@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.
Files changed (47) hide show
  1. package/dist/0b19af1befc07ce338dd.wasm +0 -0
  2. package/dist/2632c3bda9473da74fd5.wasm +0 -0
  3. package/dist/64f5351ba3784bfe2f3e.wasm +0 -0
  4. package/dist/9318ca94aac4d0fe0135.wasm +0 -0
  5. package/dist/index.umd.js +219 -115
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/worker/SharedSyncImplementation.umd.js +164 -109
  8. package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
  9. package/dist/worker/WASQLiteDB.umd.js +24 -12
  10. package/dist/worker/WASQLiteDB.umd.js.map +1 -1
  11. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js +16 -3
  12. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite-async_mjs.umd.js.map +1 -1
  13. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js +16 -3
  14. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_mc-wa-sqlite_mjs.umd.js.map +1 -1
  15. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js +16 -3
  16. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite-async_mjs.umd.js.map +1 -1
  17. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js +16 -3
  18. package/dist/worker/node_modules_journeyapps_wa-sqlite_dist_wa-sqlite_mjs.umd.js.map +1 -1
  19. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js +18 -11
  20. package/dist/worker/node_modules_journeyapps_wa-sqlite_src_examples_OPFSCoopSyncVFS_js.umd.js.map +1 -1
  21. package/lib/package.json +2 -2
  22. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +4 -1
  23. package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +60 -29
  24. package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +11 -2
  25. package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.d.ts +1 -1
  26. package/lib/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.js +2 -2
  27. package/lib/src/worker/sync/SharedSyncImplementation.js +80 -68
  28. package/lib/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +5 -5
  30. package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +79 -48
  31. package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +11 -3
  32. package/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts +3 -3
  33. package/src/worker/db/WASQLiteDB.worker.ts +0 -1
  34. package/src/worker/sync/SharedSyncImplementation.ts +89 -74
  35. package/dist/1807036ae51c10ee4d23.wasm +0 -0
  36. package/dist/307d8ce2280e3bae09d5.wasm +0 -0
  37. package/dist/cd8b9e8f4c87bf81c169.wasm +0 -0
  38. package/dist/e797080f5ed0b5324166.wasm +0 -0
  39. package/lib/src/worker/sync/MockSyncService.d.ts +0 -2
  40. package/lib/src/worker/sync/MockSyncService.js +0 -3
  41. package/lib/src/worker/sync/MockSyncServiceTypes.d.ts +0 -101
  42. package/lib/src/worker/sync/MockSyncServiceTypes.js +0 -1
  43. package/lib/src/worker/sync/MockSyncServiceWorker.d.ts +0 -56
  44. package/lib/src/worker/sync/MockSyncServiceWorker.js +0 -369
  45. package/src/worker/sync/MockSyncService.ts +0 -3
  46. package/src/worker/sync/MockSyncServiceTypes.ts +0 -71
  47. 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
- }