@powersync/web 0.0.0-dev-20251201150812 → 0.0.0-dev-20251209082930
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/0b19af1befc07ce338dd.wasm +0 -0
- package/dist/2632c3bda9473da74fd5.wasm +0 -0
- package/dist/64f5351ba3784bfe2f3e.wasm +0 -0
- package/dist/9318ca94aac4d0fe0135.wasm +0 -0
- package/dist/index.umd.js +219 -115
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +164 -109
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +24 -12
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js +16 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js +16 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js +16 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +16 -3
- package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map +1 -1
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js +18 -11
- package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +4 -1
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +60 -29
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +11 -2
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +1 -1
- package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +2 -2
- package/lib/src/worker/sync/SharedSyncImplementation.js +80 -68
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +79 -48
- package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +11 -3
- package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +3 -3
- package/src/worker/db/WASQLiteDB.worker.ts +0 -1
- package/src/worker/sync/SharedSyncImplementation.ts +89 -74
- package/dist/1807036ae51c10ee4d23.wasm +0 -0
- package/dist/307d8ce2280e3bae09d5.wasm +0 -0
- package/dist/cd8b9e8f4c87bf81c169.wasm +0 -0
- package/dist/e797080f5ed0b5324166.wasm +0 -0
- package/lib/src/worker/sync/MockSyncService.d.ts +0 -2
- package/lib/src/worker/sync/MockSyncService.js +0 -3
- package/lib/src/worker/sync/MockSyncServiceTypes.d.ts +0 -101
- package/lib/src/worker/sync/MockSyncServiceTypes.js +0 -1
- package/lib/src/worker/sync/MockSyncServiceWorker.d.ts +0 -56
- package/lib/src/worker/sync/MockSyncServiceWorker.js +0 -369
- package/src/worker/sync/MockSyncService.ts +0 -3
- package/src/worker/sync/MockSyncServiceTypes.ts +0 -71
- package/src/worker/sync/MockSyncServiceWorker.ts +0 -406
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
import type { MockSyncServiceMessage, MockSyncServiceResponse } from './MockSyncServiceTypes';
|
|
2
|
-
import {
|
|
3
|
-
ActiveResponse,
|
|
4
|
-
AutomaticResponseConfig,
|
|
5
|
-
PendingRequest,
|
|
6
|
-
PendingRequestInternal
|
|
7
|
-
} from './MockSyncServiceTypes';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Mock sync service implementation for shared worker environments.
|
|
11
|
-
* This allows tests to mock sync responses when using enableMultipleTabs: true.
|
|
12
|
-
* Requests are kept pending until a client explicitly creates a response.
|
|
13
|
-
*/
|
|
14
|
-
export class MockSyncService {
|
|
15
|
-
private pendingRequests: Map<string, PendingRequestInternal> = new Map();
|
|
16
|
-
private activeResponses: Map<string, ActiveResponse> = new Map();
|
|
17
|
-
private nextId = 0;
|
|
18
|
-
private automaticResponse: AutomaticResponseConfig | null = null;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A Static instance of the mock sync service.
|
|
22
|
-
* This can be used directly for non-worker environments.
|
|
23
|
-
* A proxy is required for worker environments.
|
|
24
|
-
*/
|
|
25
|
-
static readonly GLOBAL_INSTANCE = new MockSyncService();
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Register a new pending request (called by WebRemote when a sync stream is requested).
|
|
29
|
-
* Returns a promise that resolves when a client creates a response for this request.
|
|
30
|
-
*/
|
|
31
|
-
registerPendingRequest(
|
|
32
|
-
url: string,
|
|
33
|
-
method: string,
|
|
34
|
-
headers: Record<string, string>,
|
|
35
|
-
body: any,
|
|
36
|
-
signal?: AbortSignal
|
|
37
|
-
): Promise<Response> {
|
|
38
|
-
const id = `pending-${++this.nextId}`;
|
|
39
|
-
|
|
40
|
-
let resolveResponse: (response: Response) => void;
|
|
41
|
-
let rejectResponse: (error: Error) => void;
|
|
42
|
-
|
|
43
|
-
const responsePromise = new Promise<Response>((resolve, reject) => {
|
|
44
|
-
resolveResponse = resolve;
|
|
45
|
-
rejectResponse = reject;
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const pendingRequest: PendingRequestInternal = {
|
|
49
|
-
id,
|
|
50
|
-
url,
|
|
51
|
-
method,
|
|
52
|
-
headers,
|
|
53
|
-
body,
|
|
54
|
-
responsePromise: {
|
|
55
|
-
resolve: resolveResponse!,
|
|
56
|
-
reject: rejectResponse!
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
this.pendingRequests.set(id, pendingRequest);
|
|
61
|
-
|
|
62
|
-
signal?.addEventListener('abort', () => {
|
|
63
|
-
this.pendingRequests.delete(id);
|
|
64
|
-
rejectResponse(new Error('Request aborted'));
|
|
65
|
-
|
|
66
|
-
// if already in active responses, remove it
|
|
67
|
-
if (this.activeResponses.has(id)) {
|
|
68
|
-
const response = this.activeResponses.get(id);
|
|
69
|
-
if (response) {
|
|
70
|
-
response.stream.close();
|
|
71
|
-
}
|
|
72
|
-
this.activeResponses.delete(id);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// If automatic response is configured, apply it immediately
|
|
77
|
-
if (this.automaticResponse) {
|
|
78
|
-
// Use setTimeout to ensure the response is created asynchronously
|
|
79
|
-
// This prevents issues if the response creation happens synchronously
|
|
80
|
-
setTimeout(() => {
|
|
81
|
-
try {
|
|
82
|
-
// Create response with automatic config
|
|
83
|
-
this.createResponse(id, this.automaticResponse!.status, this.automaticResponse!.headers);
|
|
84
|
-
|
|
85
|
-
// Push body lines if provided
|
|
86
|
-
if (this.automaticResponse!.bodyLines) {
|
|
87
|
-
for (const line of this.automaticResponse!.bodyLines) {
|
|
88
|
-
const lineStr = `${JSON.stringify(line)}\n`;
|
|
89
|
-
const encoder = new TextEncoder();
|
|
90
|
-
this.pushBodyData(id, encoder.encode(lineStr));
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Complete the response
|
|
95
|
-
this.completeResponse(id);
|
|
96
|
-
} catch (e) {
|
|
97
|
-
// If automatic response fails, reject the promise
|
|
98
|
-
rejectResponse!(e instanceof Error ? e : new Error(String(e)));
|
|
99
|
-
}
|
|
100
|
-
}, 0);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Return the promise - it will resolve when createResponse is called (or immediately if auto-response is set)
|
|
104
|
-
return responsePromise;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Get all pending requests
|
|
109
|
-
*/
|
|
110
|
-
getPendingRequestsSync(): PendingRequest[] {
|
|
111
|
-
return Array.from(this.pendingRequests.values()).map((pr) => ({
|
|
112
|
-
id: pr.id,
|
|
113
|
-
url: pr.url,
|
|
114
|
-
method: pr.method,
|
|
115
|
-
headers: pr.headers,
|
|
116
|
-
body: pr.body
|
|
117
|
-
}));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Create a response for a pending request.
|
|
122
|
-
* This resolves the response promise and allows pushing body lines.
|
|
123
|
-
*/
|
|
124
|
-
createResponse(pendingRequestId: string, status: number, headers: Record<string, string>): void {
|
|
125
|
-
const pendingRequest = this.pendingRequests.get(pendingRequestId);
|
|
126
|
-
if (!pendingRequest) {
|
|
127
|
-
throw new Error(`Pending request ${pendingRequestId} not found`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Create a readable stream that the mock service can control
|
|
131
|
-
// Response.body is always ReadableStream<Uint8Array>, so we use Uint8Array
|
|
132
|
-
const stream = new ReadableStream<Uint8Array>({
|
|
133
|
-
start: (controller) => {
|
|
134
|
-
// Store the active response once the controller is available
|
|
135
|
-
// The start callback is called synchronously, so this is safe
|
|
136
|
-
const activeResponse: ActiveResponse = {
|
|
137
|
-
id: pendingRequestId,
|
|
138
|
-
status,
|
|
139
|
-
headers,
|
|
140
|
-
stream: controller
|
|
141
|
-
};
|
|
142
|
-
this.activeResponses.set(pendingRequestId, activeResponse);
|
|
143
|
-
},
|
|
144
|
-
cancel: () => {
|
|
145
|
-
// Remove response when stream is cancelled
|
|
146
|
-
this.activeResponses.delete(pendingRequestId);
|
|
147
|
-
this.pendingRequests.delete(pendingRequestId);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Create the Response object
|
|
152
|
-
const response = new Response(stream, {
|
|
153
|
-
status,
|
|
154
|
-
headers
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// Resolve the pending request's promise
|
|
158
|
-
pendingRequest.responsePromise.resolve(response);
|
|
159
|
-
|
|
160
|
-
// Remove from pending (it's now active)
|
|
161
|
-
this.pendingRequests.delete(pendingRequestId);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Push body data to an active response.
|
|
166
|
-
* Accepts either text (string) or binary data (ArrayBuffer or Uint8Array).
|
|
167
|
-
* All data is encoded to Uint8Array before enqueueing (required by ReadableStream<Uint8Array>).
|
|
168
|
-
*/
|
|
169
|
-
pushBodyData(pendingRequestId: string, data: string | ArrayBuffer | Uint8Array): void {
|
|
170
|
-
const activeResponse = this.activeResponses.get(pendingRequestId);
|
|
171
|
-
if (!activeResponse) {
|
|
172
|
-
throw new Error(`Active response ${pendingRequestId} not found`);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
let encoded: Uint8Array;
|
|
177
|
-
|
|
178
|
-
if (typeof data === 'string') {
|
|
179
|
-
// Encode string to Uint8Array (required by ReadableStream<Uint8Array>)
|
|
180
|
-
const encoder = new TextEncoder();
|
|
181
|
-
encoded = encoder.encode(data);
|
|
182
|
-
} else if (data instanceof ArrayBuffer) {
|
|
183
|
-
// Convert ArrayBuffer to Uint8Array
|
|
184
|
-
encoded = new Uint8Array(data);
|
|
185
|
-
} else {
|
|
186
|
-
// Already Uint8Array, use directly
|
|
187
|
-
encoded = data;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
activeResponse.stream.enqueue(encoded);
|
|
191
|
-
} catch (e) {
|
|
192
|
-
// Stream might be closed, remove it
|
|
193
|
-
this.activeResponses.delete(pendingRequestId);
|
|
194
|
-
throw new Error(`Failed to push data to response ${pendingRequestId}: ${e}`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Complete an active response (close the stream)
|
|
200
|
-
*/
|
|
201
|
-
completeResponse(pendingRequestId: string): void {
|
|
202
|
-
const activeResponse = this.activeResponses.get(pendingRequestId);
|
|
203
|
-
if (!activeResponse) {
|
|
204
|
-
throw new Error(`Active response ${pendingRequestId} not found`);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
activeResponse.stream.close();
|
|
209
|
-
} catch (e) {
|
|
210
|
-
// Stream might already be closed
|
|
211
|
-
} finally {
|
|
212
|
-
this.activeResponses.delete(pendingRequestId);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Set the automatic response configuration.
|
|
218
|
-
* When set, this will be used to automatically reply to all pending requests.
|
|
219
|
-
*/
|
|
220
|
-
setAutomaticResponse(config: AutomaticResponseConfig | null): void {
|
|
221
|
-
this.automaticResponse = config;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Automatically reply to all pending requests using the automatic response configuration.
|
|
226
|
-
* Returns the number of requests that were replied to.
|
|
227
|
-
*/
|
|
228
|
-
replyToAllPendingRequests(): number {
|
|
229
|
-
if (!this.automaticResponse) {
|
|
230
|
-
throw new Error('Automatic response not set. Call setAutomaticResponse first.');
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const pendingRequestIds = Array.from(this.pendingRequests.keys());
|
|
234
|
-
let count = 0;
|
|
235
|
-
|
|
236
|
-
for (const requestId of pendingRequestIds) {
|
|
237
|
-
try {
|
|
238
|
-
// Create response with automatic config
|
|
239
|
-
this.createResponse(requestId, this.automaticResponse.status, this.automaticResponse.headers);
|
|
240
|
-
|
|
241
|
-
// Push body lines if provided
|
|
242
|
-
if (this.automaticResponse.bodyLines) {
|
|
243
|
-
for (const line of this.automaticResponse.bodyLines) {
|
|
244
|
-
const lineStr = `${JSON.stringify(line)}\n`;
|
|
245
|
-
const encoder = new TextEncoder();
|
|
246
|
-
this.pushBodyData(requestId, encoder.encode(lineStr));
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Complete the response
|
|
251
|
-
this.completeResponse(requestId);
|
|
252
|
-
count++;
|
|
253
|
-
} catch (e) {
|
|
254
|
-
// Skip requests that fail (might already be handled)
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return count;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Set up message handler for the mock service on a MessagePort
|
|
265
|
-
*/
|
|
266
|
-
export function setupMockServiceMessageHandler(port: MessagePort) {
|
|
267
|
-
port.addEventListener('message', (event: MessageEvent<MockSyncServiceMessage>) => {
|
|
268
|
-
const message = event.data;
|
|
269
|
-
|
|
270
|
-
if (!message || typeof message !== 'object' || !('type' in message)) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const service = MockSyncService.GLOBAL_INSTANCE;
|
|
275
|
-
|
|
276
|
-
try {
|
|
277
|
-
switch (message.type) {
|
|
278
|
-
case 'getPendingRequests': {
|
|
279
|
-
try {
|
|
280
|
-
const requests = service.getPendingRequestsSync();
|
|
281
|
-
port.postMessage({
|
|
282
|
-
type: 'getPendingRequests',
|
|
283
|
-
requestId: message.requestId,
|
|
284
|
-
requests
|
|
285
|
-
} satisfies MockSyncServiceResponse);
|
|
286
|
-
} catch (error) {
|
|
287
|
-
port.postMessage({
|
|
288
|
-
type: 'error',
|
|
289
|
-
requestId: message.requestId,
|
|
290
|
-
error: error instanceof Error ? error.message : String(error)
|
|
291
|
-
} satisfies MockSyncServiceResponse);
|
|
292
|
-
}
|
|
293
|
-
break;
|
|
294
|
-
}
|
|
295
|
-
case 'createResponse': {
|
|
296
|
-
try {
|
|
297
|
-
service.createResponse(message.pendingRequestId, message.status, message.headers);
|
|
298
|
-
port.postMessage({
|
|
299
|
-
type: 'createResponse',
|
|
300
|
-
requestId: message.requestId,
|
|
301
|
-
success: true
|
|
302
|
-
} satisfies MockSyncServiceResponse);
|
|
303
|
-
} catch (error) {
|
|
304
|
-
port.postMessage({
|
|
305
|
-
type: 'error',
|
|
306
|
-
requestId: message.requestId,
|
|
307
|
-
error: error instanceof Error ? error.message : String(error)
|
|
308
|
-
} satisfies MockSyncServiceResponse);
|
|
309
|
-
}
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
case 'pushBodyData': {
|
|
313
|
-
try {
|
|
314
|
-
service.pushBodyData(message.pendingRequestId, message.data);
|
|
315
|
-
port.postMessage({
|
|
316
|
-
type: 'pushBodyData',
|
|
317
|
-
requestId: message.requestId,
|
|
318
|
-
success: true
|
|
319
|
-
} satisfies MockSyncServiceResponse);
|
|
320
|
-
} catch (error) {
|
|
321
|
-
port.postMessage({
|
|
322
|
-
type: 'error',
|
|
323
|
-
requestId: message.requestId,
|
|
324
|
-
error: error instanceof Error ? error.message : String(error)
|
|
325
|
-
} satisfies MockSyncServiceResponse);
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
case 'completeResponse': {
|
|
330
|
-
try {
|
|
331
|
-
service.completeResponse(message.pendingRequestId);
|
|
332
|
-
port.postMessage({
|
|
333
|
-
type: 'completeResponse',
|
|
334
|
-
requestId: message.requestId,
|
|
335
|
-
success: true
|
|
336
|
-
} satisfies MockSyncServiceResponse);
|
|
337
|
-
} catch (error) {
|
|
338
|
-
port.postMessage({
|
|
339
|
-
type: 'error',
|
|
340
|
-
requestId: message.requestId,
|
|
341
|
-
error: error instanceof Error ? error.message : String(error)
|
|
342
|
-
} satisfies MockSyncServiceResponse);
|
|
343
|
-
}
|
|
344
|
-
break;
|
|
345
|
-
}
|
|
346
|
-
case 'setAutomaticResponse': {
|
|
347
|
-
try {
|
|
348
|
-
service.setAutomaticResponse(message.config);
|
|
349
|
-
port.postMessage({
|
|
350
|
-
type: 'setAutomaticResponse',
|
|
351
|
-
requestId: message.requestId,
|
|
352
|
-
success: true
|
|
353
|
-
} satisfies MockSyncServiceResponse);
|
|
354
|
-
} catch (error) {
|
|
355
|
-
port.postMessage({
|
|
356
|
-
type: 'error',
|
|
357
|
-
requestId: message.requestId,
|
|
358
|
-
error: error instanceof Error ? error.message : String(error)
|
|
359
|
-
} satisfies MockSyncServiceResponse);
|
|
360
|
-
}
|
|
361
|
-
break;
|
|
362
|
-
}
|
|
363
|
-
case 'replyToAllPendingRequests': {
|
|
364
|
-
try {
|
|
365
|
-
const count = service.replyToAllPendingRequests();
|
|
366
|
-
port.postMessage({
|
|
367
|
-
type: 'replyToAllPendingRequests',
|
|
368
|
-
requestId: message.requestId,
|
|
369
|
-
success: true,
|
|
370
|
-
count
|
|
371
|
-
} satisfies MockSyncServiceResponse);
|
|
372
|
-
} catch (error) {
|
|
373
|
-
port.postMessage({
|
|
374
|
-
type: 'error',
|
|
375
|
-
requestId: message.requestId,
|
|
376
|
-
error: error instanceof Error ? error.message : String(error)
|
|
377
|
-
} satisfies MockSyncServiceResponse);
|
|
378
|
-
}
|
|
379
|
-
break;
|
|
380
|
-
}
|
|
381
|
-
default: {
|
|
382
|
-
const requestId =
|
|
383
|
-
'requestId' in message && typeof message === 'object' && message !== null
|
|
384
|
-
? (message as { requestId?: string }).requestId
|
|
385
|
-
: undefined;
|
|
386
|
-
port.postMessage({
|
|
387
|
-
type: 'error',
|
|
388
|
-
requestId,
|
|
389
|
-
error: `Unknown message type: ${(message as any).type}`
|
|
390
|
-
} satisfies MockSyncServiceResponse);
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
} catch (error) {
|
|
395
|
-
// Fallback for any unexpected errors
|
|
396
|
-
const requestId = 'requestId' in message ? message.requestId : undefined;
|
|
397
|
-
port.postMessage({
|
|
398
|
-
type: 'error',
|
|
399
|
-
requestId,
|
|
400
|
-
error: error instanceof Error ? error.message : String(error)
|
|
401
|
-
} satisfies MockSyncServiceResponse);
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
port.start();
|
|
406
|
-
}
|