@electric-sql/client 0.7.3 → 0.8.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.
@@ -38,6 +38,89 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
38
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
39
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
40
40
 
41
+ // src/error.ts
42
+ var FetchError = class _FetchError extends Error {
43
+ constructor(status, text, json, headers, url, message) {
44
+ super(
45
+ message || `HTTP Error ${status} at ${url}: ${text != null ? text : JSON.stringify(json)}`
46
+ );
47
+ this.url = url;
48
+ this.name = `FetchError`;
49
+ this.status = status;
50
+ this.text = text;
51
+ this.json = json;
52
+ this.headers = headers;
53
+ }
54
+ static async fromResponse(response, url) {
55
+ const status = response.status;
56
+ const headers = Object.fromEntries([...response.headers.entries()]);
57
+ let text = void 0;
58
+ let json = void 0;
59
+ const contentType = response.headers.get(`content-type`);
60
+ if (contentType && contentType.includes(`application/json`)) {
61
+ json = await response.json();
62
+ } else {
63
+ text = await response.text();
64
+ }
65
+ return new _FetchError(status, text, json, headers, url);
66
+ }
67
+ };
68
+ var FetchBackoffAbortError = class extends Error {
69
+ constructor() {
70
+ super(`Fetch with backoff aborted`);
71
+ this.name = `FetchBackoffAbortError`;
72
+ }
73
+ };
74
+ var MissingShapeUrlError = class extends Error {
75
+ constructor() {
76
+ super(`Invalid shape options: missing required url parameter`);
77
+ this.name = `MissingShapeUrlError`;
78
+ }
79
+ };
80
+ var InvalidSignalError = class extends Error {
81
+ constructor() {
82
+ super(`Invalid signal option. It must be an instance of AbortSignal.`);
83
+ this.name = `InvalidSignalError`;
84
+ }
85
+ };
86
+ var MissingShapeHandleError = class extends Error {
87
+ constructor() {
88
+ super(
89
+ `shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`
90
+ );
91
+ this.name = `MissingShapeHandleError`;
92
+ }
93
+ };
94
+ var ReservedParamError = class extends Error {
95
+ constructor(reservedParams) {
96
+ super(
97
+ `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
98
+ );
99
+ this.name = `ReservedParamError`;
100
+ }
101
+ };
102
+ var ParserNullValueError = class extends Error {
103
+ constructor(columnName) {
104
+ super(`Column "${columnName != null ? columnName : `unknown`}" does not allow NULL values`);
105
+ this.name = `ParserNullValueError`;
106
+ }
107
+ };
108
+ var MissingHeadersError = class extends Error {
109
+ constructor(url, missingHeaders) {
110
+ let msg = `The response for the shape request to ${url} didn't include the following required headers:
111
+ `;
112
+ missingHeaders.forEach((h) => {
113
+ msg += `- ${h}
114
+ `;
115
+ });
116
+ msg += `
117
+ This is often due to a proxy not setting CORS correctly so that all Electric headers can be read by the client.`;
118
+ msg += `
119
+ For more information visit the troubleshooting guide: /docs/guides/troubleshooting/missing-headers`;
120
+ super(msg);
121
+ }
122
+ };
123
+
41
124
  // src/parser.ts
42
125
  var parseNumber = (value) => Number(value);
43
126
  var parseBool = (value) => value === `true` || value === `t`;
@@ -139,7 +222,7 @@ function makeNullableParser(parser, columnInfo, columnName) {
139
222
  return (value) => {
140
223
  if (isPgNull(value)) {
141
224
  if (!isNullable) {
142
- throw new Error(`Column ${columnName != null ? columnName : `unknown`} is not nullable`);
225
+ throw new ParserNullValueError(columnName != null ? columnName : `unknown`);
143
226
  }
144
227
  return null;
145
228
  }
@@ -161,52 +244,6 @@ function isUpToDateMessage(message) {
161
244
  return isControlMessage(message) && message.headers.control === `up-to-date`;
162
245
  }
163
246
 
164
- // src/error.ts
165
- var FetchError = class _FetchError extends Error {
166
- constructor(status, text, json, headers, url, message) {
167
- super(
168
- message || `HTTP Error ${status} at ${url}: ${text != null ? text : JSON.stringify(json)}`
169
- );
170
- this.url = url;
171
- this.name = `FetchError`;
172
- this.status = status;
173
- this.text = text;
174
- this.json = json;
175
- this.headers = headers;
176
- }
177
- static async fromResponse(response, url) {
178
- const status = response.status;
179
- const headers = Object.fromEntries([...response.headers.entries()]);
180
- let text = void 0;
181
- let json = void 0;
182
- const contentType = response.headers.get(`content-type`);
183
- if (contentType && contentType.includes(`application/json`)) {
184
- json = await response.json();
185
- } else {
186
- text = await response.text();
187
- }
188
- return new _FetchError(status, text, json, headers, url);
189
- }
190
- };
191
- var FetchBackoffAbortError = class extends Error {
192
- constructor() {
193
- super(`Fetch with backoff aborted`);
194
- }
195
- };
196
- var MissingHeadersError = class extends Error {
197
- constructor(url, missingHeaders) {
198
- let msg = `The response for the shape request to ${url} didn't include the following required headers:
199
- `;
200
- missingHeaders.forEach((h) => {
201
- msg += `- ${h}
202
- `;
203
- });
204
- msg += `
205
- This is often due to a proxy not setting CORS correctly so that all Electric headers can be read by the client.`;
206
- super(msg);
207
- }
208
- };
209
-
210
247
  // src/constants.ts
211
248
  var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
212
249
  var SHAPE_HANDLE_HEADER = `electric-handle`;
@@ -306,7 +343,7 @@ function createFetchWithResponseHeadersCheck(fetchClient) {
306
343
  if (response.ok) {
307
344
  const headers = response.headers;
308
345
  const missingHeaders = [];
309
- const addMissingHeaders = (requiredHeaders) => requiredHeaders.filter((h) => !headers.has(h));
346
+ const addMissingHeaders = (requiredHeaders) => missingHeaders.push(...requiredHeaders.filter((h) => !headers.has(h)));
310
347
  addMissingHeaders(requiredElectricResponseHeaders);
311
348
  const input = args[0];
312
349
  const urlString = input.toString();
@@ -423,14 +460,14 @@ var RESERVED_PARAMS = /* @__PURE__ */ new Set([
423
460
  WHERE_QUERY_PARAM,
424
461
  REPLICA_PARAM
425
462
  ]);
426
- var _fetchClient2, _messageParser, _subscribers, _upToDateSubscribers, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _databaseId, _schema, _error, _replica, _ShapeStream_instances, publish_fn, sendErrorToSubscribers_fn, notifyUpToDateSubscribers_fn, sendErrorToUpToDateSubscribers_fn, reset_fn;
463
+ var _error, _fetchClient2, _messageParser, _subscribers, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _databaseId, _schema, _onError, _replica, _ShapeStream_instances, start_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn;
427
464
  var _ShapeStream = class _ShapeStream {
428
465
  constructor(options) {
429
466
  __privateAdd(this, _ShapeStream_instances);
467
+ __privateAdd(this, _error, null);
430
468
  __privateAdd(this, _fetchClient2);
431
469
  __privateAdd(this, _messageParser);
432
470
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
433
- __privateAdd(this, _upToDateSubscribers, /* @__PURE__ */ new Map());
434
471
  __privateAdd(this, _lastOffset);
435
472
  __privateAdd(this, _liveCacheBuster);
436
473
  // Seconds since our Electric Epoch 😎
@@ -441,17 +478,18 @@ var _ShapeStream = class _ShapeStream {
441
478
  __privateAdd(this, _shapeHandle);
442
479
  __privateAdd(this, _databaseId);
443
480
  __privateAdd(this, _schema);
444
- __privateAdd(this, _error);
481
+ __privateAdd(this, _onError);
445
482
  __privateAdd(this, _replica);
446
483
  var _a, _b, _c;
447
- validateOptions(options);
448
484
  this.options = __spreadValues({ subscribe: true }, options);
485
+ validateOptions(this.options);
449
486
  __privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
450
487
  __privateSet(this, _liveCacheBuster, ``);
451
- __privateSet(this, _shapeHandle, this.options.shapeHandle);
488
+ __privateSet(this, _shapeHandle, this.options.handle);
452
489
  __privateSet(this, _databaseId, this.options.databaseId);
453
490
  __privateSet(this, _messageParser, new MessageParser(options.parser));
454
491
  __privateSet(this, _replica, this.options.replica);
492
+ __privateSet(this, _onError, this.options.onError);
455
493
  const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
456
494
  const fetchWithBackoffClient = createFetchWithBackoff(baseFetchClient, __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
457
495
  onFailedAttempt: () => {
@@ -463,129 +501,22 @@ var _ShapeStream = class _ShapeStream {
463
501
  __privateSet(this, _fetchClient2, createFetchWithResponseHeadersCheck(
464
502
  createFetchWithChunkBuffer(fetchWithBackoffClient)
465
503
  ));
466
- this.start();
504
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
467
505
  }
468
506
  get shapeHandle() {
469
507
  return __privateGet(this, _shapeHandle);
470
508
  }
509
+ get error() {
510
+ return __privateGet(this, _error);
511
+ }
471
512
  get isUpToDate() {
472
513
  return __privateGet(this, _isUpToDate);
473
514
  }
474
515
  get lastOffset() {
475
516
  return __privateGet(this, _lastOffset);
476
517
  }
477
- get error() {
478
- return __privateGet(this, _error);
479
- }
480
- async start() {
481
- var _a, _b;
482
- __privateSet(this, _isUpToDate, false);
483
- const { url, table, where, columns, signal } = this.options;
484
- try {
485
- while (!(signal == null ? void 0 : signal.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
486
- const fetchUrl = new URL(url);
487
- if (this.options.params) {
488
- const reservedParams = Object.keys(this.options.params).filter(
489
- (key) => RESERVED_PARAMS.has(key)
490
- );
491
- if (reservedParams.length > 0) {
492
- throw new Error(
493
- `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
494
- );
495
- }
496
- for (const [key, value] of Object.entries(this.options.params)) {
497
- fetchUrl.searchParams.set(key, value);
498
- }
499
- }
500
- if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table);
501
- if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
502
- if (columns && columns.length > 0)
503
- fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`));
504
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
505
- if (__privateGet(this, _isUpToDate)) {
506
- fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
507
- fetchUrl.searchParams.set(
508
- LIVE_CACHE_BUSTER_QUERY_PARAM,
509
- __privateGet(this, _liveCacheBuster)
510
- );
511
- }
512
- if (__privateGet(this, _shapeHandle)) {
513
- fetchUrl.searchParams.set(
514
- SHAPE_HANDLE_QUERY_PARAM,
515
- __privateGet(this, _shapeHandle)
516
- );
517
- }
518
- if (__privateGet(this, _databaseId)) {
519
- fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, __privateGet(this, _databaseId));
520
- }
521
- if (((_a = __privateGet(this, _replica)) != null ? _a : _ShapeStream.Replica.DEFAULT) != _ShapeStream.Replica.DEFAULT) {
522
- fetchUrl.searchParams.set(REPLICA_PARAM, __privateGet(this, _replica));
523
- }
524
- let response;
525
- try {
526
- response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
527
- signal,
528
- headers: this.options.headers
529
- });
530
- __privateSet(this, _connected, true);
531
- } catch (e) {
532
- if (e instanceof FetchBackoffAbortError) break;
533
- if (e instanceof MissingHeadersError) throw e;
534
- if (!(e instanceof FetchError)) throw e;
535
- if (e.status == 409) {
536
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
537
- __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
538
- await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
539
- continue;
540
- } else if (e.status >= 400 && e.status < 500) {
541
- __privateMethod(this, _ShapeStream_instances, sendErrorToUpToDateSubscribers_fn).call(this, e);
542
- __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
543
- throw e;
544
- }
545
- }
546
- const { headers, status } = response;
547
- const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
548
- if (shapeHandle) {
549
- __privateSet(this, _shapeHandle, shapeHandle);
550
- }
551
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
552
- if (lastOffset) {
553
- __privateSet(this, _lastOffset, lastOffset);
554
- }
555
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
556
- if (liveCacheBuster) {
557
- __privateSet(this, _liveCacheBuster, liveCacheBuster);
558
- }
559
- const getSchema = () => {
560
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
561
- return schemaHeader ? JSON.parse(schemaHeader) : {};
562
- };
563
- __privateSet(this, _schema, (_b = __privateGet(this, _schema)) != null ? _b : getSchema());
564
- const messages = status === 204 ? `[]` : await response.text();
565
- if (status === 204) {
566
- __privateSet(this, _lastSyncedAt, Date.now());
567
- }
568
- const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
569
- if (batch.length > 0) {
570
- const prevUpToDate = __privateGet(this, _isUpToDate);
571
- const lastMessage = batch[batch.length - 1];
572
- if (isUpToDateMessage(lastMessage)) {
573
- __privateSet(this, _lastSyncedAt, Date.now());
574
- __privateSet(this, _isUpToDate, true);
575
- }
576
- await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
577
- if (!prevUpToDate && __privateGet(this, _isUpToDate)) {
578
- __privateMethod(this, _ShapeStream_instances, notifyUpToDateSubscribers_fn).call(this);
579
- }
580
- }
581
- }
582
- } catch (err) {
583
- __privateSet(this, _error, err);
584
- } finally {
585
- __privateSet(this, _connected, false);
586
- }
587
- }
588
- subscribe(callback, onError) {
518
+ subscribe(callback, onError = () => {
519
+ }) {
589
520
  const subscriptionId = Math.random();
590
521
  __privateGet(this, _subscribers).set(subscriptionId, [callback, onError]);
591
522
  return () => {
@@ -595,16 +526,6 @@ var _ShapeStream = class _ShapeStream {
595
526
  unsubscribeAll() {
596
527
  __privateGet(this, _subscribers).clear();
597
528
  }
598
- subscribeOnceToUpToDate(callback, error) {
599
- const subscriptionId = Math.random();
600
- __privateGet(this, _upToDateSubscribers).set(subscriptionId, [callback, error]);
601
- return () => {
602
- __privateGet(this, _upToDateSubscribers).delete(subscriptionId);
603
- };
604
- }
605
- unsubscribeAllUpToDateSubscribers() {
606
- __privateGet(this, _upToDateSubscribers).clear();
607
- }
608
529
  /** Unix time at which we last synced. Undefined when `isLoading` is true. */
609
530
  lastSyncedAt() {
610
531
  return __privateGet(this, _lastSyncedAt);
@@ -620,13 +541,13 @@ var _ShapeStream = class _ShapeStream {
620
541
  }
621
542
  /** True during initial fetch. False afterwise. */
622
543
  isLoading() {
623
- return !this.isUpToDate;
544
+ return !__privateGet(this, _isUpToDate);
624
545
  }
625
546
  };
547
+ _error = new WeakMap();
626
548
  _fetchClient2 = new WeakMap();
627
549
  _messageParser = new WeakMap();
628
550
  _subscribers = new WeakMap();
629
- _upToDateSubscribers = new WeakMap();
630
551
  _lastOffset = new WeakMap();
631
552
  _liveCacheBuster = new WeakMap();
632
553
  _lastSyncedAt = new WeakMap();
@@ -635,9 +556,125 @@ _connected = new WeakMap();
635
556
  _shapeHandle = new WeakMap();
636
557
  _databaseId = new WeakMap();
637
558
  _schema = new WeakMap();
638
- _error = new WeakMap();
559
+ _onError = new WeakMap();
639
560
  _replica = new WeakMap();
640
561
  _ShapeStream_instances = new WeakSet();
562
+ start_fn = async function() {
563
+ var _a, _b, _c;
564
+ try {
565
+ while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
566
+ const { url, table, where, columns, signal } = this.options;
567
+ const fetchUrl = new URL(url);
568
+ if (this.options.params) {
569
+ const reservedParams = Object.keys(this.options.params).filter(
570
+ (key) => RESERVED_PARAMS.has(key)
571
+ );
572
+ if (reservedParams.length > 0) {
573
+ throw new Error(
574
+ `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
575
+ );
576
+ }
577
+ for (const [key, value] of Object.entries(this.options.params)) {
578
+ fetchUrl.searchParams.set(key, value);
579
+ }
580
+ }
581
+ if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table);
582
+ if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
583
+ if (columns && columns.length > 0)
584
+ fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`));
585
+ fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
586
+ if (__privateGet(this, _isUpToDate)) {
587
+ fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
588
+ fetchUrl.searchParams.set(
589
+ LIVE_CACHE_BUSTER_QUERY_PARAM,
590
+ __privateGet(this, _liveCacheBuster)
591
+ );
592
+ }
593
+ if (__privateGet(this, _shapeHandle)) {
594
+ fetchUrl.searchParams.set(
595
+ SHAPE_HANDLE_QUERY_PARAM,
596
+ __privateGet(this, _shapeHandle)
597
+ );
598
+ }
599
+ if (__privateGet(this, _databaseId)) {
600
+ fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, __privateGet(this, _databaseId));
601
+ }
602
+ if (((_b = __privateGet(this, _replica)) != null ? _b : _ShapeStream.Replica.DEFAULT) != _ShapeStream.Replica.DEFAULT) {
603
+ fetchUrl.searchParams.set(REPLICA_PARAM, __privateGet(this, _replica));
604
+ }
605
+ let response;
606
+ try {
607
+ response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
608
+ signal,
609
+ headers: this.options.headers
610
+ });
611
+ __privateSet(this, _connected, true);
612
+ } catch (e) {
613
+ if (e instanceof FetchBackoffAbortError) break;
614
+ if (!(e instanceof FetchError)) throw e;
615
+ if (e.status == 409) {
616
+ const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
617
+ __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
618
+ await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
619
+ continue;
620
+ } else if (e.status >= 400 && e.status < 500) {
621
+ __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
622
+ throw e;
623
+ }
624
+ }
625
+ const { headers, status } = response;
626
+ const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
627
+ if (shapeHandle) {
628
+ __privateSet(this, _shapeHandle, shapeHandle);
629
+ }
630
+ const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
631
+ if (lastOffset) {
632
+ __privateSet(this, _lastOffset, lastOffset);
633
+ }
634
+ const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
635
+ if (liveCacheBuster) {
636
+ __privateSet(this, _liveCacheBuster, liveCacheBuster);
637
+ }
638
+ const getSchema = () => {
639
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
640
+ return schemaHeader ? JSON.parse(schemaHeader) : {};
641
+ };
642
+ __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
643
+ const messages = status === 204 ? `[]` : await response.text();
644
+ if (status === 204) {
645
+ __privateSet(this, _lastSyncedAt, Date.now());
646
+ }
647
+ const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
648
+ if (batch.length > 0) {
649
+ const lastMessage = batch[batch.length - 1];
650
+ if (isUpToDateMessage(lastMessage)) {
651
+ __privateSet(this, _lastSyncedAt, Date.now());
652
+ __privateSet(this, _isUpToDate, true);
653
+ }
654
+ await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
655
+ }
656
+ }
657
+ } catch (err) {
658
+ __privateSet(this, _error, err);
659
+ if (__privateGet(this, _onError)) {
660
+ const retryOpts = await __privateGet(this, _onError).call(this, err);
661
+ if (typeof retryOpts === `object`) {
662
+ __privateMethod(this, _ShapeStream_instances, reset_fn).call(this);
663
+ if (`params` in retryOpts) {
664
+ this.options.params = retryOpts.params;
665
+ }
666
+ if (`headers` in retryOpts) {
667
+ this.options.headers = retryOpts.headers;
668
+ }
669
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
670
+ }
671
+ return;
672
+ }
673
+ throw err;
674
+ } finally {
675
+ __privateSet(this, _connected, false);
676
+ }
677
+ };
641
678
  publish_fn = async function(messages) {
642
679
  await Promise.all(
643
680
  Array.from(__privateGet(this, _subscribers).values()).map(async ([callback, __]) => {
@@ -656,24 +693,14 @@ sendErrorToSubscribers_fn = function(error) {
656
693
  errorFn == null ? void 0 : errorFn(error);
657
694
  });
658
695
  };
659
- notifyUpToDateSubscribers_fn = function() {
660
- __privateGet(this, _upToDateSubscribers).forEach(([callback]) => {
661
- callback();
662
- });
663
- };
664
- sendErrorToUpToDateSubscribers_fn = function(error) {
665
- __privateGet(this, _upToDateSubscribers).forEach(
666
- ([_, errorCallback]) => errorCallback(error)
667
- );
668
- };
669
696
  /**
670
697
  * Resets the state of the stream, optionally with a provided
671
698
  * shape handle
672
699
  */
673
- reset_fn = function(shapeHandle) {
700
+ reset_fn = function(handle) {
674
701
  __privateSet(this, _lastOffset, `-1`);
675
702
  __privateSet(this, _liveCacheBuster, ``);
676
- __privateSet(this, _shapeHandle, shapeHandle);
703
+ __privateSet(this, _shapeHandle, handle);
677
704
  __privateSet(this, _isUpToDate, false);
678
705
  __privateSet(this, _connected, false);
679
706
  __privateSet(this, _schema, void 0);
@@ -685,26 +712,20 @@ _ShapeStream.Replica = {
685
712
  var ShapeStream = _ShapeStream;
686
713
  function validateOptions(options) {
687
714
  if (!options.url) {
688
- throw new Error(`Invalid shape options. It must provide the url`);
715
+ throw new MissingShapeUrlError();
689
716
  }
690
717
  if (options.signal && !(options.signal instanceof AbortSignal)) {
691
- throw new Error(
692
- `Invalid signal option. It must be an instance of AbortSignal.`
693
- );
718
+ throw new InvalidSignalError();
694
719
  }
695
- if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeHandle) {
696
- throw new Error(
697
- `shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`
698
- );
720
+ if (options.offset !== void 0 && options.offset !== `-1` && !options.handle) {
721
+ throw new MissingShapeHandleError();
699
722
  }
700
723
  if (options.params) {
701
724
  const reservedParams = Object.keys(options.params).filter(
702
725
  (key) => RESERVED_PARAMS.has(key)
703
726
  );
704
727
  if (reservedParams.length > 0) {
705
- throw new Error(
706
- `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
707
- );
728
+ throw new ReservedParamError(reservedParams);
708
729
  }
709
730
  }
710
731
  return;
@@ -725,15 +746,6 @@ var Shape = class {
725
746
  __privateMethod(this, _Shape_instances, process_fn).bind(this),
726
747
  __privateMethod(this, _Shape_instances, handleError_fn).bind(this)
727
748
  );
728
- const unsubscribe = __privateGet(this, _stream).subscribeOnceToUpToDate(
729
- () => {
730
- unsubscribe();
731
- },
732
- (e) => {
733
- __privateMethod(this, _Shape_instances, handleError_fn).call(this, e);
734
- throw e;
735
- }
736
- );
737
749
  }
738
750
  get isUpToDate() {
739
751
  return __privateGet(this, _stream).isUpToDate;
@@ -741,6 +753,9 @@ var Shape = class {
741
753
  get lastOffset() {
742
754
  return __privateGet(this, _stream).lastOffset;
743
755
  }
756
+ get handle() {
757
+ return __privateGet(this, _stream).shapeHandle;
758
+ }
744
759
  get rows() {
745
760
  return this.value.then((v) => Array.from(v.values()));
746
761
  }