@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.
@@ -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/client.ts
151
- var BackoffDefaults = {
152
- initialDelay: 100,
153
- maxDelay: 1e4,
154
- multiplier: 1.3
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.messageQueue = [];
159
- this.isProcessing = false;
160
- this.callback = callback;
189
+ __privateAdd(this, _queue, new AsyncProcessingQueue());
190
+ __privateAdd(this, _callback);
191
+ __privateSet(this, _callback, callback);
161
192
  }
162
193
  process(messages) {
163
- this.messageQueue.push(messages);
164
- if (!this.isProcessing) {
165
- this.processQueue();
166
- }
194
+ __privateGet(this, _queue).process(() => __privateGet(this, _callback).call(this, messages));
167
195
  }
168
- async processQueue() {
169
- this.isProcessing = true;
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,312 +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.subscribers = /* @__PURE__ */ new Map();
206
- this.upToDateSubscribers = /* @__PURE__ */ new Map();
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.isUpToDate = false;
209
- this.connected = false;
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
- this.validateOptions(options);
306
+ validateOptions(options);
212
307
  this.options = __spreadValues({ subscribe: true }, options);
213
- this.lastOffset = (_a = this.options.offset) != null ? _a : `-1`;
214
- this.shapeId = this.options.shapeId;
215
- this.messageParser = new MessageParser(options.parser);
216
- this.backoffOptions = (_b = options.backoffOptions) != null ? _b : BackoffDefaults;
217
- this.fetchClient = (_c = options.fetchClient) != null ? _c : (...args) => fetch(...args);
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.isUpToDate = false;
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.isUpToDate || this.options.subscribe) {
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(`where`, where);
228
- fetchUrl.searchParams.set(`offset`, this.lastOffset);
229
- if (this.isUpToDate) {
230
- fetchUrl.searchParams.set(`live`, `true`);
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.shapeId) {
233
- fetchUrl.searchParams.set(`shape_id`, this.shapeId);
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
- const maybeResponse = await this.fetchWithBackoff(fetchUrl);
238
- if (maybeResponse) response = maybeResponse;
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.reset();
244
- this.publish(e.json);
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[`x-electric-shape-id`];
248
- this.reset(newShapeId);
249
- this.publish(e.json);
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.sendErrorToUpToDateSubscribers(e);
253
- this.sendErrorToSubscribers(e);
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(`X-Electric-Shape-Id`);
367
+ const shapeId = headers.get(SHAPE_ID_HEADER);
259
368
  if (shapeId) {
260
- this.shapeId = shapeId;
369
+ __privateSet(this, _shapeId, shapeId);
261
370
  }
262
- const lastOffset = headers.get(`X-Electric-Chunk-Last-Offset`);
371
+ const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
263
372
  if (lastOffset) {
264
- this.lastOffset = lastOffset;
373
+ __privateSet(this, _lastOffset, lastOffset);
265
374
  }
266
375
  const getSchema = () => {
267
- const schemaHeader = headers.get(`X-Electric-Schema`);
376
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
268
377
  return schemaHeader ? JSON.parse(schemaHeader) : {};
269
378
  };
270
- this.schema = (_a = this.schema) != null ? _a : getSchema();
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.lastSyncedAt = Date.now();
382
+ __privateSet(this, _lastSyncedAt, Date.now());
274
383
  }
275
- const batch = this.messageParser.parse(messages, this.schema);
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 (isControlMessage(lastMessage) && lastMessage.headers.control === `up-to-date`) {
279
- this.lastSyncedAt = Date.now();
280
- if (!this.isUpToDate) {
281
- this.isUpToDate = true;
282
- this.notifyUpToDateSubscribers();
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.publish(batch);
394
+ __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
286
395
  }
287
396
  }
288
397
  } finally {
289
- this.connected = false;
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.subscribers.set(subscriptionId, [subscriber, onError]);
404
+ __privateGet(this, _subscribers).set(subscriptionId, [subscriber, onError]);
296
405
  return () => {
297
- this.subscribers.delete(subscriptionId);
406
+ __privateGet(this, _subscribers).delete(subscriptionId);
298
407
  };
299
408
  }
300
409
  unsubscribeAll() {
301
- this.subscribers.clear();
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.upToDateSubscribers.set(subscriptionId, [callback, error]);
414
+ __privateGet(this, _upToDateSubscribers).set(subscriptionId, [callback, error]);
316
415
  return () => {
317
- this.upToDateSubscribers.delete(subscriptionId);
416
+ __privateGet(this, _upToDateSubscribers).delete(subscriptionId);
318
417
  };
319
418
  }
320
419
  unsubscribeAllUpToDateSubscribers() {
321
- this.upToDateSubscribers.clear();
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.lastSyncedAt === void 0) return Infinity;
326
- return Date.now() - this.lastSyncedAt;
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.connected;
433
+ return __privateGet(this, _connected);
330
434
  }
331
- notifyUpToDateSubscribers() {
332
- this.upToDateSubscribers.forEach(([callback]) => {
333
- callback();
334
- });
435
+ /** True during initial fetch. False afterwise. */
436
+ isLoading() {
437
+ return !this.isUpToDate;
335
438
  }
336
- sendErrorToUpToDateSubscribers(error) {
337
- this.upToDateSubscribers.forEach(
338
- ([_, errorCallback]) => errorCallback(error)
339
- );
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`);
340
485
  }
341
- /**
342
- * Resets the state of the stream, optionally with a provided
343
- * shape ID
344
- */
345
- reset(shapeId) {
346
- this.lastOffset = `-1`;
347
- this.shapeId = shapeId;
348
- this.isUpToDate = false;
349
- this.connected = false;
350
- this.schema = void 0;
351
- }
352
- validateOptions(options) {
353
- if (!options.url) {
354
- throw new Error(`Invalid shape option. It must provide the url`);
355
- }
356
- if (options.signal && !(options.signal instanceof AbortSignal)) {
357
- throw new Error(
358
- `Invalid signal option. It must be an instance of AbortSignal.`
359
- );
360
- }
361
- if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeId) {
362
- throw new Error(
363
- `shapeId is required if this isn't an initial fetch (i.e. offset > -1)`
364
- );
365
- }
486
+ if (options.signal && !(options.signal instanceof AbortSignal)) {
487
+ throw new Error(
488
+ `Invalid signal option. It must be an instance of AbortSignal.`
489
+ );
366
490
  }
367
- async fetchWithBackoff(url) {
368
- const { initialDelay, maxDelay, multiplier } = this.backoffOptions;
369
- const signal = this.options.signal;
370
- let delay = initialDelay;
371
- let attempt = 0;
372
- while (true) {
373
- try {
374
- const result = await this.fetchClient(url.toString(), { signal });
375
- if (result.ok) {
376
- if (this.options.subscribe) {
377
- this.connected = true;
378
- }
379
- return result;
380
- } else throw await FetchError.fromResponse(result, url.toString());
381
- } catch (e) {
382
- this.connected = false;
383
- if (signal == null ? void 0 : signal.aborted) {
384
- return void 0;
385
- } else if (e instanceof FetchError && e.status >= 400 && e.status < 500) {
386
- throw e;
387
- } else {
388
- await new Promise((resolve) => setTimeout(resolve, delay));
389
- delay = Math.min(delay * multiplier, maxDelay);
390
- attempt++;
391
- console.log(`Retry attempt #${attempt} after ${delay}ms`);
392
- }
393
- }
394
- }
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
+ );
395
495
  }
396
- };
496
+ return;
497
+ }
498
+
499
+ // src/shape.ts
500
+ var _stream, _data, _subscribers2, _hasNotifiedSubscribersUpToDate, _error, _Shape_instances, process_fn, handleError_fn, notify_fn;
397
501
  var Shape = class {
398
502
  constructor(stream) {
399
- this.data = /* @__PURE__ */ new Map();
400
- this.subscribers = /* @__PURE__ */ new Map();
401
- this.error = false;
402
- this.hasNotifiedSubscribersUpToDate = false;
403
- this.stream = stream;
404
- this.stream.subscribe(this.process.bind(this), this.handleError.bind(this));
405
- const unsubscribe = this.stream.subscribeOnceToUpToDate(
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(
406
515
  () => {
407
516
  unsubscribe();
408
517
  },
409
518
  (e) => {
410
- this.handleError(e);
519
+ __privateMethod(this, _Shape_instances, handleError_fn).call(this, e);
411
520
  throw e;
412
521
  }
413
522
  );
414
523
  }
415
- lastSynced() {
416
- return this.stream.lastSynced();
417
- }
418
- isConnected() {
419
- return this.stream.isConnected();
524
+ get isUpToDate() {
525
+ return __privateGet(this, _stream).isUpToDate;
420
526
  }
421
527
  get value() {
422
- return new Promise((resolve) => {
423
- if (this.stream.isUpToDate) {
528
+ return new Promise((resolve, reject) => {
529
+ if (__privateGet(this, _stream).isUpToDate) {
424
530
  resolve(this.valueSync);
425
531
  } else {
426
- const unsubscribe = this.stream.subscribeOnceToUpToDate(
427
- () => {
428
- unsubscribe();
429
- resolve(this.valueSync);
430
- },
431
- (e) => {
432
- throw e;
433
- }
434
- );
532
+ const unsubscribe = this.subscribe((shapeData) => {
533
+ unsubscribe();
534
+ if (__privateGet(this, _error)) reject(__privateGet(this, _error));
535
+ resolve(shapeData);
536
+ });
435
537
  }
436
538
  });
437
539
  }
438
540
  get valueSync() {
439
- return this.data;
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();
440
561
  }
441
562
  subscribe(callback) {
442
563
  const subscriptionId = Math.random();
443
- this.subscribers.set(subscriptionId, callback);
564
+ __privateGet(this, _subscribers2).set(subscriptionId, callback);
444
565
  return () => {
445
- this.subscribers.delete(subscriptionId);
566
+ __privateGet(this, _subscribers2).delete(subscriptionId);
446
567
  };
447
568
  }
448
569
  unsubscribeAll() {
449
- this.subscribers.clear();
570
+ __privateGet(this, _subscribers2).clear();
450
571
  }
451
572
  get numSubscribers() {
452
- return this.subscribers.size;
573
+ return __privateGet(this, _subscribers2).size;
453
574
  }
454
- process(messages) {
455
- let dataMayHaveChanged = false;
456
- let isUpToDate = false;
457
- let newlyUpToDate = false;
458
- messages.forEach((message) => {
459
- if (isChangeMessage(message)) {
460
- dataMayHaveChanged = [`insert`, `update`, `delete`].includes(
461
- message.headers.operation
462
- );
463
- switch (message.headers.operation) {
464
- case `insert`:
465
- this.data.set(message.key, message.value);
466
- break;
467
- case `update`:
468
- this.data.set(message.key, __spreadValues(__spreadValues({}, this.data.get(message.key)), message.value));
469
- break;
470
- case `delete`:
471
- this.data.delete(message.key);
472
- break;
473
- }
474
- }
475
- if (isControlMessage(message)) {
476
- switch (message.headers.control) {
477
- case `up-to-date`:
478
- isUpToDate = true;
479
- if (!this.hasNotifiedSubscribersUpToDate) {
480
- newlyUpToDate = true;
481
- }
482
- break;
483
- case `must-refetch`:
484
- this.data.clear();
485
- this.error = false;
486
- isUpToDate = false;
487
- newlyUpToDate = false;
488
- break;
489
- }
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;
490
601
  }
491
- });
492
- if (newlyUpToDate || isUpToDate && dataMayHaveChanged) {
493
- this.hasNotifiedSubscribersUpToDate = true;
494
- this.notify();
495
602
  }
496
- }
497
- handleError(e) {
498
- if (e instanceof FetchError) {
499
- this.error = e;
500
- this.notify();
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
+ }
501
618
  }
619
+ });
620
+ if (newlyUpToDate || isUpToDate && dataMayHaveChanged) {
621
+ __privateSet(this, _hasNotifiedSubscribersUpToDate, true);
622
+ __privateMethod(this, _Shape_instances, notify_fn).call(this);
502
623
  }
503
- notify() {
504
- this.subscribers.forEach((callback) => {
505
- callback(this.valueSync);
506
- });
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);
507
629
  }
508
630
  };
631
+ notify_fn = function() {
632
+ __privateGet(this, _subscribers2).forEach((callback) => {
633
+ callback(this.valueSync);
634
+ });
635
+ };
509
636
  export {
510
637
  BackoffDefaults,
511
638
  FetchError,