Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
470b047
feat: add Premium Geo DB addon to project settings
lohanidamodar Apr 18, 2026
5954b75
feat(settings): show price in premium geo DB enable dialog
lohanidamodar Apr 19, 2026
7e73d36
update sdk
lohanidamodar Apr 19, 2026
0e53210
feat(billing): render project addons in breakdown + use server addon …
lohanidamodar Apr 19, 2026
66e615e
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar Apr 20, 2026
afb13fc
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar Apr 21, 2026
13b0478
chore: bump @appwrite.io/console SDK to 95547fc
lohanidamodar Apr 23, 2026
0cba797
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar Apr 23, 2026
6fc000f
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar Apr 26, 2026
304142c
chore: keep @appwrite.io/console@95547fc for premium geo DB SDK methods
lohanidamodar Apr 26, 2026
67566db
Revert "chore: keep @appwrite.io/console@95547fc for premium geo DB S…
lohanidamodar Apr 26, 2026
e5a62c5
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar Apr 30, 2026
a54c530
chore: update console SDK to 352239b
lohanidamodar Apr 30, 2026
4376702
merge main
lohanidamodar May 4, 2026
da68f75
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar May 4, 2026
0889ace
feat(settings): rewrite Premium Geo DB card description to focus on d…
lohanidamodar May 6, 2026
6fbdd43
feat(settings): tighten Premium Geo DB card copy to outcome-focused v…
lohanidamodar May 7, 2026
1ba8ebd
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar May 11, 2026
f8d2816
chore: update console SDK to 634f110
lohanidamodar May 11, 2026
afecbd2
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar May 12, 2026
60838e0
fix(settings): handle 3DS redirect + replace cancel/retry with refres…
lohanidamodar May 12, 2026
279737d
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar May 13, 2026
51ad756
fix: rename Models.Locale to Models.CloudLocale after SDK bump
lohanidamodar May 17, 2026
bd9d958
Merge main into feat/project-premium-geo-db-addon
lohanidamodar May 19, 2026
5b1b4fd
Bump console SDK to @2642dc5 (current cloud HEAD)
lohanidamodar May 19, 2026
0983d4c
Bump console SDK to @dd8e255
lohanidamodar Jun 25, 2026
bdf38af
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"dependencies": {
"@ai-sdk/svelte": "^1.1.24",
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@f063676",
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@febca4d",
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3",
"@appwrite.io/pink-legacy": "^1.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import UpdateVariables from '../updateVariables.svelte';
import { page } from '$app/state';
import UpdateLabels from './updateLabels.svelte';
import PremiumGeoDB from './premiumGeoDB.svelte';
import { isCloud } from '$lib/system';
import { ID } from '@appwrite.io/console';

export let data;
Expand Down Expand Up @@ -93,6 +95,9 @@
<UpdateProtocols />
<UpdateServices />
<UpdateInstallations {...data.installations} limit={data.limit} offset={data.offset} />
{#if isCloud}
<PremiumGeoDB addons={data.addons} />
{/if}
<UpdateVariables
{sdkCreateVariable}
{sdkUpdateVariable}
Expand Down
15 changes: 12 additions & 3 deletions src/routes/(console)/project-[region]-[project]/settings/+page.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { isCloud } from '$lib/system';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@appwrite.io/console';
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ depends, url, params }) => {
depends(Dependencies.PROJECT_VARIABLES);
depends(Dependencies.PROJECT_INSTALLATIONS);
depends(Dependencies.ADDONS);
const limit = PAGE_LIMIT;
const offset = Number(url.searchParams.get('offset') ?? 0);
const variablesOffset = Number(url.searchParams.get('variablesOffset') ?? 0);
const projectSdk = sdk.forProject(params.region, params.project);
const [variables, installations] = await Promise.all([
const [variables, installations, addons] = await Promise.all([
projectSdk.projectApi.listVariables({
queries: [Query.limit(limit), Query.offset(variablesOffset)]
}),
projectSdk.vcs.listInstallations({
queries: [Query.limit(limit), Query.offset(offset)]
})
}),
isCloud
? sdk
.forConsoleIn(params.region)
.projects.listAddons({ projectId: params.project })
.catch(() => null)
: Promise.resolve(null)
]);

return {
limit,
offset,
variablesOffset,
variables,
installations
installations,
addons
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
<script lang="ts">
import { Box, CardGrid } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { getChangePlanUrl, plansInfo } from '$lib/stores/billing';
import { currentPlan, organization } from '$lib/stores/organization';
import { page } from '$app/state';
import { get } from 'svelte/store';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { Badge } from '@appwrite.io/pink-svelte';
import type { Models } from '@appwrite.io/console';
import PremiumGeoDBEnableModal from './premiumGeoDBEnableModal.svelte';
import PremiumGeoDBDisableModal from './premiumGeoDBDisableModal.svelte';

export let addons: Models.AddonList | null = null;

let showEnable = false;
let showDisable = false;
let reEnabling = false;
let cancelling = false;

$: planSupportsPremiumGeoDB = $currentPlan?.supportedAddons?.premiumGeoDB === true;
$: canUpgradeToPremiumGeoDB =
!planSupportsPremiumGeoDB && hasUpgradeablePlanWithPremiumGeoDB($currentPlan);
$: premiumGeoDBAddon = addons?.addons?.find(
(a) => a.key === 'premiumGeoDB' && (a.status === 'active' || a.status === 'pending')
);
$: isPending = premiumGeoDBAddon?.status === 'pending';
$: isActive = premiumGeoDBAddon?.status === 'active';
Comment on lines +33 to +35

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Addon key casing inconsistency with BAA pattern

The BAA.svelte filter uses the all-lowercase string 'baa', consistent with Appwrite's API key convention. Here 'premiumGeoDB' (camelCase) is used. If the API returns the addon with a lowercase key (following the same pattern as BAA), this find will never match — premiumGeoDBAddon would always be undefined and the component would always render the Enable CTA even when the addon is already active or pending. The same camelCase string is also used in the onMount fallback lookup at line 65, so both detection paths would silently fail. Please confirm the exact key string the API returns for this addon. What string does the API's listAddons response return for the key field of the Premium Geo DB addon — 'premiumGeoDB', 'premiumgeodb', or something else? BAA uses 'baa' (all lowercase), so camelCase here looks inconsistent with that established pattern.

$: isScheduledForRemoval = isActive && premiumGeoDBAddon?.nextValue === 0;
Comment thread
greptile-apps[bot] marked this conversation as resolved.

function hasUpgradeablePlanWithPremiumGeoDB(plan: Models.BillingPlan): boolean {
if (!plan) return false;
const plans = get(plansInfo);
for (const [, p] of plans) {
if (p.order > plan.order && p.supportedAddons?.premiumGeoDB) {
return true;
}
}
return false;
}

async function handleCancelAndRetry() {
cancelling = true;
try {
await sdk.forConsoleIn(page.params.region).projects.deleteAddon({
projectId: page.params.project,
addonId: premiumGeoDBAddon.$id
});
await invalidate(Dependencies.ADDONS);
showEnable = true;
} catch (e) {
addNotification({
message: e.message,
type: 'error'
});
} finally {
cancelling = false;
}
}

async function handleReEnable() {
reEnabling = true;
try {
await sdk.forConsoleIn(page.params.region).projects.createPremiumGeoDBAddon({
projectId: page.params.project
});
await Promise.all([invalidate(Dependencies.ADDONS), invalidate(Dependencies.PROJECT)]);
addNotification({
message: 'Premium Geo DB addon has been re-enabled',
type: 'success'
});
} catch (e) {
addNotification({
message: e.message,
type: 'error'
});
} finally {
reEnabling = false;
}
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
</script>
Comment thread
greptile-apps[bot] marked this conversation as resolved.

<CardGrid>
<svelte:fragment slot="title">Premium Geo DB</svelte:fragment>
Enrich session and request data with premium geolocation details such as timezone, postal code, ISP,
connection type, and organization. Useful for fine-grained analytics, fraud detection, and personalized
user experiences.
<svelte:fragment slot="aside">
<Box>
<h6>
<b>Premium Geo DB</b>
</h6>
{#if !planSupportsPremiumGeoDB && canUpgradeToPremiumGeoDB}
<p class="text u-margin-block-start-8">
Premium Geo DB is not available on your current plan. Upgrade your plan to
enable it.
</p>
<Button
secondary
class="u-margin-block-start-16"
href={getChangePlanUrl($organization?.$id)}>
<span class="text">Upgrade plan</span>
</Button>
{:else if !planSupportsPremiumGeoDB}
<p class="text u-margin-block-start-8">
Premium Geo DB is not available on your current plan.
</p>
{:else if isPending}
<div class="u-flex u-cross-center u-gap-8 u-margin-block-start-8">
<Badge variant="secondary" type="warning" content="Payment pending" />
</div>
<p class="text u-margin-block-start-8">
A payment is awaiting confirmation. If the payment was interrupted, you can
cancel and retry.
</p>
<Button
secondary
class="u-margin-block-start-16"
disabled={cancelling}
on:click={handleCancelAndRetry}>
<span class="text">Cancel & retry</span>
</Button>
Comment thread
greptile-apps[bot] marked this conversation as resolved.
{:else if isActive}
<div class="u-flex u-cross-center u-gap-8 u-margin-block-start-8">
{#if isScheduledForRemoval}
<Badge variant="secondary" type="warning" content="Scheduled for removal" />
{:else}
<Badge variant="secondary" type="success" content="Active" />
{/if}
</div>
<p class="text u-margin-block-start-8">
Premium Geo DB is enabled for this project.
</p>
{#if isScheduledForRemoval}
<p class="text u-margin-block-start-8">
Premium Geo DB will be removed at the end of your current billing cycle.
</p>
<Button
secondary
class="u-margin-block-start-16"
disabled={reEnabling}
on:click={handleReEnable}>
<span class="text">Keep Premium Geo DB</span>
</Button>
{:else}
<Button
secondary
class="u-margin-block-start-16"
on:click={() => (showDisable = true)}>
<span class="text">Disable Premium Geo DB</span>
</Button>
{/if}
{:else}
<p class="text u-margin-block-start-8">
Enable Premium Geo DB for this project to collect detailed geolocation data on
every request. Billed prorated for your current cycle.
</p>
<Button
secondary
class="u-margin-block-start-16"
on:click={() => (showEnable = true)}>
<span class="text">Enable Premium Geo DB</span>
</Button>
{/if}
</Box>
</svelte:fragment>
</CardGrid>

<PremiumGeoDBEnableModal bind:show={showEnable} />

{#if premiumGeoDBAddon}
<PremiumGeoDBDisableModal bind:show={showDisable} addonId={premiumGeoDBAddon.$id} />
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script lang="ts">
import { page } from '$app/state';
import { invalidate } from '$app/navigation';
import { Modal } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';

let {
show = $bindable(false),
addonId
}: {
show: boolean;
addonId: string;
} = $props();

let error = $state<string | null>(null);
let submitting = $state(false);

async function handleSubmit() {
submitting = true;
error = null;
try {
await sdk.forConsoleIn(page.params.region).projects.deleteAddon({
projectId: page.params.project,
addonId
});
await Promise.all([invalidate(Dependencies.ADDONS), invalidate(Dependencies.PROJECT)]);
addNotification({
message:
'Premium Geo DB addon will be removed at the end of your current billing cycle',
type: 'success'
});
show = false;
} catch (e) {
error = e.message;
} finally {
submitting = false;
}
}
</script>

<Modal bind:error bind:show onSubmit={handleSubmit} title="Disable Premium Geo DB">
<p class="text">
Are you sure you want to disable the Premium Geo DB addon? The addon will remain active
until the end of your current billing cycle and will not be renewed.
</p>

<svelte:fragment slot="footer">
<Button text on:click={() => (show = false)}>Cancel</Button>
<Button secondary submit disabled={submitting}>Disable Premium Geo DB</Button>
</svelte:fragment>
</Modal>
Loading
Loading