@electric-sql/client 0.4.1 → 0.5.1
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/cjs/index.cjs +350 -223
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.browser.mjs +1 -1
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +59 -48
- package/dist/index.legacy-esm.js +348 -221
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +350 -223
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +173 -416
- package/src/constants.ts +7 -0
- package/src/error.ts +50 -0
- package/src/fetch.ts +79 -0
- package/src/helpers.ts +6 -0
- package/src/index.ts +4 -1
- package/src/queue.ts +62 -0
- package/src/shape.ts +197 -0
- package/src/types.ts +2 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
3
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
6
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
9
|
+
var __typeError = (msg) => {
|
|
10
|
+
throw TypeError(msg);
|
|
11
|
+
};
|
|
7
12
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
13
|
var __spreadValues = (a, b) => {
|
|
9
14
|
for (var prop in b || (b = {}))
|
|
@@ -16,6 +21,7 @@ var __spreadValues = (a, b) => {
|
|
|
16
21
|
}
|
|
17
22
|
return a;
|
|
18
23
|
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
19
25
|
var __objRest = (source, exclude) => {
|
|
20
26
|
var target = {};
|
|
21
27
|
for (var prop in source)
|
|
@@ -41,6 +47,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
41
47
|
return to;
|
|
42
48
|
};
|
|
43
49
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
50
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
51
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
52
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
53
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
54
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
44
55
|
var __async = (__this, __arguments, generator) => {
|
|
45
56
|
return new Promise((resolve, reject) => {
|
|
46
57
|
var fulfilled = (value) => {
|
|
@@ -193,36 +204,54 @@ function isChangeMessage(message) {
|
|
|
193
204
|
function isControlMessage(message) {
|
|
194
205
|
return !isChangeMessage(message);
|
|
195
206
|
}
|
|
207
|
+
function isUpToDateMessage(message) {
|
|
208
|
+
return isControlMessage(message) && message.headers.control === `up-to-date`;
|
|
209
|
+
}
|
|
196
210
|
|
|
197
|
-
// src/
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
211
|
+
// src/queue.ts
|
|
212
|
+
function isThenable(value) {
|
|
213
|
+
return !!value && typeof value === `object` && `then` in value && typeof value.then === `function`;
|
|
214
|
+
}
|
|
215
|
+
var _processingChain;
|
|
216
|
+
var AsyncProcessingQueue = class {
|
|
217
|
+
constructor() {
|
|
218
|
+
__privateAdd(this, _processingChain);
|
|
219
|
+
}
|
|
220
|
+
process(callback) {
|
|
221
|
+
__privateSet(this, _processingChain, isThenable(__privateGet(this, _processingChain)) ? __privateGet(this, _processingChain).then(callback) : callback());
|
|
222
|
+
return __privateGet(this, _processingChain);
|
|
223
|
+
}
|
|
224
|
+
waitForProcessing() {
|
|
225
|
+
return __async(this, null, function* () {
|
|
226
|
+
let currentChain;
|
|
227
|
+
do {
|
|
228
|
+
currentChain = __privateGet(this, _processingChain);
|
|
229
|
+
yield currentChain;
|
|
230
|
+
} while (__privateGet(this, _processingChain) !== currentChain);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
202
233
|
};
|
|
234
|
+
_processingChain = new WeakMap();
|
|
235
|
+
var _queue, _callback;
|
|
203
236
|
var MessageProcessor = class {
|
|
204
237
|
constructor(callback) {
|
|
205
|
-
this
|
|
206
|
-
this
|
|
207
|
-
this
|
|
238
|
+
__privateAdd(this, _queue, new AsyncProcessingQueue());
|
|
239
|
+
__privateAdd(this, _callback);
|
|
240
|
+
__privateSet(this, _callback, callback);
|
|
208
241
|
}
|
|
209
242
|
process(messages) {
|
|
210
|
-
this.
|
|
211
|
-
if (!this.isProcessing) {
|
|
212
|
-
this.processQueue();
|
|
213
|
-
}
|
|
243
|
+
__privateGet(this, _queue).process(() => __privateGet(this, _callback).call(this, messages));
|
|
214
244
|
}
|
|
215
|
-
|
|
245
|
+
waitForProcessing() {
|
|
216
246
|
return __async(this, null, function* () {
|
|
217
|
-
this.
|
|
218
|
-
while (this.messageQueue.length > 0) {
|
|
219
|
-
const messages = this.messageQueue.shift();
|
|
220
|
-
yield this.callback(messages);
|
|
221
|
-
}
|
|
222
|
-
this.isProcessing = false;
|
|
247
|
+
yield __privateGet(this, _queue).waitForProcessing();
|
|
223
248
|
});
|
|
224
249
|
}
|
|
225
250
|
};
|
|
251
|
+
_queue = new WeakMap();
|
|
252
|
+
_callback = new WeakMap();
|
|
253
|
+
|
|
254
|
+
// src/error.ts
|
|
226
255
|
var FetchError = class _FetchError extends Error {
|
|
227
256
|
constructor(status, text, json, headers, url, message) {
|
|
228
257
|
super(
|
|
@@ -251,316 +280,414 @@ var FetchError = class _FetchError extends Error {
|
|
|
251
280
|
});
|
|
252
281
|
}
|
|
253
282
|
};
|
|
283
|
+
var FetchBackoffAbortError = class extends Error {
|
|
284
|
+
constructor() {
|
|
285
|
+
super(`Fetch with backoff aborted`);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/fetch.ts
|
|
290
|
+
var BackoffDefaults = {
|
|
291
|
+
initialDelay: 100,
|
|
292
|
+
maxDelay: 1e4,
|
|
293
|
+
multiplier: 1.3
|
|
294
|
+
};
|
|
295
|
+
function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
|
|
296
|
+
const {
|
|
297
|
+
initialDelay,
|
|
298
|
+
maxDelay,
|
|
299
|
+
multiplier,
|
|
300
|
+
debug = false,
|
|
301
|
+
onFailedAttempt
|
|
302
|
+
} = backoffOptions;
|
|
303
|
+
return (...args) => __async(this, null, function* () {
|
|
304
|
+
var _a;
|
|
305
|
+
const url = args[0];
|
|
306
|
+
const options = args[1];
|
|
307
|
+
let delay = initialDelay;
|
|
308
|
+
let attempt = 0;
|
|
309
|
+
while (true) {
|
|
310
|
+
try {
|
|
311
|
+
const result = yield fetchClient(...args);
|
|
312
|
+
if (result.ok) return result;
|
|
313
|
+
else throw yield FetchError.fromResponse(result, url.toString());
|
|
314
|
+
} catch (e) {
|
|
315
|
+
onFailedAttempt == null ? void 0 : onFailedAttempt();
|
|
316
|
+
if ((_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.aborted) {
|
|
317
|
+
throw new FetchBackoffAbortError();
|
|
318
|
+
} else if (e instanceof FetchError && e.status >= 400 && e.status < 500) {
|
|
319
|
+
throw e;
|
|
320
|
+
} else {
|
|
321
|
+
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
322
|
+
delay = Math.min(delay * multiplier, maxDelay);
|
|
323
|
+
if (debug) {
|
|
324
|
+
attempt++;
|
|
325
|
+
console.log(`Retry attempt #${attempt} after ${delay}ms`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/constants.ts
|
|
334
|
+
var SHAPE_ID_HEADER = `x-electric-shape-id`;
|
|
335
|
+
var CHUNK_LAST_OFFSET_HEADER = `x-electric-chunk-last-offset`;
|
|
336
|
+
var SHAPE_SCHEMA_HEADER = `x-electric-schema`;
|
|
337
|
+
var SHAPE_ID_QUERY_PARAM = `shape_id`;
|
|
338
|
+
var OFFSET_QUERY_PARAM = `offset`;
|
|
339
|
+
var WHERE_QUERY_PARAM = `where`;
|
|
340
|
+
var LIVE_QUERY_PARAM = `live`;
|
|
341
|
+
|
|
342
|
+
// src/client.ts
|
|
343
|
+
var _fetchClient, _messageParser, _subscribers, _upToDateSubscribers, _lastOffset, _lastSyncedAt, _isUpToDate, _connected, _shapeId, _schema, _ShapeStream_instances, publish_fn, sendErrorToSubscribers_fn, notifyUpToDateSubscribers_fn, sendErrorToUpToDateSubscribers_fn, reset_fn;
|
|
254
344
|
var ShapeStream = class {
|
|
255
345
|
constructor(options) {
|
|
256
|
-
this
|
|
257
|
-
this
|
|
346
|
+
__privateAdd(this, _ShapeStream_instances);
|
|
347
|
+
__privateAdd(this, _fetchClient);
|
|
348
|
+
__privateAdd(this, _messageParser);
|
|
349
|
+
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
350
|
+
__privateAdd(this, _upToDateSubscribers, /* @__PURE__ */ new Map());
|
|
351
|
+
__privateAdd(this, _lastOffset);
|
|
352
|
+
__privateAdd(this, _lastSyncedAt);
|
|
258
353
|
// unix time
|
|
259
|
-
this
|
|
260
|
-
this
|
|
354
|
+
__privateAdd(this, _isUpToDate, false);
|
|
355
|
+
__privateAdd(this, _connected, false);
|
|
356
|
+
__privateAdd(this, _shapeId);
|
|
357
|
+
__privateAdd(this, _schema);
|
|
261
358
|
var _a, _b, _c;
|
|
262
|
-
|
|
359
|
+
validateOptions(options);
|
|
263
360
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
264
|
-
this
|
|
265
|
-
this
|
|
266
|
-
this
|
|
267
|
-
this
|
|
268
|
-
|
|
361
|
+
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
362
|
+
__privateSet(this, _shapeId, this.options.shapeId);
|
|
363
|
+
__privateSet(this, _messageParser, new MessageParser(options.parser));
|
|
364
|
+
__privateSet(this, _fetchClient, createFetchWithBackoff(
|
|
365
|
+
(_b = options.fetchClient) != null ? _b : (...args) => fetch(...args),
|
|
366
|
+
__spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
|
|
367
|
+
onFailedAttempt: () => {
|
|
368
|
+
var _a2, _b2;
|
|
369
|
+
__privateSet(this, _connected, false);
|
|
370
|
+
(_b2 = (_a2 = options.backoffOptions) == null ? void 0 : _a2.onFailedAttempt) == null ? void 0 : _b2.call(_a2);
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
));
|
|
269
374
|
this.start();
|
|
270
375
|
}
|
|
376
|
+
get shapeId() {
|
|
377
|
+
return __privateGet(this, _shapeId);
|
|
378
|
+
}
|
|
379
|
+
get isUpToDate() {
|
|
380
|
+
return __privateGet(this, _isUpToDate);
|
|
381
|
+
}
|
|
271
382
|
start() {
|
|
272
383
|
return __async(this, null, function* () {
|
|
273
384
|
var _a;
|
|
274
|
-
this
|
|
385
|
+
__privateSet(this, _isUpToDate, false);
|
|
275
386
|
const { url, where, signal } = this.options;
|
|
276
387
|
try {
|
|
277
|
-
while (!(signal == null ? void 0 : signal.aborted) && !this
|
|
388
|
+
while (!(signal == null ? void 0 : signal.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
|
|
278
389
|
const fetchUrl = new URL(url);
|
|
279
|
-
if (where) fetchUrl.searchParams.set(
|
|
280
|
-
fetchUrl.searchParams.set(
|
|
281
|
-
if (this
|
|
282
|
-
fetchUrl.searchParams.set(
|
|
390
|
+
if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
|
|
391
|
+
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
392
|
+
if (__privateGet(this, _isUpToDate)) {
|
|
393
|
+
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
283
394
|
}
|
|
284
|
-
if (this
|
|
285
|
-
fetchUrl.searchParams.set(
|
|
395
|
+
if (__privateGet(this, _shapeId)) {
|
|
396
|
+
fetchUrl.searchParams.set(SHAPE_ID_QUERY_PARAM, __privateGet(this, _shapeId));
|
|
286
397
|
}
|
|
287
398
|
let response;
|
|
288
399
|
try {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
else break;
|
|
400
|
+
response = yield __privateGet(this, _fetchClient).call(this, fetchUrl.toString(), { signal });
|
|
401
|
+
__privateSet(this, _connected, true);
|
|
292
402
|
} catch (e) {
|
|
403
|
+
if (e instanceof FetchBackoffAbortError) break;
|
|
293
404
|
if (!(e instanceof FetchError)) throw e;
|
|
294
405
|
if (e.status == 400) {
|
|
295
|
-
this.
|
|
296
|
-
this.
|
|
406
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this);
|
|
407
|
+
__privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
297
408
|
continue;
|
|
298
409
|
} else if (e.status == 409) {
|
|
299
|
-
const newShapeId = e.headers[
|
|
300
|
-
this.
|
|
301
|
-
this.
|
|
410
|
+
const newShapeId = e.headers[SHAPE_ID_HEADER];
|
|
411
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeId);
|
|
412
|
+
__privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
302
413
|
continue;
|
|
303
414
|
} else if (e.status >= 400 && e.status < 500) {
|
|
304
|
-
this.
|
|
305
|
-
this.
|
|
415
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToUpToDateSubscribers_fn).call(this, e);
|
|
416
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
306
417
|
throw e;
|
|
307
418
|
}
|
|
308
419
|
}
|
|
309
420
|
const { headers, status } = response;
|
|
310
|
-
const shapeId = headers.get(
|
|
421
|
+
const shapeId = headers.get(SHAPE_ID_HEADER);
|
|
311
422
|
if (shapeId) {
|
|
312
|
-
this
|
|
423
|
+
__privateSet(this, _shapeId, shapeId);
|
|
313
424
|
}
|
|
314
|
-
const lastOffset = headers.get(
|
|
425
|
+
const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
|
|
315
426
|
if (lastOffset) {
|
|
316
|
-
this
|
|
427
|
+
__privateSet(this, _lastOffset, lastOffset);
|
|
317
428
|
}
|
|
318
429
|
const getSchema = () => {
|
|
319
|
-
const schemaHeader = headers.get(
|
|
430
|
+
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
320
431
|
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
321
432
|
};
|
|
322
|
-
this
|
|
433
|
+
__privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
|
|
323
434
|
const messages = status === 204 ? `[]` : yield response.text();
|
|
324
435
|
if (status === 204) {
|
|
325
|
-
this
|
|
436
|
+
__privateSet(this, _lastSyncedAt, Date.now());
|
|
326
437
|
}
|
|
327
|
-
const batch = this.
|
|
438
|
+
const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
|
|
328
439
|
if (batch.length > 0) {
|
|
329
440
|
const lastMessage = batch[batch.length - 1];
|
|
330
|
-
if (
|
|
331
|
-
this
|
|
332
|
-
if (!this
|
|
333
|
-
this
|
|
334
|
-
this.
|
|
441
|
+
if (isUpToDateMessage(lastMessage)) {
|
|
442
|
+
__privateSet(this, _lastSyncedAt, Date.now());
|
|
443
|
+
if (!__privateGet(this, _isUpToDate)) {
|
|
444
|
+
__privateSet(this, _isUpToDate, true);
|
|
445
|
+
__privateMethod(this, _ShapeStream_instances, notifyUpToDateSubscribers_fn).call(this);
|
|
335
446
|
}
|
|
336
447
|
}
|
|
337
|
-
this.
|
|
448
|
+
__privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
|
|
338
449
|
}
|
|
339
450
|
}
|
|
340
451
|
} finally {
|
|
341
|
-
this
|
|
452
|
+
__privateSet(this, _connected, false);
|
|
342
453
|
}
|
|
343
454
|
});
|
|
344
455
|
}
|
|
345
456
|
subscribe(callback, onError) {
|
|
346
457
|
const subscriptionId = Math.random();
|
|
347
458
|
const subscriber = new MessageProcessor(callback);
|
|
348
|
-
this.
|
|
459
|
+
__privateGet(this, _subscribers).set(subscriptionId, [subscriber, onError]);
|
|
349
460
|
return () => {
|
|
350
|
-
this.
|
|
461
|
+
__privateGet(this, _subscribers).delete(subscriptionId);
|
|
351
462
|
};
|
|
352
463
|
}
|
|
353
464
|
unsubscribeAll() {
|
|
354
|
-
this.
|
|
355
|
-
}
|
|
356
|
-
publish(messages) {
|
|
357
|
-
this.subscribers.forEach(([subscriber, _]) => {
|
|
358
|
-
subscriber.process(messages);
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
sendErrorToSubscribers(error) {
|
|
362
|
-
this.subscribers.forEach(([_, errorFn]) => {
|
|
363
|
-
errorFn == null ? void 0 : errorFn(error);
|
|
364
|
-
});
|
|
465
|
+
__privateGet(this, _subscribers).clear();
|
|
365
466
|
}
|
|
366
467
|
subscribeOnceToUpToDate(callback, error) {
|
|
367
468
|
const subscriptionId = Math.random();
|
|
368
|
-
this.
|
|
469
|
+
__privateGet(this, _upToDateSubscribers).set(subscriptionId, [callback, error]);
|
|
369
470
|
return () => {
|
|
370
|
-
this.
|
|
471
|
+
__privateGet(this, _upToDateSubscribers).delete(subscriptionId);
|
|
371
472
|
};
|
|
372
473
|
}
|
|
373
474
|
unsubscribeAllUpToDateSubscribers() {
|
|
374
|
-
this.
|
|
475
|
+
__privateGet(this, _upToDateSubscribers).clear();
|
|
476
|
+
}
|
|
477
|
+
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
478
|
+
lastSyncedAt() {
|
|
479
|
+
return __privateGet(this, _lastSyncedAt);
|
|
375
480
|
}
|
|
376
481
|
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
|
|
377
482
|
lastSynced() {
|
|
378
|
-
if (this
|
|
379
|
-
return Date.now() - this
|
|
483
|
+
if (__privateGet(this, _lastSyncedAt) === void 0) return Infinity;
|
|
484
|
+
return Date.now() - __privateGet(this, _lastSyncedAt);
|
|
380
485
|
}
|
|
486
|
+
/** Indicates if we are connected to the Electric sync service. */
|
|
381
487
|
isConnected() {
|
|
382
|
-
return this
|
|
488
|
+
return __privateGet(this, _connected);
|
|
383
489
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
});
|
|
490
|
+
/** True during initial fetch. False afterwise. */
|
|
491
|
+
isLoading() {
|
|
492
|
+
return !this.isUpToDate;
|
|
388
493
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
494
|
+
};
|
|
495
|
+
_fetchClient = new WeakMap();
|
|
496
|
+
_messageParser = new WeakMap();
|
|
497
|
+
_subscribers = new WeakMap();
|
|
498
|
+
_upToDateSubscribers = new WeakMap();
|
|
499
|
+
_lastOffset = new WeakMap();
|
|
500
|
+
_lastSyncedAt = new WeakMap();
|
|
501
|
+
_isUpToDate = new WeakMap();
|
|
502
|
+
_connected = new WeakMap();
|
|
503
|
+
_shapeId = new WeakMap();
|
|
504
|
+
_schema = new WeakMap();
|
|
505
|
+
_ShapeStream_instances = new WeakSet();
|
|
506
|
+
publish_fn = function(messages) {
|
|
507
|
+
__privateGet(this, _subscribers).forEach(([subscriber, _]) => {
|
|
508
|
+
subscriber.process(messages);
|
|
509
|
+
});
|
|
510
|
+
};
|
|
511
|
+
sendErrorToSubscribers_fn = function(error) {
|
|
512
|
+
__privateGet(this, _subscribers).forEach(([_, errorFn]) => {
|
|
513
|
+
errorFn == null ? void 0 : errorFn(error);
|
|
514
|
+
});
|
|
515
|
+
};
|
|
516
|
+
notifyUpToDateSubscribers_fn = function() {
|
|
517
|
+
__privateGet(this, _upToDateSubscribers).forEach(([callback]) => {
|
|
518
|
+
callback();
|
|
519
|
+
});
|
|
520
|
+
};
|
|
521
|
+
sendErrorToUpToDateSubscribers_fn = function(error) {
|
|
522
|
+
__privateGet(this, _upToDateSubscribers).forEach(
|
|
523
|
+
([_, errorCallback]) => errorCallback(error)
|
|
524
|
+
);
|
|
525
|
+
};
|
|
526
|
+
/**
|
|
527
|
+
* Resets the state of the stream, optionally with a provided
|
|
528
|
+
* shape ID
|
|
529
|
+
*/
|
|
530
|
+
reset_fn = function(shapeId) {
|
|
531
|
+
__privateSet(this, _lastOffset, `-1`);
|
|
532
|
+
__privateSet(this, _shapeId, shapeId);
|
|
533
|
+
__privateSet(this, _isUpToDate, false);
|
|
534
|
+
__privateSet(this, _connected, false);
|
|
535
|
+
__privateSet(this, _schema, void 0);
|
|
536
|
+
};
|
|
537
|
+
function validateOptions(options) {
|
|
538
|
+
if (!options.url) {
|
|
539
|
+
throw new Error(`Invalid shape option. It must provide the url`);
|
|
393
540
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
reset(shapeId) {
|
|
399
|
-
this.lastOffset = `-1`;
|
|
400
|
-
this.shapeId = shapeId;
|
|
401
|
-
this.isUpToDate = false;
|
|
402
|
-
this.connected = false;
|
|
403
|
-
this.schema = void 0;
|
|
404
|
-
}
|
|
405
|
-
validateOptions(options) {
|
|
406
|
-
if (!options.url) {
|
|
407
|
-
throw new Error(`Invalid shape option. It must provide the url`);
|
|
408
|
-
}
|
|
409
|
-
if (options.signal && !(options.signal instanceof AbortSignal)) {
|
|
410
|
-
throw new Error(
|
|
411
|
-
`Invalid signal option. It must be an instance of AbortSignal.`
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeId) {
|
|
415
|
-
throw new Error(
|
|
416
|
-
`shapeId is required if this isn't an initial fetch (i.e. offset > -1)`
|
|
417
|
-
);
|
|
418
|
-
}
|
|
541
|
+
if (options.signal && !(options.signal instanceof AbortSignal)) {
|
|
542
|
+
throw new Error(
|
|
543
|
+
`Invalid signal option. It must be an instance of AbortSignal.`
|
|
544
|
+
);
|
|
419
545
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
let delay = initialDelay;
|
|
425
|
-
let attempt = 0;
|
|
426
|
-
while (true) {
|
|
427
|
-
try {
|
|
428
|
-
const result = yield this.fetchClient(url.toString(), { signal });
|
|
429
|
-
if (result.ok) {
|
|
430
|
-
if (this.options.subscribe) {
|
|
431
|
-
this.connected = true;
|
|
432
|
-
}
|
|
433
|
-
return result;
|
|
434
|
-
} else throw yield FetchError.fromResponse(result, url.toString());
|
|
435
|
-
} catch (e) {
|
|
436
|
-
this.connected = false;
|
|
437
|
-
if (signal == null ? void 0 : signal.aborted) {
|
|
438
|
-
return void 0;
|
|
439
|
-
} else if (e instanceof FetchError && e.status >= 400 && e.status < 500) {
|
|
440
|
-
throw e;
|
|
441
|
-
} else {
|
|
442
|
-
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
443
|
-
delay = Math.min(delay * multiplier, maxDelay);
|
|
444
|
-
attempt++;
|
|
445
|
-
console.log(`Retry attempt #${attempt} after ${delay}ms`);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
});
|
|
546
|
+
if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeId) {
|
|
547
|
+
throw new Error(
|
|
548
|
+
`shapeId is required if this isn't an initial fetch (i.e. offset > -1)`
|
|
549
|
+
);
|
|
450
550
|
}
|
|
451
|
-
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// src/shape.ts
|
|
555
|
+
var _stream, _data, _subscribers2, _hasNotifiedSubscribersUpToDate, _error, _Shape_instances, process_fn, handleError_fn, notify_fn;
|
|
452
556
|
var Shape = class {
|
|
453
557
|
constructor(stream) {
|
|
454
|
-
this
|
|
455
|
-
this
|
|
456
|
-
this
|
|
457
|
-
this
|
|
458
|
-
this
|
|
459
|
-
|
|
460
|
-
|
|
558
|
+
__privateAdd(this, _Shape_instances);
|
|
559
|
+
__privateAdd(this, _stream);
|
|
560
|
+
__privateAdd(this, _data, /* @__PURE__ */ new Map());
|
|
561
|
+
__privateAdd(this, _subscribers2, /* @__PURE__ */ new Map());
|
|
562
|
+
__privateAdd(this, _hasNotifiedSubscribersUpToDate, false);
|
|
563
|
+
__privateAdd(this, _error, false);
|
|
564
|
+
__privateSet(this, _stream, stream);
|
|
565
|
+
__privateGet(this, _stream).subscribe(
|
|
566
|
+
__privateMethod(this, _Shape_instances, process_fn).bind(this),
|
|
567
|
+
__privateMethod(this, _Shape_instances, handleError_fn).bind(this)
|
|
568
|
+
);
|
|
569
|
+
const unsubscribe = __privateGet(this, _stream).subscribeOnceToUpToDate(
|
|
461
570
|
() => {
|
|
462
571
|
unsubscribe();
|
|
463
572
|
},
|
|
464
573
|
(e) => {
|
|
465
|
-
this.
|
|
574
|
+
__privateMethod(this, _Shape_instances, handleError_fn).call(this, e);
|
|
466
575
|
throw e;
|
|
467
576
|
}
|
|
468
577
|
);
|
|
469
578
|
}
|
|
470
|
-
|
|
471
|
-
return this.
|
|
472
|
-
}
|
|
473
|
-
isConnected() {
|
|
474
|
-
return this.stream.isConnected();
|
|
579
|
+
get isUpToDate() {
|
|
580
|
+
return __privateGet(this, _stream).isUpToDate;
|
|
475
581
|
}
|
|
476
582
|
get value() {
|
|
477
|
-
return new Promise((resolve) => {
|
|
478
|
-
if (this.
|
|
583
|
+
return new Promise((resolve, reject) => {
|
|
584
|
+
if (__privateGet(this, _stream).isUpToDate) {
|
|
479
585
|
resolve(this.valueSync);
|
|
480
586
|
} else {
|
|
481
|
-
const unsubscribe = this.
|
|
482
|
-
()
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
(e) => {
|
|
487
|
-
throw e;
|
|
488
|
-
}
|
|
489
|
-
);
|
|
587
|
+
const unsubscribe = this.subscribe((shapeData) => {
|
|
588
|
+
unsubscribe();
|
|
589
|
+
if (__privateGet(this, _error)) reject(__privateGet(this, _error));
|
|
590
|
+
resolve(shapeData);
|
|
591
|
+
});
|
|
490
592
|
}
|
|
491
593
|
});
|
|
492
594
|
}
|
|
493
595
|
get valueSync() {
|
|
494
|
-
return this
|
|
596
|
+
return __privateGet(this, _data);
|
|
597
|
+
}
|
|
598
|
+
get error() {
|
|
599
|
+
return __privateGet(this, _error);
|
|
600
|
+
}
|
|
601
|
+
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
602
|
+
lastSyncedAt() {
|
|
603
|
+
return __privateGet(this, _stream).lastSyncedAt();
|
|
604
|
+
}
|
|
605
|
+
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
|
|
606
|
+
lastSynced() {
|
|
607
|
+
return __privateGet(this, _stream).lastSynced();
|
|
608
|
+
}
|
|
609
|
+
/** True during initial fetch. False afterwise. */
|
|
610
|
+
isLoading() {
|
|
611
|
+
return __privateGet(this, _stream).isLoading();
|
|
612
|
+
}
|
|
613
|
+
/** Indicates if we are connected to the Electric sync service. */
|
|
614
|
+
isConnected() {
|
|
615
|
+
return __privateGet(this, _stream).isConnected();
|
|
495
616
|
}
|
|
496
617
|
subscribe(callback) {
|
|
497
618
|
const subscriptionId = Math.random();
|
|
498
|
-
this.
|
|
619
|
+
__privateGet(this, _subscribers2).set(subscriptionId, callback);
|
|
499
620
|
return () => {
|
|
500
|
-
this.
|
|
621
|
+
__privateGet(this, _subscribers2).delete(subscriptionId);
|
|
501
622
|
};
|
|
502
623
|
}
|
|
503
624
|
unsubscribeAll() {
|
|
504
|
-
this.
|
|
625
|
+
__privateGet(this, _subscribers2).clear();
|
|
505
626
|
}
|
|
506
627
|
get numSubscribers() {
|
|
507
|
-
return this.
|
|
628
|
+
return __privateGet(this, _subscribers2).size;
|
|
508
629
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
newlyUpToDate = true;
|
|
536
|
-
}
|
|
537
|
-
break;
|
|
538
|
-
case `must-refetch`:
|
|
539
|
-
this.data.clear();
|
|
540
|
-
this.error = false;
|
|
541
|
-
isUpToDate = false;
|
|
542
|
-
newlyUpToDate = false;
|
|
543
|
-
break;
|
|
544
|
-
}
|
|
630
|
+
};
|
|
631
|
+
_stream = new WeakMap();
|
|
632
|
+
_data = new WeakMap();
|
|
633
|
+
_subscribers2 = new WeakMap();
|
|
634
|
+
_hasNotifiedSubscribersUpToDate = new WeakMap();
|
|
635
|
+
_error = new WeakMap();
|
|
636
|
+
_Shape_instances = new WeakSet();
|
|
637
|
+
process_fn = function(messages) {
|
|
638
|
+
let dataMayHaveChanged = false;
|
|
639
|
+
let isUpToDate = false;
|
|
640
|
+
let newlyUpToDate = false;
|
|
641
|
+
messages.forEach((message) => {
|
|
642
|
+
if (isChangeMessage(message)) {
|
|
643
|
+
dataMayHaveChanged = [`insert`, `update`, `delete`].includes(
|
|
644
|
+
message.headers.operation
|
|
645
|
+
);
|
|
646
|
+
switch (message.headers.operation) {
|
|
647
|
+
case `insert`:
|
|
648
|
+
__privateGet(this, _data).set(message.key, message.value);
|
|
649
|
+
break;
|
|
650
|
+
case `update`:
|
|
651
|
+
__privateGet(this, _data).set(message.key, __spreadValues(__spreadValues({}, __privateGet(this, _data).get(message.key)), message.value));
|
|
652
|
+
break;
|
|
653
|
+
case `delete`:
|
|
654
|
+
__privateGet(this, _data).delete(message.key);
|
|
655
|
+
break;
|
|
545
656
|
}
|
|
546
|
-
});
|
|
547
|
-
if (newlyUpToDate || isUpToDate && dataMayHaveChanged) {
|
|
548
|
-
this.hasNotifiedSubscribersUpToDate = true;
|
|
549
|
-
this.notify();
|
|
550
657
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
658
|
+
if (isControlMessage(message)) {
|
|
659
|
+
switch (message.headers.control) {
|
|
660
|
+
case `up-to-date`:
|
|
661
|
+
isUpToDate = true;
|
|
662
|
+
if (!__privateGet(this, _hasNotifiedSubscribersUpToDate)) {
|
|
663
|
+
newlyUpToDate = true;
|
|
664
|
+
}
|
|
665
|
+
break;
|
|
666
|
+
case `must-refetch`:
|
|
667
|
+
__privateGet(this, _data).clear();
|
|
668
|
+
__privateSet(this, _error, false);
|
|
669
|
+
isUpToDate = false;
|
|
670
|
+
newlyUpToDate = false;
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
556
673
|
}
|
|
674
|
+
});
|
|
675
|
+
if (newlyUpToDate || isUpToDate && dataMayHaveChanged) {
|
|
676
|
+
__privateSet(this, _hasNotifiedSubscribersUpToDate, true);
|
|
677
|
+
__privateMethod(this, _Shape_instances, notify_fn).call(this);
|
|
557
678
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
679
|
+
};
|
|
680
|
+
handleError_fn = function(e) {
|
|
681
|
+
if (e instanceof FetchError) {
|
|
682
|
+
__privateSet(this, _error, e);
|
|
683
|
+
__privateMethod(this, _Shape_instances, notify_fn).call(this);
|
|
562
684
|
}
|
|
563
685
|
};
|
|
686
|
+
notify_fn = function() {
|
|
687
|
+
__privateGet(this, _subscribers2).forEach((callback) => {
|
|
688
|
+
callback(this.valueSync);
|
|
689
|
+
});
|
|
690
|
+
};
|
|
564
691
|
// Annotate the CommonJS export names for ESM import in node:
|
|
565
692
|
0 && (module.exports = {
|
|
566
693
|
BackoffDefaults,
|