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