From ee7cf29f44fdd338d95f073b1e1fa88fb87dbf56 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Thu, 10 Sep 2026 11:28:00 -0600 Subject: [PATCH] Fix browser Crypto invocation when opening saved Builder projects --- src/utils/builder-project-sync.client.ts | 4 +-- tests/builder-project-sync-client.test.ts | 43 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/utils/builder-project-sync.client.ts b/src/utils/builder-project-sync.client.ts index f1b4a5878..3bd6ba517 100644 --- a/src/utils/builder-project-sync.client.ts +++ b/src/utils/builder-project-sync.client.ts @@ -495,7 +495,7 @@ export type BuilderProjectSyncCollection = ReturnType< export function getBuilderProjectBrowserSessionId({ storage = getSessionStorage(), - createId = crypto.randomUUID, + createId = () => crypto.randomUUID(), }: { storage?: Pick createId?: () => string @@ -512,7 +512,7 @@ export function getBuilderProjectBrowserSessionId({ async function claimBuilderProjectBrowserSession({ storage = getSessionStorage(), lockManager = getBrowserSessionLockManager(), - createId = crypto.randomUUID, + createId = () => crypto.randomUUID(), }: { storage?: Pick lockManager?: BuilderProjectBrowserSessionLockManager diff --git a/tests/builder-project-sync-client.test.ts b/tests/builder-project-sync-client.test.ts index 0d8403f58..ef3109ce4 100644 --- a/tests/builder-project-sync-client.test.ts +++ b/tests/builder-project-sync-client.test.ts @@ -131,6 +131,49 @@ test('Builder project browser sessions remain stable in session storage', () => ) }) +test('the default browser session generator preserves the Crypto receiver', (context) => { + const original = crypto.randomUUID + context.mock.method(crypto, 'randomUUID', function (this: Crypto) { + if (this !== crypto) throw new TypeError('Illegal invocation') + return original.call(this) + }) + const storage = memoryStorage() + const id = getBuilderProjectBrowserSessionId({ storage }) + assert.match(id, /^[a-f0-9-]{36}$/) + assert.equal(getBuilderProjectBrowserSessionId({ storage }), id) +}) + +test('saved project sync starts with the browser-native session generator', async (context) => { + const original = crypto.randomUUID + context.mock.method(crypto, 'randomUUID', function (this: Crypto) { + if (this !== crypto) throw new TypeError('Illegal invocation') + return original.call(this) + }) + await withFakeIndexedDb(async () => { + const storage = memoryStorage() + const client = await createBuilderProjectSyncClient({ + projectId, + sessionStorage: storage, + browserSessionLockManager: memoryLockManager(), + fetch: async () => jsonSnapshotPage(snapshot), + createEventSource: () => ({ + readyState: 1, + addEventListener: () => undefined, + removeEventListener: () => undefined, + close: () => undefined, + }), + }) + try { + assert.equal( + client.browserSessionId, + getBuilderProjectBrowserSessionId({ storage }), + ) + } finally { + await client.cleanup() + } + }) +}) + test('durable project revisions enter the outbox before upload', async () => { await withFakeIndexedDb(async (indexedDb) => { const nextRevisionId = uuid(50)