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