@electric-sql/client 0.5.0 → 0.6.0
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/README.md +2 -0
- package/dist/cjs/index.cjs +436 -240
- 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 +57 -50
- package/dist/index.legacy-esm.js +434 -236
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +436 -240
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +179 -422
- package/src/constants.ts +8 -0
- package/src/error.ts +50 -0
- package/src/fetch.ts +272 -0
- package/src/helpers.ts +6 -0
- package/src/index.ts +4 -1
- 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,11 @@ 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
|
-
var BackoffDefaults = {
|
|
199
|
-
initialDelay: 100,
|
|
200
|
-
maxDelay: 1e4,
|
|
201
|
-
multiplier: 1.3
|
|
202
|
-
};
|
|
203
|
-
var MessageProcessor = class {
|
|
204
|
-
constructor(callback) {
|
|
205
|
-
this.messageQueue = [];
|
|
206
|
-
this.isProcessing = false;
|
|
207
|
-
this.callback = callback;
|
|
208
|
-
}
|
|
209
|
-
process(messages) {
|
|
210
|
-
this.messageQueue.push(messages);
|
|
211
|
-
if (!this.isProcessing) {
|
|
212
|
-
this.processQueue();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
processQueue() {
|
|
216
|
-
return __async(this, null, function* () {
|
|
217
|
-
this.isProcessing = true;
|
|
218
|
-
while (this.messageQueue.length > 0) {
|
|
219
|
-
const messages = this.messageQueue.shift();
|
|
220
|
-
yield this.callback(messages);
|
|
221
|
-
}
|
|
222
|
-
this.isProcessing = false;
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
};
|
|
211
|
+
// src/error.ts
|
|
226
212
|
var FetchError = class _FetchError extends Error {
|
|
227
213
|
constructor(status, text, json, headers, url, message) {
|
|
228
214
|
super(
|
|
@@ -251,324 +237,534 @@ var FetchError = class _FetchError extends Error {
|
|
|
251
237
|
});
|
|
252
238
|
}
|
|
253
239
|
};
|
|
240
|
+
var FetchBackoffAbortError = class extends Error {
|
|
241
|
+
constructor() {
|
|
242
|
+
super(`Fetch with backoff aborted`);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// src/constants.ts
|
|
247
|
+
var SHAPE_ID_HEADER = `electric-shape-id`;
|
|
248
|
+
var CHUNK_LAST_OFFSET_HEADER = `electric-chunk-last-offset`;
|
|
249
|
+
var CHUNK_UP_TO_DATE_HEADER = `electric-chunk-up-to-date`;
|
|
250
|
+
var SHAPE_SCHEMA_HEADER = `electric-schema`;
|
|
251
|
+
var SHAPE_ID_QUERY_PARAM = `shape_id`;
|
|
252
|
+
var OFFSET_QUERY_PARAM = `offset`;
|
|
253
|
+
var WHERE_QUERY_PARAM = `where`;
|
|
254
|
+
var LIVE_QUERY_PARAM = `live`;
|
|
255
|
+
|
|
256
|
+
// src/fetch.ts
|
|
257
|
+
var BackoffDefaults = {
|
|
258
|
+
initialDelay: 100,
|
|
259
|
+
maxDelay: 1e4,
|
|
260
|
+
multiplier: 1.3
|
|
261
|
+
};
|
|
262
|
+
function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
|
|
263
|
+
const {
|
|
264
|
+
initialDelay,
|
|
265
|
+
maxDelay,
|
|
266
|
+
multiplier,
|
|
267
|
+
debug = false,
|
|
268
|
+
onFailedAttempt
|
|
269
|
+
} = backoffOptions;
|
|
270
|
+
return (...args) => __async(this, null, function* () {
|
|
271
|
+
var _a;
|
|
272
|
+
const url = args[0];
|
|
273
|
+
const options = args[1];
|
|
274
|
+
let delay = initialDelay;
|
|
275
|
+
let attempt = 0;
|
|
276
|
+
while (true) {
|
|
277
|
+
try {
|
|
278
|
+
const result = yield fetchClient(...args);
|
|
279
|
+
if (result.ok) return result;
|
|
280
|
+
else throw yield FetchError.fromResponse(result, url.toString());
|
|
281
|
+
} catch (e) {
|
|
282
|
+
onFailedAttempt == null ? void 0 : onFailedAttempt();
|
|
283
|
+
if ((_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.aborted) {
|
|
284
|
+
throw new FetchBackoffAbortError();
|
|
285
|
+
} else if (e instanceof FetchError && e.status >= 400 && e.status < 500) {
|
|
286
|
+
throw e;
|
|
287
|
+
} else {
|
|
288
|
+
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
289
|
+
delay = Math.min(delay * multiplier, maxDelay);
|
|
290
|
+
if (debug) {
|
|
291
|
+
attempt++;
|
|
292
|
+
console.log(`Retry attempt #${attempt} after ${delay}ms`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
var ChunkPrefetchDefaults = {
|
|
300
|
+
maxChunksToPrefetch: 2
|
|
301
|
+
};
|
|
302
|
+
function createFetchWithChunkBuffer(fetchClient, prefetchOptions = ChunkPrefetchDefaults) {
|
|
303
|
+
const { maxChunksToPrefetch } = prefetchOptions;
|
|
304
|
+
let prefetchQueue;
|
|
305
|
+
const prefetchClient = (...args) => __async(this, null, function* () {
|
|
306
|
+
const url = args[0].toString();
|
|
307
|
+
const prefetchedRequest = prefetchQueue == null ? void 0 : prefetchQueue.consume(...args);
|
|
308
|
+
if (prefetchedRequest) {
|
|
309
|
+
return prefetchedRequest;
|
|
310
|
+
}
|
|
311
|
+
prefetchQueue == null ? void 0 : prefetchQueue.abort();
|
|
312
|
+
const response = yield fetchClient(...args);
|
|
313
|
+
const nextUrl = getNextChunkUrl(url, response);
|
|
314
|
+
if (nextUrl) {
|
|
315
|
+
prefetchQueue = new PrefetchQueue({
|
|
316
|
+
fetchClient,
|
|
317
|
+
maxPrefetchedRequests: maxChunksToPrefetch,
|
|
318
|
+
url: nextUrl,
|
|
319
|
+
requestInit: args[1]
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
return response;
|
|
323
|
+
});
|
|
324
|
+
return prefetchClient;
|
|
325
|
+
}
|
|
326
|
+
var _fetchClient, _maxPrefetchedRequests, _prefetchQueue, _queueHeadUrl, _queueTailUrl, _PrefetchQueue_instances, prefetch_fn;
|
|
327
|
+
var PrefetchQueue = class {
|
|
328
|
+
constructor(options) {
|
|
329
|
+
__privateAdd(this, _PrefetchQueue_instances);
|
|
330
|
+
__privateAdd(this, _fetchClient);
|
|
331
|
+
__privateAdd(this, _maxPrefetchedRequests);
|
|
332
|
+
__privateAdd(this, _prefetchQueue, /* @__PURE__ */ new Map());
|
|
333
|
+
__privateAdd(this, _queueHeadUrl);
|
|
334
|
+
__privateAdd(this, _queueTailUrl);
|
|
335
|
+
var _a;
|
|
336
|
+
__privateSet(this, _fetchClient, (_a = options.fetchClient) != null ? _a : (...args) => fetch(...args));
|
|
337
|
+
__privateSet(this, _maxPrefetchedRequests, options.maxPrefetchedRequests);
|
|
338
|
+
__privateSet(this, _queueHeadUrl, options.url.toString());
|
|
339
|
+
__privateSet(this, _queueTailUrl, __privateGet(this, _queueHeadUrl));
|
|
340
|
+
__privateMethod(this, _PrefetchQueue_instances, prefetch_fn).call(this, options.url, options.requestInit);
|
|
341
|
+
}
|
|
342
|
+
abort() {
|
|
343
|
+
__privateGet(this, _prefetchQueue).forEach(([_, aborter]) => aborter.abort());
|
|
344
|
+
}
|
|
345
|
+
consume(...args) {
|
|
346
|
+
var _a;
|
|
347
|
+
const url = args[0].toString();
|
|
348
|
+
const request = (_a = __privateGet(this, _prefetchQueue).get(url)) == null ? void 0 : _a[0];
|
|
349
|
+
if (!request || url !== __privateGet(this, _queueHeadUrl)) return;
|
|
350
|
+
__privateGet(this, _prefetchQueue).delete(url);
|
|
351
|
+
request.then((response) => {
|
|
352
|
+
const nextUrl = getNextChunkUrl(url, response);
|
|
353
|
+
__privateSet(this, _queueHeadUrl, nextUrl);
|
|
354
|
+
if (!__privateGet(this, _prefetchQueue).has(__privateGet(this, _queueTailUrl))) {
|
|
355
|
+
__privateMethod(this, _PrefetchQueue_instances, prefetch_fn).call(this, __privateGet(this, _queueTailUrl), args[1]);
|
|
356
|
+
}
|
|
357
|
+
}).catch(() => {
|
|
358
|
+
});
|
|
359
|
+
return request;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
_fetchClient = new WeakMap();
|
|
363
|
+
_maxPrefetchedRequests = new WeakMap();
|
|
364
|
+
_prefetchQueue = new WeakMap();
|
|
365
|
+
_queueHeadUrl = new WeakMap();
|
|
366
|
+
_queueTailUrl = new WeakMap();
|
|
367
|
+
_PrefetchQueue_instances = new WeakSet();
|
|
368
|
+
prefetch_fn = function(...args) {
|
|
369
|
+
var _a, _b;
|
|
370
|
+
const url = args[0].toString();
|
|
371
|
+
if (__privateGet(this, _prefetchQueue).size >= __privateGet(this, _maxPrefetchedRequests)) return;
|
|
372
|
+
const aborter = new AbortController();
|
|
373
|
+
try {
|
|
374
|
+
const request = __privateGet(this, _fetchClient).call(this, url, __spreadProps(__spreadValues({}, (_a = args[1]) != null ? _a : {}), {
|
|
375
|
+
signal: chainAborter(aborter, (_b = args[1]) == null ? void 0 : _b.signal)
|
|
376
|
+
}));
|
|
377
|
+
__privateGet(this, _prefetchQueue).set(url, [request, aborter]);
|
|
378
|
+
request.then((response) => {
|
|
379
|
+
if (!response.ok || aborter.signal.aborted) return;
|
|
380
|
+
const nextUrl = getNextChunkUrl(url, response);
|
|
381
|
+
if (!nextUrl || nextUrl === url) return;
|
|
382
|
+
__privateSet(this, _queueTailUrl, nextUrl);
|
|
383
|
+
return __privateMethod(this, _PrefetchQueue_instances, prefetch_fn).call(this, nextUrl, args[1]);
|
|
384
|
+
}).catch(() => {
|
|
385
|
+
});
|
|
386
|
+
} catch (_) {
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
function getNextChunkUrl(url, res) {
|
|
390
|
+
const shapeId = res.headers.get(SHAPE_ID_HEADER);
|
|
391
|
+
const lastOffset = res.headers.get(CHUNK_LAST_OFFSET_HEADER);
|
|
392
|
+
const isUpToDate = res.headers.has(CHUNK_UP_TO_DATE_HEADER);
|
|
393
|
+
if (!shapeId || !lastOffset || isUpToDate) return;
|
|
394
|
+
const nextUrl = new URL(url);
|
|
395
|
+
if (nextUrl.searchParams.has(LIVE_QUERY_PARAM)) return;
|
|
396
|
+
nextUrl.searchParams.set(SHAPE_ID_QUERY_PARAM, shapeId);
|
|
397
|
+
nextUrl.searchParams.set(OFFSET_QUERY_PARAM, lastOffset);
|
|
398
|
+
return nextUrl.toString();
|
|
399
|
+
}
|
|
400
|
+
function chainAborter(aborter, sourceSignal) {
|
|
401
|
+
if (!sourceSignal) return aborter.signal;
|
|
402
|
+
if (sourceSignal.aborted) aborter.abort();
|
|
403
|
+
else
|
|
404
|
+
sourceSignal.addEventListener(`abort`, () => aborter.abort(), {
|
|
405
|
+
once: true
|
|
406
|
+
});
|
|
407
|
+
return aborter.signal;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/client.ts
|
|
411
|
+
var _fetchClient2, _messageParser, _subscribers, _upToDateSubscribers, _lastOffset, _lastSyncedAt, _isUpToDate, _connected, _shapeId, _schema, _ShapeStream_instances, publish_fn, sendErrorToSubscribers_fn, notifyUpToDateSubscribers_fn, sendErrorToUpToDateSubscribers_fn, reset_fn;
|
|
254
412
|
var ShapeStream = class {
|
|
255
413
|
constructor(options) {
|
|
256
|
-
this
|
|
257
|
-
this
|
|
414
|
+
__privateAdd(this, _ShapeStream_instances);
|
|
415
|
+
__privateAdd(this, _fetchClient2);
|
|
416
|
+
__privateAdd(this, _messageParser);
|
|
417
|
+
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
418
|
+
__privateAdd(this, _upToDateSubscribers, /* @__PURE__ */ new Map());
|
|
419
|
+
__privateAdd(this, _lastOffset);
|
|
420
|
+
__privateAdd(this, _lastSyncedAt);
|
|
258
421
|
// unix time
|
|
259
|
-
this
|
|
260
|
-
this
|
|
422
|
+
__privateAdd(this, _isUpToDate, false);
|
|
423
|
+
__privateAdd(this, _connected, false);
|
|
424
|
+
__privateAdd(this, _shapeId);
|
|
425
|
+
__privateAdd(this, _schema);
|
|
261
426
|
var _a, _b, _c;
|
|
262
|
-
|
|
427
|
+
validateOptions(options);
|
|
263
428
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
264
|
-
this
|
|
265
|
-
this
|
|
266
|
-
this
|
|
267
|
-
|
|
268
|
-
|
|
429
|
+
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
430
|
+
__privateSet(this, _shapeId, this.options.shapeId);
|
|
431
|
+
__privateSet(this, _messageParser, new MessageParser(options.parser));
|
|
432
|
+
const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
|
|
433
|
+
const fetchWithBackoffClient = createFetchWithBackoff(baseFetchClient, __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
|
|
434
|
+
onFailedAttempt: () => {
|
|
435
|
+
var _a2, _b2;
|
|
436
|
+
__privateSet(this, _connected, false);
|
|
437
|
+
(_b2 = (_a2 = options.backoffOptions) == null ? void 0 : _a2.onFailedAttempt) == null ? void 0 : _b2.call(_a2);
|
|
438
|
+
}
|
|
439
|
+
}));
|
|
440
|
+
__privateSet(this, _fetchClient2, createFetchWithChunkBuffer(fetchWithBackoffClient));
|
|
269
441
|
this.start();
|
|
270
442
|
}
|
|
443
|
+
get shapeId() {
|
|
444
|
+
return __privateGet(this, _shapeId);
|
|
445
|
+
}
|
|
446
|
+
get isUpToDate() {
|
|
447
|
+
return __privateGet(this, _isUpToDate);
|
|
448
|
+
}
|
|
271
449
|
start() {
|
|
272
450
|
return __async(this, null, function* () {
|
|
273
451
|
var _a;
|
|
274
|
-
this
|
|
452
|
+
__privateSet(this, _isUpToDate, false);
|
|
275
453
|
const { url, where, signal } = this.options;
|
|
276
454
|
try {
|
|
277
|
-
while (!(signal == null ? void 0 : signal.aborted) && !this
|
|
455
|
+
while (!(signal == null ? void 0 : signal.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
|
|
278
456
|
const fetchUrl = new URL(url);
|
|
279
|
-
if (where) fetchUrl.searchParams.set(
|
|
280
|
-
fetchUrl.searchParams.set(
|
|
281
|
-
if (this
|
|
282
|
-
fetchUrl.searchParams.set(
|
|
457
|
+
if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
|
|
458
|
+
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
459
|
+
if (__privateGet(this, _isUpToDate)) {
|
|
460
|
+
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
283
461
|
}
|
|
284
|
-
if (this
|
|
285
|
-
fetchUrl.searchParams.set(
|
|
462
|
+
if (__privateGet(this, _shapeId)) {
|
|
463
|
+
fetchUrl.searchParams.set(SHAPE_ID_QUERY_PARAM, __privateGet(this, _shapeId));
|
|
286
464
|
}
|
|
287
465
|
let response;
|
|
288
466
|
try {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
else break;
|
|
467
|
+
response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), { signal });
|
|
468
|
+
__privateSet(this, _connected, true);
|
|
292
469
|
} catch (e) {
|
|
470
|
+
if (e instanceof FetchBackoffAbortError) break;
|
|
293
471
|
if (!(e instanceof FetchError)) throw e;
|
|
294
472
|
if (e.status == 400) {
|
|
295
|
-
this.
|
|
296
|
-
this.
|
|
473
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this);
|
|
474
|
+
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
297
475
|
continue;
|
|
298
476
|
} else if (e.status == 409) {
|
|
299
|
-
const newShapeId = e.headers[
|
|
300
|
-
this.
|
|
301
|
-
this.
|
|
477
|
+
const newShapeId = e.headers[SHAPE_ID_HEADER];
|
|
478
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeId);
|
|
479
|
+
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
302
480
|
continue;
|
|
303
481
|
} else if (e.status >= 400 && e.status < 500) {
|
|
304
|
-
this.
|
|
305
|
-
this.
|
|
482
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToUpToDateSubscribers_fn).call(this, e);
|
|
483
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
306
484
|
throw e;
|
|
307
485
|
}
|
|
308
486
|
}
|
|
309
487
|
const { headers, status } = response;
|
|
310
|
-
const shapeId = headers.get(
|
|
488
|
+
const shapeId = headers.get(SHAPE_ID_HEADER);
|
|
311
489
|
if (shapeId) {
|
|
312
|
-
this
|
|
490
|
+
__privateSet(this, _shapeId, shapeId);
|
|
313
491
|
}
|
|
314
|
-
const lastOffset = headers.get(
|
|
492
|
+
const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
|
|
315
493
|
if (lastOffset) {
|
|
316
|
-
this
|
|
494
|
+
__privateSet(this, _lastOffset, lastOffset);
|
|
317
495
|
}
|
|
318
496
|
const getSchema = () => {
|
|
319
|
-
const schemaHeader = headers.get(
|
|
497
|
+
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
320
498
|
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
321
499
|
};
|
|
322
|
-
this
|
|
500
|
+
__privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
|
|
323
501
|
const messages = status === 204 ? `[]` : yield response.text();
|
|
324
502
|
if (status === 204) {
|
|
325
|
-
this
|
|
503
|
+
__privateSet(this, _lastSyncedAt, Date.now());
|
|
326
504
|
}
|
|
327
|
-
const batch = this.
|
|
505
|
+
const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
|
|
328
506
|
if (batch.length > 0) {
|
|
507
|
+
const prevUpToDate = __privateGet(this, _isUpToDate);
|
|
329
508
|
const lastMessage = batch[batch.length - 1];
|
|
330
|
-
if (
|
|
331
|
-
this
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
509
|
+
if (isUpToDateMessage(lastMessage)) {
|
|
510
|
+
__privateSet(this, _lastSyncedAt, Date.now());
|
|
511
|
+
__privateSet(this, _isUpToDate, true);
|
|
512
|
+
}
|
|
513
|
+
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
|
|
514
|
+
if (!prevUpToDate && __privateGet(this, _isUpToDate)) {
|
|
515
|
+
__privateMethod(this, _ShapeStream_instances, notifyUpToDateSubscribers_fn).call(this);
|
|
336
516
|
}
|
|
337
|
-
this.publish(batch);
|
|
338
517
|
}
|
|
339
518
|
}
|
|
340
519
|
} finally {
|
|
341
|
-
this
|
|
520
|
+
__privateSet(this, _connected, false);
|
|
342
521
|
}
|
|
343
522
|
});
|
|
344
523
|
}
|
|
345
524
|
subscribe(callback, onError) {
|
|
346
525
|
const subscriptionId = Math.random();
|
|
347
|
-
|
|
348
|
-
this.subscribers.set(subscriptionId, [subscriber, onError]);
|
|
526
|
+
__privateGet(this, _subscribers).set(subscriptionId, [callback, onError]);
|
|
349
527
|
return () => {
|
|
350
|
-
this.
|
|
528
|
+
__privateGet(this, _subscribers).delete(subscriptionId);
|
|
351
529
|
};
|
|
352
530
|
}
|
|
353
531
|
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
|
-
});
|
|
532
|
+
__privateGet(this, _subscribers).clear();
|
|
365
533
|
}
|
|
366
534
|
subscribeOnceToUpToDate(callback, error) {
|
|
367
535
|
const subscriptionId = Math.random();
|
|
368
|
-
this.
|
|
536
|
+
__privateGet(this, _upToDateSubscribers).set(subscriptionId, [callback, error]);
|
|
369
537
|
return () => {
|
|
370
|
-
this.
|
|
538
|
+
__privateGet(this, _upToDateSubscribers).delete(subscriptionId);
|
|
371
539
|
};
|
|
372
540
|
}
|
|
373
541
|
unsubscribeAllUpToDateSubscribers() {
|
|
374
|
-
this.
|
|
542
|
+
__privateGet(this, _upToDateSubscribers).clear();
|
|
543
|
+
}
|
|
544
|
+
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
545
|
+
lastSyncedAt() {
|
|
546
|
+
return __privateGet(this, _lastSyncedAt);
|
|
375
547
|
}
|
|
376
548
|
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
|
|
377
549
|
lastSynced() {
|
|
378
|
-
if (this
|
|
379
|
-
return Date.now() - this
|
|
550
|
+
if (__privateGet(this, _lastSyncedAt) === void 0) return Infinity;
|
|
551
|
+
return Date.now() - __privateGet(this, _lastSyncedAt);
|
|
380
552
|
}
|
|
553
|
+
/** Indicates if we are connected to the Electric sync service. */
|
|
381
554
|
isConnected() {
|
|
382
|
-
return this
|
|
555
|
+
return __privateGet(this, _connected);
|
|
383
556
|
}
|
|
384
557
|
/** True during initial fetch. False afterwise. */
|
|
385
558
|
isLoading() {
|
|
386
559
|
return !this.isUpToDate;
|
|
387
560
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
561
|
+
};
|
|
562
|
+
_fetchClient2 = new WeakMap();
|
|
563
|
+
_messageParser = new WeakMap();
|
|
564
|
+
_subscribers = new WeakMap();
|
|
565
|
+
_upToDateSubscribers = new WeakMap();
|
|
566
|
+
_lastOffset = new WeakMap();
|
|
567
|
+
_lastSyncedAt = new WeakMap();
|
|
568
|
+
_isUpToDate = new WeakMap();
|
|
569
|
+
_connected = new WeakMap();
|
|
570
|
+
_shapeId = new WeakMap();
|
|
571
|
+
_schema = new WeakMap();
|
|
572
|
+
_ShapeStream_instances = new WeakSet();
|
|
573
|
+
publish_fn = function(messages) {
|
|
574
|
+
return __async(this, null, function* () {
|
|
575
|
+
yield Promise.all(
|
|
576
|
+
Array.from(__privateGet(this, _subscribers).values()).map((_0) => __async(this, [_0], function* ([callback, __]) {
|
|
577
|
+
try {
|
|
578
|
+
yield callback(messages);
|
|
579
|
+
} catch (err) {
|
|
580
|
+
queueMicrotask(() => {
|
|
581
|
+
throw err;
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
}))
|
|
396
585
|
);
|
|
586
|
+
});
|
|
587
|
+
};
|
|
588
|
+
sendErrorToSubscribers_fn = function(error) {
|
|
589
|
+
__privateGet(this, _subscribers).forEach(([_, errorFn]) => {
|
|
590
|
+
errorFn == null ? void 0 : errorFn(error);
|
|
591
|
+
});
|
|
592
|
+
};
|
|
593
|
+
notifyUpToDateSubscribers_fn = function() {
|
|
594
|
+
__privateGet(this, _upToDateSubscribers).forEach(([callback]) => {
|
|
595
|
+
callback();
|
|
596
|
+
});
|
|
597
|
+
};
|
|
598
|
+
sendErrorToUpToDateSubscribers_fn = function(error) {
|
|
599
|
+
__privateGet(this, _upToDateSubscribers).forEach(
|
|
600
|
+
([_, errorCallback]) => errorCallback(error)
|
|
601
|
+
);
|
|
602
|
+
};
|
|
603
|
+
/**
|
|
604
|
+
* Resets the state of the stream, optionally with a provided
|
|
605
|
+
* shape ID
|
|
606
|
+
*/
|
|
607
|
+
reset_fn = function(shapeId) {
|
|
608
|
+
__privateSet(this, _lastOffset, `-1`);
|
|
609
|
+
__privateSet(this, _shapeId, shapeId);
|
|
610
|
+
__privateSet(this, _isUpToDate, false);
|
|
611
|
+
__privateSet(this, _connected, false);
|
|
612
|
+
__privateSet(this, _schema, void 0);
|
|
613
|
+
};
|
|
614
|
+
function validateOptions(options) {
|
|
615
|
+
if (!options.url) {
|
|
616
|
+
throw new Error(`Invalid shape option. It must provide the url`);
|
|
397
617
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
reset(shapeId) {
|
|
403
|
-
this.lastOffset = `-1`;
|
|
404
|
-
this.shapeId = shapeId;
|
|
405
|
-
this.isUpToDate = false;
|
|
406
|
-
this.connected = false;
|
|
407
|
-
this.schema = void 0;
|
|
408
|
-
}
|
|
409
|
-
validateOptions(options) {
|
|
410
|
-
if (!options.url) {
|
|
411
|
-
throw new Error(`Invalid shape option. It must provide the url`);
|
|
412
|
-
}
|
|
413
|
-
if (options.signal && !(options.signal instanceof AbortSignal)) {
|
|
414
|
-
throw new Error(
|
|
415
|
-
`Invalid signal option. It must be an instance of AbortSignal.`
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeId) {
|
|
419
|
-
throw new Error(
|
|
420
|
-
`shapeId is required if this isn't an initial fetch (i.e. offset > -1)`
|
|
421
|
-
);
|
|
422
|
-
}
|
|
618
|
+
if (options.signal && !(options.signal instanceof AbortSignal)) {
|
|
619
|
+
throw new Error(
|
|
620
|
+
`Invalid signal option. It must be an instance of AbortSignal.`
|
|
621
|
+
);
|
|
423
622
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
let delay = initialDelay;
|
|
429
|
-
let attempt = 0;
|
|
430
|
-
while (true) {
|
|
431
|
-
try {
|
|
432
|
-
const result = yield this.fetchClient(url.toString(), { signal });
|
|
433
|
-
if (result.ok) {
|
|
434
|
-
if (this.options.subscribe) {
|
|
435
|
-
this.connected = true;
|
|
436
|
-
}
|
|
437
|
-
return result;
|
|
438
|
-
} else throw yield FetchError.fromResponse(result, url.toString());
|
|
439
|
-
} catch (e) {
|
|
440
|
-
this.connected = false;
|
|
441
|
-
if (signal == null ? void 0 : signal.aborted) {
|
|
442
|
-
return void 0;
|
|
443
|
-
} else if (e instanceof FetchError && e.status >= 400 && e.status < 500) {
|
|
444
|
-
throw e;
|
|
445
|
-
} else {
|
|
446
|
-
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
447
|
-
delay = Math.min(delay * multiplier, maxDelay);
|
|
448
|
-
attempt++;
|
|
449
|
-
console.log(`Retry attempt #${attempt} after ${delay}ms`);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
});
|
|
623
|
+
if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeId) {
|
|
624
|
+
throw new Error(
|
|
625
|
+
`shapeId is required if this isn't an initial fetch (i.e. offset > -1)`
|
|
626
|
+
);
|
|
454
627
|
}
|
|
455
|
-
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/shape.ts
|
|
632
|
+
var _stream, _data, _subscribers2, _hasNotifiedSubscribersUpToDate, _error, _Shape_instances, process_fn, handleError_fn, notify_fn;
|
|
456
633
|
var Shape = class {
|
|
457
634
|
constructor(stream) {
|
|
458
|
-
this
|
|
459
|
-
this
|
|
460
|
-
this
|
|
461
|
-
this
|
|
462
|
-
this
|
|
463
|
-
|
|
464
|
-
|
|
635
|
+
__privateAdd(this, _Shape_instances);
|
|
636
|
+
__privateAdd(this, _stream);
|
|
637
|
+
__privateAdd(this, _data, /* @__PURE__ */ new Map());
|
|
638
|
+
__privateAdd(this, _subscribers2, /* @__PURE__ */ new Map());
|
|
639
|
+
__privateAdd(this, _hasNotifiedSubscribersUpToDate, false);
|
|
640
|
+
__privateAdd(this, _error, false);
|
|
641
|
+
__privateSet(this, _stream, stream);
|
|
642
|
+
__privateGet(this, _stream).subscribe(
|
|
643
|
+
__privateMethod(this, _Shape_instances, process_fn).bind(this),
|
|
644
|
+
__privateMethod(this, _Shape_instances, handleError_fn).bind(this)
|
|
645
|
+
);
|
|
646
|
+
const unsubscribe = __privateGet(this, _stream).subscribeOnceToUpToDate(
|
|
465
647
|
() => {
|
|
466
648
|
unsubscribe();
|
|
467
649
|
},
|
|
468
650
|
(e) => {
|
|
469
|
-
this.
|
|
651
|
+
__privateMethod(this, _Shape_instances, handleError_fn).call(this, e);
|
|
470
652
|
throw e;
|
|
471
653
|
}
|
|
472
654
|
);
|
|
473
655
|
}
|
|
474
|
-
|
|
475
|
-
return this.
|
|
476
|
-
}
|
|
477
|
-
isConnected() {
|
|
478
|
-
return this.stream.isConnected();
|
|
479
|
-
}
|
|
480
|
-
/** True during initial fetch. False afterwise. */
|
|
481
|
-
isLoading() {
|
|
482
|
-
return this.stream.isLoading();
|
|
656
|
+
get isUpToDate() {
|
|
657
|
+
return __privateGet(this, _stream).isUpToDate;
|
|
483
658
|
}
|
|
484
659
|
get value() {
|
|
485
|
-
return new Promise((resolve) => {
|
|
486
|
-
if (this.
|
|
660
|
+
return new Promise((resolve, reject) => {
|
|
661
|
+
if (__privateGet(this, _stream).isUpToDate) {
|
|
487
662
|
resolve(this.valueSync);
|
|
488
663
|
} else {
|
|
489
|
-
const unsubscribe = this.
|
|
490
|
-
()
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
(e) => {
|
|
495
|
-
throw e;
|
|
496
|
-
}
|
|
497
|
-
);
|
|
664
|
+
const unsubscribe = this.subscribe((shapeData) => {
|
|
665
|
+
unsubscribe();
|
|
666
|
+
if (__privateGet(this, _error)) reject(__privateGet(this, _error));
|
|
667
|
+
resolve(shapeData);
|
|
668
|
+
});
|
|
498
669
|
}
|
|
499
670
|
});
|
|
500
671
|
}
|
|
501
672
|
get valueSync() {
|
|
502
|
-
return this
|
|
673
|
+
return __privateGet(this, _data);
|
|
674
|
+
}
|
|
675
|
+
get error() {
|
|
676
|
+
return __privateGet(this, _error);
|
|
677
|
+
}
|
|
678
|
+
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
679
|
+
lastSyncedAt() {
|
|
680
|
+
return __privateGet(this, _stream).lastSyncedAt();
|
|
681
|
+
}
|
|
682
|
+
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
|
|
683
|
+
lastSynced() {
|
|
684
|
+
return __privateGet(this, _stream).lastSynced();
|
|
685
|
+
}
|
|
686
|
+
/** True during initial fetch. False afterwise. */
|
|
687
|
+
isLoading() {
|
|
688
|
+
return __privateGet(this, _stream).isLoading();
|
|
689
|
+
}
|
|
690
|
+
/** Indicates if we are connected to the Electric sync service. */
|
|
691
|
+
isConnected() {
|
|
692
|
+
return __privateGet(this, _stream).isConnected();
|
|
503
693
|
}
|
|
504
694
|
subscribe(callback) {
|
|
505
695
|
const subscriptionId = Math.random();
|
|
506
|
-
this.
|
|
696
|
+
__privateGet(this, _subscribers2).set(subscriptionId, callback);
|
|
507
697
|
return () => {
|
|
508
|
-
this.
|
|
698
|
+
__privateGet(this, _subscribers2).delete(subscriptionId);
|
|
509
699
|
};
|
|
510
700
|
}
|
|
511
701
|
unsubscribeAll() {
|
|
512
|
-
this.
|
|
702
|
+
__privateGet(this, _subscribers2).clear();
|
|
513
703
|
}
|
|
514
704
|
get numSubscribers() {
|
|
515
|
-
return this.
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
newlyUpToDate = true;
|
|
544
|
-
}
|
|
545
|
-
break;
|
|
546
|
-
case `must-refetch`:
|
|
547
|
-
this.data.clear();
|
|
548
|
-
this.error = false;
|
|
549
|
-
isUpToDate = false;
|
|
550
|
-
newlyUpToDate = false;
|
|
551
|
-
break;
|
|
552
|
-
}
|
|
705
|
+
return __privateGet(this, _subscribers2).size;
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
_stream = new WeakMap();
|
|
709
|
+
_data = new WeakMap();
|
|
710
|
+
_subscribers2 = new WeakMap();
|
|
711
|
+
_hasNotifiedSubscribersUpToDate = new WeakMap();
|
|
712
|
+
_error = new WeakMap();
|
|
713
|
+
_Shape_instances = new WeakSet();
|
|
714
|
+
process_fn = function(messages) {
|
|
715
|
+
let dataMayHaveChanged = false;
|
|
716
|
+
let isUpToDate = false;
|
|
717
|
+
let newlyUpToDate = false;
|
|
718
|
+
messages.forEach((message) => {
|
|
719
|
+
if (isChangeMessage(message)) {
|
|
720
|
+
dataMayHaveChanged = [`insert`, `update`, `delete`].includes(
|
|
721
|
+
message.headers.operation
|
|
722
|
+
);
|
|
723
|
+
switch (message.headers.operation) {
|
|
724
|
+
case `insert`:
|
|
725
|
+
__privateGet(this, _data).set(message.key, message.value);
|
|
726
|
+
break;
|
|
727
|
+
case `update`:
|
|
728
|
+
__privateGet(this, _data).set(message.key, __spreadValues(__spreadValues({}, __privateGet(this, _data).get(message.key)), message.value));
|
|
729
|
+
break;
|
|
730
|
+
case `delete`:
|
|
731
|
+
__privateGet(this, _data).delete(message.key);
|
|
732
|
+
break;
|
|
553
733
|
}
|
|
554
|
-
});
|
|
555
|
-
if (newlyUpToDate || isUpToDate && dataMayHaveChanged) {
|
|
556
|
-
this.hasNotifiedSubscribersUpToDate = true;
|
|
557
|
-
this.notify();
|
|
558
734
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
735
|
+
if (isControlMessage(message)) {
|
|
736
|
+
switch (message.headers.control) {
|
|
737
|
+
case `up-to-date`:
|
|
738
|
+
isUpToDate = true;
|
|
739
|
+
if (!__privateGet(this, _hasNotifiedSubscribersUpToDate)) {
|
|
740
|
+
newlyUpToDate = true;
|
|
741
|
+
}
|
|
742
|
+
break;
|
|
743
|
+
case `must-refetch`:
|
|
744
|
+
__privateGet(this, _data).clear();
|
|
745
|
+
__privateSet(this, _error, false);
|
|
746
|
+
isUpToDate = false;
|
|
747
|
+
newlyUpToDate = false;
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
564
750
|
}
|
|
751
|
+
});
|
|
752
|
+
if (newlyUpToDate || isUpToDate && dataMayHaveChanged) {
|
|
753
|
+
__privateSet(this, _hasNotifiedSubscribersUpToDate, true);
|
|
754
|
+
__privateMethod(this, _Shape_instances, notify_fn).call(this);
|
|
565
755
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
756
|
+
};
|
|
757
|
+
handleError_fn = function(e) {
|
|
758
|
+
if (e instanceof FetchError) {
|
|
759
|
+
__privateSet(this, _error, e);
|
|
760
|
+
__privateMethod(this, _Shape_instances, notify_fn).call(this);
|
|
570
761
|
}
|
|
571
762
|
};
|
|
763
|
+
notify_fn = function() {
|
|
764
|
+
__privateGet(this, _subscribers2).forEach((callback) => {
|
|
765
|
+
callback(this.valueSync);
|
|
766
|
+
});
|
|
767
|
+
};
|
|
572
768
|
// Annotate the CommonJS export names for ESM import in node:
|
|
573
769
|
0 && (module.exports = {
|
|
574
770
|
BackoffDefaults,
|