From 41aca21b710703a39b09a693fcac246149e7b894 Mon Sep 17 00:00:00 2001
From: harsh mahajan
Date: Mon, 18 May 2026 11:14:25 +0530
Subject: [PATCH] fix: add impersonation params to resource urls
---
src/lib/appwrite/impersonation.ts | 27 ++++++++++++++-
.../billing/alerts/paymentAuthRequired.svelte | 11 +++++--
src/lib/components/filePicker.svelte | 19 +++++------
.../billing/paymentHistory.svelte | 11 +++++--
.../billing/retryPaymentModal.svelte | 13 +++++---
.../invoices/[invoiceId]/download/+page.ts | 5 ++-
.../invoices/[invoiceId]/view/+page.ts | 5 ++-
.../settings/invoicesTable.svelte | 11 +++++--
.../functions/function-[function]/store.ts | 11 ++++---
.../(components)/deploymentActionMenu.svelte | 11 ++++---
.../sites/(components)/siteCard.svelte | 17 ++++++----
.../sites/grid.svelte | 17 ++++++----
.../storage/bucket-[bucket]/+page.svelte | 21 ++++++------
.../bucket-[bucket]/file-[file]/+page.svelte | 33 +++++++++++--------
14 files changed, 141 insertions(+), 71 deletions(-)
diff --git a/src/lib/appwrite/impersonation.ts b/src/lib/appwrite/impersonation.ts
index 9339a9924..9f8d6b45f 100644
--- a/src/lib/appwrite/impersonation.ts
+++ b/src/lib/appwrite/impersonation.ts
@@ -1,4 +1,4 @@
-import { writable } from 'svelte/store';
+import { derived, writable } from 'svelte/store';
import { building } from '$app/environment';
const KEY_TARGET_USER_ID = 'console.impersonation.targetUserId';
@@ -82,6 +82,31 @@ export function readImpersonationTargetUserId(): string | null {
return sessionStorage.getItem(KEY_TARGET_USER_ID);
}
+export function createImpersonatedResourceUrl(
+ url: string,
+ queryParams: Record = {}
+): string {
+ const parsedUrl = new URL(url, globalThis.location?.origin);
+ const targetUserId = readImpersonationTargetUserId();
+
+ for (const [key, value] of Object.entries(queryParams)) {
+ if (value !== undefined) {
+ parsedUrl.searchParams.set(key, value.toString());
+ }
+ }
+
+ if (!targetUserId) return parsedUrl.toString();
+
+ parsedUrl.searchParams.set('impersonateUserId', targetUserId);
+
+ return parsedUrl.toString();
+}
+
+export const impersonatedResourceUrl = derived(
+ impersonationRevision,
+ () => createImpersonatedResourceUrl
+);
+
export function readOperatorSnapshot(): OperatorSnapshot | null {
if (building) return null;
const raw = sessionStorage.getItem(KEY_OPERATOR);
diff --git a/src/lib/components/billing/alerts/paymentAuthRequired.svelte b/src/lib/components/billing/alerts/paymentAuthRequired.svelte
index a67537ab0..2d6955e19 100644
--- a/src/lib/components/billing/alerts/paymentAuthRequired.svelte
+++ b/src/lib/components/billing/alerts/paymentAuthRequired.svelte
@@ -3,10 +3,17 @@
import { page } from '$app/state';
import { Button } from '$lib/elements/forms';
import { HeaderAlert } from '$lib/layout';
+ import { impersonatedResourceUrl } from '$lib/appwrite/impersonation';
import { actionRequiredInvoices, hideBillingHeaderRoutes } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { getApiEndpoint } from '$lib/stores/sdk';
const endpoint = getApiEndpoint();
+
+ function invoiceUrl(invoiceId: string) {
+ return $impersonatedResourceUrl(
+ `${endpoint}/organizations/${$organization.$id}/invoices/${invoiceId}/view`
+ );
+ }
{#if $actionRequiredInvoices && $actionRequiredInvoices?.invoices?.length && !hideBillingHeaderRoutes.includes(page.url.pathname)}
@@ -14,9 +21,7 @@
Please authorize your upcoming payment for {$organization.name}. Your bank requires this
security measure to proceed with payment.
-
-
- View invoice
-
+ View invoice
{
return redirect(
302,
- `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/download`
+ createImpersonatedResourceUrl(
+ `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/download`
+ )
);
};
diff --git a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts
index 3a4576785..9351393ae 100644
--- a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts
+++ b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts
@@ -1,4 +1,5 @@
import { getApiEndpoint, sdk } from '$lib/stores/sdk';
+import { createImpersonatedResourceUrl } from '$lib/appwrite/impersonation';
import { redirect } from '@sveltejs/kit';
import type { PageLoad } from './$types';
@@ -13,6 +14,8 @@ export const load: PageLoad = async ({ params }) => {
return redirect(
302,
- `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/view`
+ createImpersonatedResourceUrl(
+ `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/view`
+ )
);
};
diff --git a/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte b/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte
index 514e8a575..100c23554 100644
--- a/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte
+++ b/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte
@@ -5,6 +5,7 @@
import { Button } from '$lib/elements/forms';
import { formatCurrency } from '$lib/helpers/numbers';
import { trackEvent } from '$lib/actions/analytics';
+ import { impersonatedResourceUrl } from '$lib/appwrite/impersonation';
import { ActionMenu, Badge, Icon, Link, Popover, Table } from '@appwrite.io/pink-svelte';
import {
IconDotsHorizontal,
@@ -24,6 +25,12 @@
$selectedInvoice = invoice;
$showRetryModal = true;
}
+
+ function invoiceUrl(invoiceId: string, action: 'view' | 'download') {
+ return $impersonatedResourceUrl(
+ `${endpoint}/organizations/${page.params.organization}/invoices/${invoiceId}/${action}`
+ );
+ }
+ href={invoiceUrl(invoice.$id, 'view')}>
View invoice
+ href={invoiceUrl(invoice.$id, 'download')}>
Download PDF
{#if status === 'overdue' || status === 'failed'}
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts
index 42bf293ce..3f320daf1 100644
--- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts
+++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts
@@ -3,6 +3,7 @@ import { DeploymentDownloadType, type Models } from '@appwrite.io/console';
import type { Column } from '$lib/helpers/types';
import { sdk } from '$lib/stores/sdk';
import { page } from '$app/stores';
+import { createImpersonatedResourceUrl } from '$lib/appwrite/impersonation';
export const func = derived(page, ($page) => $page.data.function as Models.Function);
export const deploymentList = derived(
@@ -150,22 +151,24 @@ export const columns = writable([
export function getOutputDownload(funcId: string, deploymentId: string) {
const p = get(page);
- return (
+ return createImpersonatedResourceUrl(
sdk.forProject(p.params.region, p.params.project).functions.getDeploymentDownload({
functionId: funcId,
deploymentId,
type: DeploymentDownloadType.Output
- }) + '&mode=admin'
+ }),
+ { mode: 'admin' }
);
}
export function getSourceDownload(funcId: string, deploymentId: string) {
const p = get(page);
- return (
+ return createImpersonatedResourceUrl(
sdk.forProject(p.params.region, p.params.project).functions.getDeploymentDownload({
functionId: funcId,
deploymentId,
type: DeploymentDownloadType.Source
- }) + '&mode=admin'
+ }),
+ { mode: 'admin' }
);
}
diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte
index c0190429d..d3b6e657f 100644
--- a/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte
+++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte
@@ -17,6 +17,7 @@
import { ActionMenu, Icon, Tooltip } from '@appwrite.io/pink-svelte';
import { getEffectiveBuildStatus } from '$lib/helpers/buildTimeout';
import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store';
+ import { impersonatedResourceUrl } from '$lib/appwrite/impersonation';
export let selectedDeployment: Models.Deployment;
export let deployment: Models.Deployment;
@@ -28,21 +29,23 @@
export let inCard = false;
function getOutputDownload(deploymentId: string) {
- return (
+ return $impersonatedResourceUrl(
sdk.forProject(page.params.region, page.params.project).sites.getDeploymentDownload({
siteId: page.params.site,
deploymentId: deploymentId,
type: DeploymentDownloadType.Output
- }) + '&mode=admin'
+ }),
+ { mode: 'admin' }
);
}
function getSourceDownload(deploymentId: string) {
- return (
+ return $impersonatedResourceUrl(
sdk.forProject(page.params.region, page.params.project).sites.getDeploymentDownload({
siteId: page.params.site,
deploymentId: deploymentId,
type: DeploymentDownloadType.Source
- }) + '&mode=admin'
+ }),
+ { mode: 'admin' }
);
}
diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte
index f85215900..294027c17 100644
--- a/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte
+++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte
@@ -27,6 +27,7 @@
import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store';
import { regionalProtocol } from '$routes/(console)/project-[region]-[project]/store';
import type { Snippet } from 'svelte';
+ import { impersonatedResourceUrl } from '$lib/appwrite/impersonation';
let {
site,
@@ -71,13 +72,15 @@
}
function getFilePreview(fileId: string) {
- return sdk.forConsoleIn(page.params.region).storage.getFilePreview({
- bucketId: 'screenshots',
- fileId,
- width: 1024,
- height: 576,
- output: ImageFormat.Avif
- });
+ return $impersonatedResourceUrl(
+ sdk.forConsoleIn(page.params.region).storage.getFilePreview({
+ bucketId: 'screenshots',
+ fileId,
+ width: 1024,
+ height: 576,
+ output: ImageFormat.Avif
+ })
+ );
}
diff --git a/src/routes/(console)/project-[region]-[project]/sites/grid.svelte b/src/routes/(console)/project-[region]-[project]/sites/grid.svelte
index 99029389e..704c20a16 100644
--- a/src/routes/(console)/project-[region]-[project]/sites/grid.svelte
+++ b/src/routes/(console)/project-[region]-[project]/sites/grid.svelte
@@ -14,6 +14,7 @@
import { IconExclamation } from '@appwrite.io/pink-icons-svelte';
import { Link } from '$lib/elements';
import { getFrameworkIcon } from '$lib/stores/sites';
+ import { impersonatedResourceUrl } from '$lib/appwrite/impersonation';
export let siteList: Models.SiteList;
@@ -33,13 +34,15 @@
}
function getFilePreview(fileId: string) {
- return sdk.forConsoleIn(page.params.region).storage.getFilePreview({
- bucketId: 'screenshots',
- fileId,
- width: 1024,
- height: 576,
- output: ImageFormat.Avif
- });
+ return $impersonatedResourceUrl(
+ sdk.forConsoleIn(page.params.region).storage.getFilePreview({
+ bucketId: 'screenshots',
+ fileId,
+ width: 1024,
+ height: 576,
+ output: ImageFormat.Avif
+ })
+ );
}
diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte
index ef5988aee..7e18d3e1f 100644
--- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte
@@ -34,6 +34,7 @@
import { isSmallViewport } from '$lib/stores/viewport';
import { ID } from '@appwrite.io/console';
import { addNotification } from '$lib/stores/notifications';
+ import { impersonatedResourceUrl } from '$lib/appwrite/impersonation';
import type { PageProps } from './$types';
const { data }: PageProps = $props();
@@ -44,17 +45,15 @@
let isDragging = $state(false);
function getPreview(fileId: string) {
- return (
- sdk
- .forProject(page.params.region, page.params.project)
- .storage.getFilePreview({
- bucketId: page.params.bucket,
- fileId,
- height: 128,
- width: 128,
- output: ImageFormat.Avif
- })
- .toString() + '&mode=admin'
+ return $impersonatedResourceUrl(
+ sdk.forProject(page.params.region, page.params.project).storage.getFilePreview({
+ bucketId: page.params.bucket,
+ fileId,
+ height: 128,
+ width: 128,
+ output: ImageFormat.Avif
+ }),
+ { mode: 'admin' }
);
}
diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte
index a940dc8f6..557bed67f 100644
--- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte
@@ -38,6 +38,7 @@
import { ImageFormat, type Models } from '@appwrite.io/console';
import { isSmallViewport } from '$lib/stores/viewport';
import { Menu } from '$lib/components/menu';
+ import { impersonatedResourceUrl } from '$lib/appwrite/impersonation';
let showFileAlert = true;
@@ -50,33 +51,39 @@
let showCopyUrlModal = false;
let selectedFileToken: Models.ResourceToken | null = null;
- const getPreview = (fileId: string) =>
- sdk
- .forProject(page.params.region, page.params.project)
- .storage.getFilePreview({
+ function getPreview(fileId: string) {
+ return $impersonatedResourceUrl(
+ sdk.forProject(page.params.region, page.params.project).storage.getFilePreview({
bucketId: $file.bucketId,
fileId,
width: 640,
height: 300,
output: ImageFormat.Avif
- })
- .toString() + '&mode=admin';
- const getView = (fileId: string) =>
- sdk
- .forProject(page.params.region, page.params.project)
- .storage.getFileView({ bucketId: $file.bucketId, fileId })
- .toString() + '&mode=admin';
+ }),
+ { mode: 'admin' }
+ );
+ }
+
+ function getView(fileId: string) {
+ return $impersonatedResourceUrl(
+ sdk
+ .forProject(page.params.region, page.params.project)
+ .storage.getFileView({ bucketId: $file.bucketId, fileId }),
+ { mode: 'admin' }
+ );
+ }
$: if (filePermissions) {
arePermsDisabled = !symmetricDifference(filePermissions, $file.$permissions).length;
}
function downloadFile() {
- return (
+ return $impersonatedResourceUrl(
sdk
.forProject(page.params.region, page.params.project)
.storage.getFileDownload({ bucketId: $file.bucketId, fileId: $file.$id })
- .toString() + '&mode=admin'
+ .toString(),
+ { mode: 'admin' }
);
}