@electric-sql/client 0.7.2 → 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,41 +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
-
219
269
  // src/constants.ts
220
270
  var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
221
271
  var SHAPE_HANDLE_HEADER = `electric-handle`;
@@ -303,6 +353,36 @@ function createFetchWithChunkBuffer(fetchClient, prefetchOptions = ChunkPrefetch
303
353
  });
304
354
  return prefetchClient;
305
355
  }
356
+ var requiredElectricResponseHeaders = [
357
+ `electric-offset`,
358
+ `electric-handle`
359
+ ];
360
+ var requiredLiveResponseHeaders = [`electric-cursor`];
361
+ var requiredNonLiveResponseHeaders = [`electric-schema`];
362
+ function createFetchWithResponseHeadersCheck(fetchClient) {
363
+ return (...args) => __async(this, null, function* () {
364
+ const response = yield fetchClient(...args);
365
+ if (response.ok) {
366
+ const headers = response.headers;
367
+ const missingHeaders = [];
368
+ const addMissingHeaders = (requiredHeaders) => missingHeaders.push(...requiredHeaders.filter((h) => !headers.has(h)));
369
+ addMissingHeaders(requiredElectricResponseHeaders);
370
+ const input = args[0];
371
+ const urlString = input.toString();
372
+ const url = new URL(urlString);
373
+ if (url.searchParams.has(LIVE_QUERY_PARAM, `true`)) {
374
+ addMissingHeaders(requiredLiveResponseHeaders);
375
+ }
376
+ if (!url.searchParams.has(LIVE_QUERY_PARAM) || url.searchParams.has(LIVE_QUERY_PARAM, `false`)) {
377
+ addMissingHeaders(requiredNonLiveResponseHeaders);
378
+ }
379
+ if (missingHeaders.length > 0) {
380
+ throw new MissingHeadersError(urlString, missingHeaders);
381
+ }
382
+ }
383
+ return response;
384
+ });
385
+ }
306
386
  var _fetchClient, _maxPrefetchedRequests, _prefetchQueue, _queueHeadUrl, _queueTailUrl, _PrefetchQueue_instances, prefetch_fn;
307
387
  var PrefetchQueue = class {
308
388
  constructor(options) {
@@ -402,14 +482,14 @@ var RESERVED_PARAMS = /* @__PURE__ */ new Set([
402
482
  WHERE_QUERY_PARAM,
403
483
  REPLICA_PARAM
404
484
  ]);
405
- 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;
406
486
  var _ShapeStream = class _ShapeStream {
407
487
  constructor(options) {
408
488
  __privateAdd(this, _ShapeStream_instances);
489
+ __privateAdd(this, _error, null);
409
490
  __privateAdd(this, _fetchClient2);
410
491
  __privateAdd(this, _messageParser);
411
492
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
412
- __privateAdd(this, _upToDateSubscribers, /* @__PURE__ */ new Map());
413
493
  __privateAdd(this, _lastOffset);
414
494
  __privateAdd(this, _liveCacheBuster);
415
495
  // Seconds since our Electric Epoch 😎
@@ -420,17 +500,18 @@ var _ShapeStream = class _ShapeStream {
420
500
  __privateAdd(this, _shapeHandle);
421
501
  __privateAdd(this, _databaseId);
422
502
  __privateAdd(this, _schema);
423
- __privateAdd(this, _error);
503
+ __privateAdd(this, _onError);
424
504
  __privateAdd(this, _replica);
425
505
  var _a, _b, _c;
426
- validateOptions(options);
427
506
  this.options = __spreadValues({ subscribe: true }, options);
507
+ validateOptions(this.options);
428
508
  __privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
429
509
  __privateSet(this, _liveCacheBuster, ``);
430
- __privateSet(this, _shapeHandle, this.options.shapeHandle);
510
+ __privateSet(this, _shapeHandle, this.options.handle);
431
511
  __privateSet(this, _databaseId, this.options.databaseId);
432
512
  __privateSet(this, _messageParser, new MessageParser(options.parser));
433
513
  __privateSet(this, _replica, this.options.replica);
514
+ __privateSet(this, _onError, this.options.onError);
434
515
  const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
435
516
  const fetchWithBackoffClient = createFetchWithBackoff(baseFetchClient, __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
436
517
  onFailedAttempt: () => {
@@ -439,128 +520,25 @@ var _ShapeStream = class _ShapeStream {
439
520
  (_b2 = (_a2 = options.backoffOptions) == null ? void 0 : _a2.onFailedAttempt) == null ? void 0 : _b2.call(_a2);
440
521
  }
441
522
  }));
442
- __privateSet(this, _fetchClient2, createFetchWithChunkBuffer(fetchWithBackoffClient));
443
- this.start();
523
+ __privateSet(this, _fetchClient2, createFetchWithResponseHeadersCheck(
524
+ createFetchWithChunkBuffer(fetchWithBackoffClient)
525
+ ));
526
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
444
527
  }
445
528
  get shapeHandle() {
446
529
  return __privateGet(this, _shapeHandle);
447
530
  }
448
- get isUpToDate() {
449
- return __privateGet(this, _isUpToDate);
450
- }
451
531
  get error() {
452
532
  return __privateGet(this, _error);
453
533
  }
454
- start() {
455
- return __async(this, null, function* () {
456
- var _a, _b;
457
- __privateSet(this, _isUpToDate, false);
458
- const { url, table, where, columns, signal } = this.options;
459
- try {
460
- while (!(signal == null ? void 0 : signal.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
461
- const fetchUrl = new URL(url);
462
- if (this.options.params) {
463
- const reservedParams = Object.keys(this.options.params).filter(
464
- (key) => RESERVED_PARAMS.has(key)
465
- );
466
- if (reservedParams.length > 0) {
467
- throw new Error(
468
- `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
469
- );
470
- }
471
- for (const [key, value] of Object.entries(this.options.params)) {
472
- fetchUrl.searchParams.set(key, value);
473
- }
474
- }
475
- if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table);
476
- if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
477
- if (columns && columns.length > 0)
478
- fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`));
479
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
480
- if (__privateGet(this, _isUpToDate)) {
481
- fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
482
- fetchUrl.searchParams.set(
483
- LIVE_CACHE_BUSTER_QUERY_PARAM,
484
- __privateGet(this, _liveCacheBuster)
485
- );
486
- }
487
- if (__privateGet(this, _shapeHandle)) {
488
- fetchUrl.searchParams.set(
489
- SHAPE_HANDLE_QUERY_PARAM,
490
- __privateGet(this, _shapeHandle)
491
- );
492
- }
493
- if (__privateGet(this, _databaseId)) {
494
- fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, __privateGet(this, _databaseId));
495
- }
496
- if (((_a = __privateGet(this, _replica)) != null ? _a : _ShapeStream.Replica.DEFAULT) != _ShapeStream.Replica.DEFAULT) {
497
- fetchUrl.searchParams.set(REPLICA_PARAM, __privateGet(this, _replica));
498
- }
499
- let response;
500
- try {
501
- response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
502
- signal,
503
- headers: this.options.headers
504
- });
505
- __privateSet(this, _connected, true);
506
- } catch (e) {
507
- if (e instanceof FetchBackoffAbortError) break;
508
- if (!(e instanceof FetchError)) throw e;
509
- if (e.status == 409) {
510
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
511
- __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
512
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
513
- continue;
514
- } else if (e.status >= 400 && e.status < 500) {
515
- __privateMethod(this, _ShapeStream_instances, sendErrorToUpToDateSubscribers_fn).call(this, e);
516
- __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
517
- throw e;
518
- }
519
- }
520
- const { headers, status } = response;
521
- const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
522
- if (shapeHandle) {
523
- __privateSet(this, _shapeHandle, shapeHandle);
524
- }
525
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
526
- if (lastOffset) {
527
- __privateSet(this, _lastOffset, lastOffset);
528
- }
529
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
530
- if (liveCacheBuster) {
531
- __privateSet(this, _liveCacheBuster, liveCacheBuster);
532
- }
533
- const getSchema = () => {
534
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
535
- return schemaHeader ? JSON.parse(schemaHeader) : {};
536
- };
537
- __privateSet(this, _schema, (_b = __privateGet(this, _schema)) != null ? _b : getSchema());
538
- const messages = status === 204 ? `[]` : yield response.text();
539
- if (status === 204) {
540
- __privateSet(this, _lastSyncedAt, Date.now());
541
- }
542
- const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
543
- if (batch.length > 0) {
544
- const prevUpToDate = __privateGet(this, _isUpToDate);
545
- const lastMessage = batch[batch.length - 1];
546
- if (isUpToDateMessage(lastMessage)) {
547
- __privateSet(this, _lastSyncedAt, Date.now());
548
- __privateSet(this, _isUpToDate, true);
549
- }
550
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
551
- if (!prevUpToDate && __privateGet(this, _isUpToDate)) {
552
- __privateMethod(this, _ShapeStream_instances, notifyUpToDateSubscribers_fn).call(this);
553
- }
554
- }
555
- }
556
- } catch (err) {
557
- __privateSet(this, _error, err);
558
- } finally {
559
- __privateSet(this, _connected, false);
560
- }
561
- });
534
+ get isUpToDate() {
535
+ return __privateGet(this, _isUpToDate);
536
+ }
537
+ get lastOffset() {
538
+ return __privateGet(this, _lastOffset);
562
539
  }
563
- subscribe(callback, onError) {
540
+ subscribe(callback, onError = () => {
541
+ }) {
564
542
  const subscriptionId = Math.random();
565
543
  __privateGet(this, _subscribers).set(subscriptionId, [callback, onError]);
566
544
  return () => {
@@ -570,16 +548,6 @@ var _ShapeStream = class _ShapeStream {
570
548
  unsubscribeAll() {
571
549
  __privateGet(this, _subscribers).clear();
572
550
  }
573
- subscribeOnceToUpToDate(callback, error) {
574
- const subscriptionId = Math.random();
575
- __privateGet(this, _upToDateSubscribers).set(subscriptionId, [callback, error]);
576
- return () => {
577
- __privateGet(this, _upToDateSubscribers).delete(subscriptionId);
578
- };
579
- }
580
- unsubscribeAllUpToDateSubscribers() {
581
- __privateGet(this, _upToDateSubscribers).clear();
582
- }
583
551
  /** Unix time at which we last synced. Undefined when `isLoading` is true. */
584
552
  lastSyncedAt() {
585
553
  return __privateGet(this, _lastSyncedAt);
@@ -595,13 +563,13 @@ var _ShapeStream = class _ShapeStream {
595
563
  }
596
564
  /** True during initial fetch. False afterwise. */
597
565
  isLoading() {
598
- return !this.isUpToDate;
566
+ return !__privateGet(this, _isUpToDate);
599
567
  }
600
568
  };
569
+ _error = new WeakMap();
601
570
  _fetchClient2 = new WeakMap();
602
571
  _messageParser = new WeakMap();
603
572
  _subscribers = new WeakMap();
604
- _upToDateSubscribers = new WeakMap();
605
573
  _lastOffset = new WeakMap();
606
574
  _liveCacheBuster = new WeakMap();
607
575
  _lastSyncedAt = new WeakMap();
@@ -610,9 +578,127 @@ _connected = new WeakMap();
610
578
  _shapeHandle = new WeakMap();
611
579
  _databaseId = new WeakMap();
612
580
  _schema = new WeakMap();
613
- _error = new WeakMap();
581
+ _onError = new WeakMap();
614
582
  _replica = new WeakMap();
615
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
+ };
616
702
  publish_fn = function(messages) {
617
703
  return __async(this, null, function* () {
618
704
  yield Promise.all(
@@ -633,24 +719,14 @@ sendErrorToSubscribers_fn = function(error) {
633
719
  errorFn == null ? void 0 : errorFn(error);
634
720
  });
635
721
  };
636
- notifyUpToDateSubscribers_fn = function() {
637
- __privateGet(this, _upToDateSubscribers).forEach(([callback]) => {
638
- callback();
639
- });
640
- };
641
- sendErrorToUpToDateSubscribers_fn = function(error) {
642
- __privateGet(this, _upToDateSubscribers).forEach(
643
- ([_, errorCallback]) => errorCallback(error)
644
- );
645
- };
646
722
  /**
647
723
  * Resets the state of the stream, optionally with a provided
648
724
  * shape handle
649
725
  */
650
- reset_fn = function(shapeHandle) {
726
+ reset_fn = function(handle) {
651
727
  __privateSet(this, _lastOffset, `-1`);
652
728
  __privateSet(this, _liveCacheBuster, ``);
653
- __privateSet(this, _shapeHandle, shapeHandle);
729
+ __privateSet(this, _shapeHandle, handle);
654
730
  __privateSet(this, _isUpToDate, false);
655
731
  __privateSet(this, _connected, false);
656
732
  __privateSet(this, _schema, void 0);
@@ -662,17 +738,21 @@ _ShapeStream.Replica = {
662
738
  var ShapeStream = _ShapeStream;
663
739
  function validateOptions(options) {
664
740
  if (!options.url) {
665
- throw new Error(`Invalid shape options. It must provide the url`);
741
+ throw new MissingShapeUrlError();
666
742
  }
667
743
  if (options.signal && !(options.signal instanceof AbortSignal)) {
668
- throw new Error(
669
- `Invalid signal option. It must be an instance of AbortSignal.`
670
- );
744
+ throw new InvalidSignalError();
671
745
  }
672
- if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeHandle) {
673
- throw new Error(
674
- `shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`
746
+ if (options.offset !== void 0 && options.offset !== `-1` && !options.handle) {
747
+ throw new MissingShapeHandleError();
748
+ }
749
+ if (options.params) {
750
+ const reservedParams = Object.keys(options.params).filter(
751
+ (key) => RESERVED_PARAMS.has(key)
675
752
  );
753
+ if (reservedParams.length > 0) {
754
+ throw new ReservedParamError(reservedParams);
755
+ }
676
756
  }
677
757
  return;
678
758
  }
@@ -692,19 +772,16 @@ var Shape = class {
692
772
  __privateMethod(this, _Shape_instances, process_fn).bind(this),
693
773
  __privateMethod(this, _Shape_instances, handleError_fn).bind(this)
694
774
  );
695
- const unsubscribe = __privateGet(this, _stream).subscribeOnceToUpToDate(
696
- () => {
697
- unsubscribe();
698
- },
699
- (e) => {
700
- __privateMethod(this, _Shape_instances, handleError_fn).call(this, e);
701
- throw e;
702
- }
703
- );
704
775
  }
705
776
  get isUpToDate() {
706
777
  return __privateGet(this, _stream).isUpToDate;
707
778
  }
779
+ get lastOffset() {
780
+ return __privateGet(this, _stream).lastOffset;
781
+ }
782
+ get handle() {
783
+ return __privateGet(this, _stream).shapeHandle;
784
+ }
708
785
  get rows() {
709
786
  return this.value.then((v) => Array.from(v.values()));
710
787
  }