Skip to content

Commit 2fbb953

Browse files
lohanidamodarclaude
andcommitted
fix: use Date header from health/version instead of health.getTime()
health.getTime() requires health.read scope which regular console users don't have. Instead, parse the Date header from the existing health/version fetch that already happens on console load. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e8938c3 commit 2fbb953

4 files changed

Lines changed: 17 additions & 26 deletions

File tree

src/lib/helpers/fingerprint.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,15 @@ const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
77
let serverTimeCache: { serverSecs: number; fetchedAtMs: number } | null = null;
88

99
/**
10-
* Fetch and cache the server's clock so fingerprint timestamps always align
11-
* with the backend's clock, regardless of local clock drift.
10+
* Cache the server's clock so fingerprint timestamps always align with the
11+
* backend's clock, regardless of local clock drift.
1212
*
13-
* @param getServerTime - callback that returns the server's unix timestamp in seconds
14-
* (e.g. `health.getTime()` → `response.localTime`)
13+
* @param serverTimeSecs - the server's unix timestamp in seconds
14+
* (e.g. parsed from a response Date header)
1515
*/
16-
export async function syncServerTime(
17-
getServerTime: () => Promise<number>
18-
): Promise<void> {
16+
export function syncServerTime(serverTimeSecs: number): void {
1917
if (serverTimeCache) return;
20-
try {
21-
const fetchedAtMs = Date.now();
22-
const serverSecs = await getServerTime();
23-
serverTimeCache = { serverSecs, fetchedAtMs };
24-
} catch {
25-
console.warn('Failed to sync server time for fingerprint');
26-
}
18+
serverTimeCache = { serverSecs: serverTimeSecs, fetchedAtMs: Date.now() };
2719
}
2820

2921
function getServerTimestamp(): number {

src/routes/(console)/+layout.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Platform, Query } from '@appwrite.io/console';
66
import { makePlansMap } from '$lib/helpers/billing';
77
import { plansInfo as plansInfoStore } from '$lib/stores/billing';
88
import { normalizeConsoleVariables } from '$lib/helpers/domains';
9+
import { syncServerTime } from '$lib/helpers/fingerprint';
910

1011
export const load: LayoutLoad = async ({ depends, parent }) => {
1112
const { organizations, plansInfo } = await parent();
@@ -28,7 +29,13 @@ export const load: LayoutLoad = async ({ depends, parent }) => {
2829
plansArrayPromise,
2930
fetch(`${endpoint}/health/version`, {
3031
headers: { 'X-Appwrite-Project': project as string }
31-
}).then((response) => response.json() as { version?: string }),
32+
}).then((response) => {
33+
const dateHeader = response.headers.get('Date');
34+
if (dateHeader) {
35+
syncServerTime(Math.floor(new Date(dateHeader).getTime() / 1000));
36+
}
37+
return response.json() as { version?: string };
38+
}),
3239
sdk.forConsole.console.variables()
3340
]);
3441

src/routes/(console)/project-[region]-[project]/+layout.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { loadAvailableRegions } from '$routes/(console)/regions';
1111
import { type Models, Platform } from '@appwrite.io/console';
1212
import { redirect } from '@sveltejs/kit';
1313
import { resolve } from '$app/paths';
14-
import { generateFingerprintToken, syncServerTime } from '$lib/helpers/fingerprint';
14+
import { generateFingerprintToken } from '$lib/helpers/fingerprint';
1515
import { normalizeConsoleVariables } from '$lib/helpers/domains';
1616
import { browser } from '$app/environment';
1717

@@ -107,11 +107,7 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => {
107107
// Track console access for cloud projects (fire-and-forget, backend has 6-day cooldown).
108108
// Skip if paused — user must explicitly resume via the paused project modal.
109109
if (isCloud && browser && project.status !== 'paused') {
110-
syncServerTime(async () => {
111-
const { localTime } = await sdk.forConsole.health.getTime();
112-
return localTime;
113-
})
114-
.then(() => generateFingerprintToken())
110+
generateFingerprintToken()
115111
.then((fingerprint) => {
116112
sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint;
117113
return sdk.forConsole.projects.updateConsoleAccess({

src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { Dependencies } from '$lib/constants';
77
import { addNotification } from '$lib/stores/notifications';
88
import { Submit, trackError } from '$lib/actions/analytics';
9-
import { generateFingerprintToken, syncServerTime } from '$lib/helpers/fingerprint';
9+
import { generateFingerprintToken } from '$lib/helpers/fingerprint';
1010
import { Alert, Layout, Modal, Typography } from '@appwrite.io/pink-svelte';
1111
import { Status } from '@appwrite.io/console';
1212
@@ -28,10 +28,6 @@
2828
error = null;
2929
3030
try {
31-
await syncServerTime(async () => {
32-
const { localTime } = await sdk.forConsole.health.getTime();
33-
return localTime;
34-
});
3531
const fingerprint = await generateFingerprintToken();
3632
sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint;
3733

0 commit comments

Comments
 (0)