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