Skip to content

Commit 86bd1b9

Browse files
author
DominicGBauer
committed
chore: revert to error
1 parent d0bfbbf commit 86bd1b9

File tree

7 files changed

+19
-122
lines changed

7 files changed

+19
-122
lines changed

packages/web/src/db/PowerSyncDatabase.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
WebStreamingSyncImplementation,
2929
WebStreamingSyncImplementationOptions
3030
} from './sync/WebStreamingSyncImplementation';
31-
import { getNavigationLocks } from '../shared/navigator';
31+
import { getNavigatorLocks } from '../shared/navigator';
3232

3333
export interface WebPowerSyncFlags extends WebSQLFlags {
3434
/**
@@ -161,7 +161,7 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
161161
if (this.resolvedFlags.ssrMode) {
162162
return PowerSyncDatabase.SHARED_MUTEX.runExclusive(cb);
163163
}
164-
return getNavigationLocks().request(`lock-${this.database.name}`, cb);
164+
return getNavigatorLocks().request(`lock-${this.database.name}`, cb);
165165
}
166166

167167
protected generateSyncStreamImplementation(connector: PowerSyncBackendConnector): StreamingSyncImplementation {

packages/web/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type { DBFunctionsInterface, OpenDB } from '../../../shared/types';
1515
import { _openDB } from '../../../shared/open-db';
1616
import { getWorkerDatabaseOpener, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database';
1717
import { ResolvedWebSQLOpenOptions, resolveWebSQLFlags, WebSQLFlags } from '../web-sql-flags';
18-
import { getNavigationLocks } from '../../../shared/navigator';
18+
import { getNavigatorLocks } from '../../../shared/navigator';
1919

2020
/**
2121
* These flags are the same as {@link WebSQLFlags}.
@@ -187,7 +187,7 @@ export class WASQLiteDBAdapter extends BaseObserver<DBAdapterListener> implement
187187
}
188188

189189
protected acquireLock(callback: () => Promise<any>): Promise<any> {
190-
return getNavigationLocks().request(`db-lock-${this.options.dbFilename}`, callback);
190+
return getNavigatorLocks().request(`db-lock-${this.options.dbFilename}`, callback);
191191
}
192192

193193
async readTransaction<T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions | undefined): Promise<T> {

packages/web/src/db/sync/WebStreamingSyncImplementation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
LockType
66
} from '@powersync/common';
77
import { ResolvedWebSQLOpenOptions, WebSQLFlags } from '../adapters/web-sql-flags';
8-
import { getNavigationLocks } from '../../shared/navigator';
8+
import { getNavigatorLocks } from '../../shared/navigator';
99

1010
export interface WebStreamingSyncImplementationOptions extends AbstractStreamingSyncImplementationOptions {
1111
flags?: WebSQLFlags;
@@ -33,6 +33,6 @@ export class WebStreamingSyncImplementation extends AbstractStreamingSyncImpleme
3333
obtainLock<T>(lockOptions: LockOptions<T>): Promise<T> {
3434
const identifier = `streaming-sync-${lockOptions.type}-${this.webOptions.identifier}`;
3535
lockOptions.type == LockType.SYNC && console.debug('requesting lock for ', identifier);
36-
return getNavigationLocks().request(identifier, { signal: lockOptions.signal }, lockOptions.callback);
36+
return getNavigatorLocks().request(identifier, { signal: lockOptions.signal }, lockOptions.callback);
3737
}
3838
}
Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,7 @@
1-
import { Mutex } from 'async-mutex';
2-
3-
export const getNavigationLocks = (): LockManager => {
1+
export const getNavigatorLocks = (): LockManager => {
42
if ('locks' in navigator && navigator.locks) {
53
return navigator.locks;
64
}
7-
console.warn('Navigator locks are not available in this context.' +
8-
'This may be due to running in an unsecure context. ' +
9-
'Consider using HTTPS or a secure context for full functionality.' +
10-
'Using fallback implementation.');
11-
12-
const mutexes = new Map<string, Mutex>();
13-
14-
const getMutex = (name: string): Mutex => {
15-
if (!mutexes.has(name)) {
16-
mutexes.set(name, new Mutex());
17-
}
18-
return mutexes.get(name)!;
19-
};
20-
21-
const fallbackLockManager: LockManager = {
22-
request: async (
23-
name: string,
24-
optionsOrCallback: LockOptions | LockGrantedCallback,
25-
maybeCallback?: LockGrantedCallback
26-
): Promise<LockManagerSnapshot> => {
27-
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback!;
28-
const options: LockOptions = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
29-
30-
const mutex = getMutex(name);
31-
const release = await mutex.acquire();
32-
try {
33-
const lock: Lock = { name, mode: options.mode || 'exclusive' };
34-
return await callback(lock);
35-
} finally {
36-
release();
37-
mutexes.delete(name);
38-
}
39-
},
40-
41-
query: async (): Promise<LockManagerSnapshot> => {
42-
return {
43-
held: Array.from(mutexes.keys()).map(name => ({ name, mode: 'exclusive' as const })),
44-
pending: [] // We can't accurately track pending locks in this implementation as this requires a queue
45-
};
46-
}
47-
};
485

49-
return fallbackLockManager;
6+
throw new Error('Navigator locks are not available in an insecure context. Use a secure context such as HTTPS or http://localhost.');
507
}

packages/web/src/worker/db/WASQLiteDB.worker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import '@journeyapps/wa-sqlite';
66
import * as Comlink from 'comlink';
77
import { _openDB } from '../../shared/open-db';
88
import type { DBFunctionsInterface } from '../../shared/types';
9-
import { getNavigationLocks } from '../../shared/navigator';
9+
import { getNavigatorLocks } from '../../shared/navigator';
1010

1111
/**
1212
* Keeps track of open DB connections and the clients which
@@ -24,7 +24,7 @@ let nextClientId = 1;
2424

2525
const openDBShared = async (dbFileName: string): Promise<DBFunctionsInterface> => {
2626
// Prevent multiple simultaneous opens from causing race conditions
27-
return getNavigationLocks().request(OPEN_DB_LOCK, async () => {
27+
return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
2828
const clientId = nextClientId++;
2929

3030
if (!DBMap.has(dbFileName)) {

packages/web/src/worker/sync/SharedSyncImplementation.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
import { WASQLiteDBAdapter } from '../../db/adapters/wa-sqlite/WASQLiteDBAdapter';
2424
import { AbstractSharedSyncClientProvider } from './AbstractSharedSyncClientProvider';
2525
import { BroadcastLogger } from './BroadcastLogger';
26-
import { getNavigationLocks } from '../../shared/navigator';
26+
import { getNavigatorLocks } from '../../shared/navigator';
2727

2828
/**
2929
* Manual message events for shared sync clients
@@ -166,7 +166,7 @@ export class SharedSyncImplementation
166166
async connect(options?: PowerSyncConnectionOptions) {
167167
await this.waitForReady();
168168
// This effectively queues connect and disconnect calls. Ensuring multiple tabs' requests are synchronized
169-
return getNavigationLocks().request('shared-sync-connect', async () => {
169+
return getNavigatorLocks().request('shared-sync-connect', async () => {
170170
this.syncStreamClient = this.generateStreamingImplementation();
171171

172172
this.syncStreamClient.registerListener({
@@ -182,7 +182,7 @@ export class SharedSyncImplementation
182182
async disconnect() {
183183
await this.waitForReady();
184184
// This effectively queues connect and disconnect calls. Ensuring multiple tabs' requests are synchronized
185-
return getNavigationLocks().request('shared-sync-connect', async () => {
185+
return getNavigatorLocks().request('shared-sync-connect', async () => {
186186
await this.syncStreamClient?.disconnect();
187187
await this.syncStreamClient?.dispose();
188188
this.syncStreamClient = null;
Lines changed: 6 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2-
import { getNavigationLocks } from '../../src/shared/navigator';
1+
import { describe, it, expect, vi, afterEach } from 'vitest';
2+
import { getNavigatorLocks } from '../../src/shared/navigator';
33

44
describe('getNavigationLocks', () => {
55
afterEach(() => {
@@ -14,74 +14,14 @@ describe('getNavigationLocks', () => {
1414

1515
vi.spyOn(navigator, 'locks', 'get').mockReturnValue(mockLocks);
1616

17-
const result = getNavigationLocks();
17+
const result = getNavigatorLocks();
1818
expect(result).toBe(mockLocks);
1919
});
2020

21-
it('should return fallback implementation if navigator.locks is not available', () => {
22-
// @ts-ignore
23-
vi.spyOn(navigator, 'locks', 'get').mockReturnValue(undefined);
21+
it('should throw an error if navigator.locks is unavailable', () => {
2422

25-
const result = getNavigationLocks();
26-
expect(result).toHaveProperty('request');
27-
expect(result).toHaveProperty('query');
28-
expect(result).not.toBe(navigator.locks);
29-
});
30-
31-
it('fallback request should acquire and release a lock', async () => {
32-
// @ts-ignore
33-
vi.spyOn(navigator, 'locks', 'get').mockReturnValue(undefined);
34-
const locks = getNavigationLocks();
35-
36-
const mockCallback = vi.fn().mockResolvedValue('result');
37-
const result = await locks.request('test-lock', mockCallback);
38-
39-
expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({
40-
name: 'test-lock',
41-
mode: 'exclusive'
42-
}));
43-
expect(result).toBe('result');
44-
});
45-
46-
it('fallback query should return held locks', async () => {
47-
// @ts-ignore
48-
vi.spyOn(navigator, 'locks', 'get').mockReturnValue(undefined);
49-
const locks = getNavigationLocks();
50-
51-
// Acquire a lock first
52-
await locks.request('test-lock', async () => {
53-
const queryResult = await locks.query();
54-
expect(queryResult.held).toHaveLength(1);
55-
expect(queryResult.held![0]).toEqual(expect.objectContaining({
56-
name: 'test-lock',
57-
mode: 'exclusive'
58-
}));
59-
expect(queryResult.pending).toHaveLength(0);
60-
});
61-
62-
const finalQueryResult = await locks.query();
63-
expect(finalQueryResult.held).toHaveLength(0);
64-
});
65-
66-
it('fallback implementation should handle concurrent requests', async () => {
67-
// @ts-ignore
68-
vi.spyOn(navigator, 'locks', 'get').mockReturnValue(undefined);
69-
const locks = getNavigationLocks();
70-
71-
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
72-
73-
const request1 = locks.request('test-lock', async () => {
74-
await delay(200);
75-
return 'first';
76-
});
77-
78-
const request2 = locks.request('test-lock', async () => {
79-
return 'second';
80-
});
81-
82-
const [result1, result2] = await Promise.all([request1, request2]);
23+
vi.spyOn(navigator, 'locks', 'get').mockReturnValue(undefined!);
8324

84-
expect(result1).toBe('first');
85-
expect(result2).toBe('second');
25+
expect(() => getNavigatorLocks()).toThrowError('Navigator locks are not available in an insecure context. Use a secure context such as HTTPS or http://localhost.');;
8626
});
8727
});

0 commit comments

Comments
 (0)