diff --git a/src/lib/helpers/fingerprint.ts b/src/lib/helpers/fingerprint.ts index 9ecf76ed7..7c330786b 100644 --- a/src/lib/helpers/fingerprint.ts +++ b/src/lib/helpers/fingerprint.ts @@ -4,6 +4,7 @@ const SECRET = env.PUBLIC_CONSOLE_FINGERPRINT_KEY ?? ''; const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour async function sha256(message: string): Promise { + if (!crypto?.subtle) return ''; const data = new TextEncoder().encode(message); const hash = await crypto.subtle.digest('SHA-256', data); return Array.from(new Uint8Array(hash)) @@ -12,6 +13,7 @@ async function sha256(message: string): Promise { } async function hmacSha256(message: string, secret: string): Promise { + if (!crypto?.subtle) return ''; const key = await crypto.subtle.importKey( 'raw', new TextEncoder().encode(secret), @@ -204,7 +206,7 @@ export async function generateFingerprintToken(): Promise { }; const payload = JSON.stringify(signals); - const encoded = btoa(payload); + const encoded = btoa(unescape(encodeURIComponent(payload))); if (!SECRET) { return encoded; diff --git a/src/routes/(console)/project-[region]-[project]/+layout.ts b/src/routes/(console)/project-[region]-[project]/+layout.ts index 858f9625a..8263d56ac 100644 --- a/src/routes/(console)/project-[region]-[project]/+layout.ts +++ b/src/routes/(console)/project-[region]-[project]/+layout.ts @@ -13,6 +13,7 @@ import { redirect } from '@sveltejs/kit'; import { resolve } from '$app/paths'; import { generateFingerprintToken } from '$lib/helpers/fingerprint'; import { normalizeConsoleVariables } from '$lib/helpers/domains'; +import { browser } from '$app/environment'; export const load: LayoutLoad = async ({ params, depends, parent }) => { const { plansInfo, organizations, preferences: prefs } = await parent(); @@ -103,35 +104,24 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => { plansInfo.set(organization.billingPlanId, organizationPlan); } - // Track console access for cloud only (fire-and-forget, backend has 6-day cooldown) - // Don't call if project is paused - user must explicitly resume via createConsoleAccess - if (isCloud) { - const projectInactivityDays = organizationPlan?.projectInactivityDays ?? 0; - const consoleAccessedAt = (project as { consoleAccessedAt?: string }).consoleAccessedAt; - - let isPaused = false; - if (projectInactivityDays > 0 && consoleAccessedAt) { - const lastAccess = new Date(consoleAccessedAt); - const now = new Date(); - const diffDays = Math.floor( - (now.getTime() - lastAccess.getTime()) / (1000 * 60 * 60 * 24) - ); - isPaused = diffDays >= projectInactivityDays; - } - - if (!isPaused) { - generateFingerprintToken() - .then((fingerprint) => { - sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint; - return sdk.forConsole.projects.updateConsoleAccess({ - projectId: params.project - }); - }) - .catch(() => {}) - .finally(() => { - delete sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint']; + // Track console access for cloud projects (fire-and-forget, backend has 6-day cooldown). + // Skip if paused — user must explicitly resume via the paused project modal. + if (isCloud && browser && project.status !== 'paused') { + generateFingerprintToken() + .then((fingerprint) => { + sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint; + return ( + sdk.forConsole.projects as unknown as { + updateConsoleAccess(params: { projectId: string }): Promise; + } + ).updateConsoleAccess({ + projectId: params.project }); - } + }) + .catch(() => {}) + .finally(() => { + delete sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint']; + }); } return { diff --git a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte index d6e88e666..143cacce8 100644 --- a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte @@ -7,7 +7,6 @@ import { Submit, trackError } from '$lib/actions/analytics'; import { generateFingerprintToken } from '$lib/helpers/fingerprint'; import { Alert, Layout, Modal, Typography } from '@appwrite.io/pink-svelte'; - import { Status } from '@appwrite.io/console'; let { show = $bindable(false), @@ -29,7 +28,14 @@ sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint; try { - await sdk.forConsole.projects.updateStatus({ projectId, status: Status.Active }); + await ( + sdk.forConsole.projects as unknown as { + updateStatus(params: { + projectId: string; + status: string; + }): Promise; + } + ).updateStatus({ projectId, status: 'active' }); } finally { delete sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint']; }