@electric-sql/client 0.7.3 → 0.9.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.
@@ -85,6 +85,91 @@ __export(src_exports, {
85
85
  });
86
86
  module.exports = __toCommonJS(src_exports);
87
87
 
88
+ // src/error.ts
89
+ var FetchError = class _FetchError extends Error {
90
+ constructor(status, text, json, headers, url, message) {
91
+ super(
92
+ message || `HTTP Error ${status} at ${url}: ${text != null ? text : JSON.stringify(json)}`
93
+ );
94
+ this.url = url;
95
+ this.name = `FetchError`;
96
+ this.status = status;
97
+ this.text = text;
98
+ this.json = json;
99
+ this.headers = headers;
100
+ }
101
+ static fromResponse(response, url) {
102
+ return __async(this, null, function* () {
103
+ const status = response.status;
104
+ const headers = Object.fromEntries([...response.headers.entries()]);
105
+ let text = void 0;
106
+ let json = void 0;
107
+ const contentType = response.headers.get(`content-type`);
108
+ if (contentType && contentType.includes(`application/json`)) {
109
+ json = yield response.json();
110
+ } else {
111
+ text = yield response.text();
112
+ }
113
+ return new _FetchError(status, text, json, headers, url);
114
+ });
115
+ }
116
+ };
117
+ var FetchBackoffAbortError = class extends Error {
118
+ constructor() {
119
+ super(`Fetch with backoff aborted`);
120
+ this.name = `FetchBackoffAbortError`;
121
+ }
122
+ };
123
+ var MissingShapeUrlError = class extends Error {
124
+ constructor() {
125
+ super(`Invalid shape options: missing required url parameter`);
126
+ this.name = `MissingShapeUrlError`;
127
+ }
128
+ };
129
+ var InvalidSignalError = class extends Error {
130
+ constructor() {
131
+ super(`Invalid signal option. It must be an instance of AbortSignal.`);
132
+ this.name = `InvalidSignalError`;
133
+ }
134
+ };
135
+ var MissingShapeHandleError = class extends Error {
136
+ constructor() {
137
+ super(
138
+ `shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`
139
+ );
140
+ this.name = `MissingShapeHandleError`;
141
+ }
142
+ };
143
+ var ReservedParamError = class extends Error {
144
+ constructor(reservedParams) {
145
+ super(
146
+ `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
147
+ );
148
+ this.name = `ReservedParamError`;
149
+ }
150
+ };
151
+ var ParserNullValueError = class extends Error {
152
+ constructor(columnName) {
153
+ super(`Column "${columnName != null ? columnName : `unknown`}" does not allow NULL values`);
154
+ this.name = `ParserNullValueError`;
155
+ }
156
+ };
157
+ var MissingHeadersError = class extends Error {
158
+ constructor(url, missingHeaders) {
159
+ let msg = `The response for the shape request to ${url} didn't include the following required headers:
160
+ `;
161
+ missingHeaders.forEach((h) => {
162
+ msg += `- ${h}
163
+ `;
164
+ });
165
+ msg += `
166
+ This is often due to a proxy not setting CORS correctly so that all Electric headers can be read by the client.`;
167
+ msg += `
168
+ For more information visit the troubleshooting guide: /docs/guides/troubleshooting/missing-headers`;
169
+ super(msg);
170
+ }
171
+ };
172
+
88
173
  // src/parser.ts
89
174
  var parseNumber = (value) => Number(value);
90
175
  var parseBool = (value) => value === `true` || value === `t`;
@@ -186,7 +271,7 @@ function makeNullableParser(parser, columnInfo, columnName) {
186
271
  return (value) => {
187
272
  if (isPgNull(value)) {
188
273
  if (!isNullable) {
189
- throw new Error(`Column ${columnName != null ? columnName : `unknown`} is not nullable`);
274
+ throw new ParserNullValueError(columnName != null ? columnName : `unknown`);
190
275
  }
191
276
  return null;
192
277
  }
@@ -208,61 +293,12 @@ function isUpToDateMessage(message) {
208
293
  return isControlMessage(message) && message.headers.control === `up-to-date`;
209
294
  }
210
295
 
211
- // src/error.ts
212
- var FetchError = class _FetchError extends Error {
213
- constructor(status, text, json, headers, url, message) {
214
- super(
215
- message || `HTTP Error ${status} at ${url}: ${text != null ? text : JSON.stringify(json)}`
216
- );
217
- this.url = url;
218
- this.name = `FetchError`;
219
- this.status = status;
220
- this.text = text;
221
- this.json = json;
222
- this.headers = headers;
223
- }
224
- static fromResponse(response, url) {
225
- return __async(this, null, function* () {
226
- const status = response.status;
227
- const headers = Object.fromEntries([...response.headers.entries()]);
228
- let text = void 0;
229
- let json = void 0;
230
- const contentType = response.headers.get(`content-type`);
231
- if (contentType && contentType.includes(`application/json`)) {
232
- json = yield response.json();
233
- } else {
234
- text = yield response.text();
235
- }
236
- return new _FetchError(status, text, json, headers, url);
237
- });
238
- }
239
- };
240
- var FetchBackoffAbortError = class extends Error {
241
- constructor() {
242
- super(`Fetch with backoff aborted`);
243
- }
244
- };
245
- var MissingHeadersError = class extends Error {
246
- constructor(url, missingHeaders) {
247
- let msg = `The response for the shape request to ${url} didn't include the following required headers:
248
- `;
249
- missingHeaders.forEach((h) => {
250
- msg += `- ${h}
251
- `;
252
- });
253
- msg += `
254
- This is often due to a proxy not setting CORS correctly so that all Electric headers can be read by the client.`;
255
- super(msg);
256
- }
257
- };
258
-
259
296
  // src/constants.ts
260
297
  var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
261
298
  var SHAPE_HANDLE_HEADER = `electric-handle`;
262
299
  var CHUNK_LAST_OFFSET_HEADER = `electric-offset`;
263
300
  var SHAPE_SCHEMA_HEADER = `electric-schema`;
264
301
  var CHUNK_UP_TO_DATE_HEADER = `electric-up-to-date`;
265
- var DATABASE_ID_QUERY_PARAM = `database_id`;
266
302
  var COLUMNS_QUERY_PARAM = `columns`;
267
303
  var LIVE_CACHE_BUSTER_QUERY_PARAM = `cursor`;
268
304
  var SHAPE_HANDLE_QUERY_PARAM = `handle`;
@@ -355,7 +391,7 @@ function createFetchWithResponseHeadersCheck(fetchClient) {
355
391
  if (response.ok) {
356
392
  const headers = response.headers;
357
393
  const missingHeaders = [];
358
- const addMissingHeaders = (requiredHeaders) => requiredHeaders.filter((h) => !headers.has(h));
394
+ const addMissingHeaders = (requiredHeaders) => missingHeaders.push(...requiredHeaders.filter((h) => !headers.has(h)));
359
395
  addMissingHeaders(requiredElectricResponseHeaders);
360
396
  const input = args[0];
361
397
  const urlString = input.toString();
@@ -448,6 +484,7 @@ function getNextChunkUrl(url, res) {
448
484
  if (nextUrl.searchParams.has(LIVE_QUERY_PARAM)) return;
449
485
  nextUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, shapeHandle);
450
486
  nextUrl.searchParams.set(OFFSET_QUERY_PARAM, lastOffset);
487
+ nextUrl.searchParams.sort();
451
488
  return nextUrl.toString();
452
489
  }
453
490
  function chainAborter(aborter, sourceSignal) {
@@ -462,24 +499,26 @@ function chainAborter(aborter, sourceSignal) {
462
499
 
463
500
  // src/client.ts
464
501
  var RESERVED_PARAMS = /* @__PURE__ */ new Set([
465
- DATABASE_ID_QUERY_PARAM,
466
- COLUMNS_QUERY_PARAM,
467
502
  LIVE_CACHE_BUSTER_QUERY_PARAM,
468
503
  SHAPE_HANDLE_QUERY_PARAM,
469
504
  LIVE_QUERY_PARAM,
470
- OFFSET_QUERY_PARAM,
471
- TABLE_QUERY_PARAM,
472
- WHERE_QUERY_PARAM,
473
- REPLICA_PARAM
505
+ OFFSET_QUERY_PARAM
474
506
  ]);
475
- 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;
476
- var _ShapeStream = class _ShapeStream {
507
+ function toInternalParams(params) {
508
+ const result = {};
509
+ for (const [key, value] of Object.entries(params)) {
510
+ result[key] = Array.isArray(value) ? value.join(`,`) : value;
511
+ }
512
+ return result;
513
+ }
514
+ var _error, _fetchClient2, _messageParser, _subscribers, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _ShapeStream_instances, start_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn;
515
+ var ShapeStream = class {
477
516
  constructor(options) {
478
517
  __privateAdd(this, _ShapeStream_instances);
518
+ __privateAdd(this, _error, null);
479
519
  __privateAdd(this, _fetchClient2);
480
520
  __privateAdd(this, _messageParser);
481
521
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
482
- __privateAdd(this, _upToDateSubscribers, /* @__PURE__ */ new Map());
483
522
  __privateAdd(this, _lastOffset);
484
523
  __privateAdd(this, _liveCacheBuster);
485
524
  // Seconds since our Electric Epoch 😎
@@ -488,19 +527,16 @@ var _ShapeStream = class _ShapeStream {
488
527
  __privateAdd(this, _isUpToDate, false);
489
528
  __privateAdd(this, _connected, false);
490
529
  __privateAdd(this, _shapeHandle);
491
- __privateAdd(this, _databaseId);
492
530
  __privateAdd(this, _schema);
493
- __privateAdd(this, _error);
494
- __privateAdd(this, _replica);
531
+ __privateAdd(this, _onError);
495
532
  var _a, _b, _c;
496
- validateOptions(options);
497
533
  this.options = __spreadValues({ subscribe: true }, options);
534
+ validateOptions(this.options);
498
535
  __privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
499
536
  __privateSet(this, _liveCacheBuster, ``);
500
- __privateSet(this, _shapeHandle, this.options.shapeHandle);
501
- __privateSet(this, _databaseId, this.options.databaseId);
537
+ __privateSet(this, _shapeHandle, this.options.handle);
502
538
  __privateSet(this, _messageParser, new MessageParser(options.parser));
503
- __privateSet(this, _replica, this.options.replica);
539
+ __privateSet(this, _onError, this.options.onError);
504
540
  const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
505
541
  const fetchWithBackoffClient = createFetchWithBackoff(baseFetchClient, __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
506
542
  onFailedAttempt: () => {
@@ -512,131 +548,22 @@ var _ShapeStream = class _ShapeStream {
512
548
  __privateSet(this, _fetchClient2, createFetchWithResponseHeadersCheck(
513
549
  createFetchWithChunkBuffer(fetchWithBackoffClient)
514
550
  ));
515
- this.start();
551
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
516
552
  }
517
553
  get shapeHandle() {
518
554
  return __privateGet(this, _shapeHandle);
519
555
  }
556
+ get error() {
557
+ return __privateGet(this, _error);
558
+ }
520
559
  get isUpToDate() {
521
560
  return __privateGet(this, _isUpToDate);
522
561
  }
523
562
  get lastOffset() {
524
563
  return __privateGet(this, _lastOffset);
525
564
  }
526
- get error() {
527
- return __privateGet(this, _error);
528
- }
529
- start() {
530
- return __async(this, null, function* () {
531
- var _a, _b;
532
- __privateSet(this, _isUpToDate, false);
533
- const { url, table, where, columns, signal } = this.options;
534
- try {
535
- while (!(signal == null ? void 0 : signal.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
536
- const fetchUrl = new URL(url);
537
- if (this.options.params) {
538
- const reservedParams = Object.keys(this.options.params).filter(
539
- (key) => RESERVED_PARAMS.has(key)
540
- );
541
- if (reservedParams.length > 0) {
542
- throw new Error(
543
- `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
544
- );
545
- }
546
- for (const [key, value] of Object.entries(this.options.params)) {
547
- fetchUrl.searchParams.set(key, value);
548
- }
549
- }
550
- if (table) fetchUrl.searchParams.set(TABLE_QUERY_PARAM, table);
551
- if (where) fetchUrl.searchParams.set(WHERE_QUERY_PARAM, where);
552
- if (columns && columns.length > 0)
553
- fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, columns.join(`,`));
554
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
555
- if (__privateGet(this, _isUpToDate)) {
556
- fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
557
- fetchUrl.searchParams.set(
558
- LIVE_CACHE_BUSTER_QUERY_PARAM,
559
- __privateGet(this, _liveCacheBuster)
560
- );
561
- }
562
- if (__privateGet(this, _shapeHandle)) {
563
- fetchUrl.searchParams.set(
564
- SHAPE_HANDLE_QUERY_PARAM,
565
- __privateGet(this, _shapeHandle)
566
- );
567
- }
568
- if (__privateGet(this, _databaseId)) {
569
- fetchUrl.searchParams.set(DATABASE_ID_QUERY_PARAM, __privateGet(this, _databaseId));
570
- }
571
- if (((_a = __privateGet(this, _replica)) != null ? _a : _ShapeStream.Replica.DEFAULT) != _ShapeStream.Replica.DEFAULT) {
572
- fetchUrl.searchParams.set(REPLICA_PARAM, __privateGet(this, _replica));
573
- }
574
- let response;
575
- try {
576
- response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
577
- signal,
578
- headers: this.options.headers
579
- });
580
- __privateSet(this, _connected, true);
581
- } catch (e) {
582
- if (e instanceof FetchBackoffAbortError) break;
583
- if (e instanceof MissingHeadersError) throw e;
584
- if (!(e instanceof FetchError)) throw e;
585
- if (e.status == 409) {
586
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
587
- __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
588
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
589
- continue;
590
- } else if (e.status >= 400 && e.status < 500) {
591
- __privateMethod(this, _ShapeStream_instances, sendErrorToUpToDateSubscribers_fn).call(this, e);
592
- __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
593
- throw e;
594
- }
595
- }
596
- const { headers, status } = response;
597
- const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
598
- if (shapeHandle) {
599
- __privateSet(this, _shapeHandle, shapeHandle);
600
- }
601
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
602
- if (lastOffset) {
603
- __privateSet(this, _lastOffset, lastOffset);
604
- }
605
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
606
- if (liveCacheBuster) {
607
- __privateSet(this, _liveCacheBuster, liveCacheBuster);
608
- }
609
- const getSchema = () => {
610
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
611
- return schemaHeader ? JSON.parse(schemaHeader) : {};
612
- };
613
- __privateSet(this, _schema, (_b = __privateGet(this, _schema)) != null ? _b : getSchema());
614
- const messages = status === 204 ? `[]` : yield response.text();
615
- if (status === 204) {
616
- __privateSet(this, _lastSyncedAt, Date.now());
617
- }
618
- const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
619
- if (batch.length > 0) {
620
- const prevUpToDate = __privateGet(this, _isUpToDate);
621
- const lastMessage = batch[batch.length - 1];
622
- if (isUpToDateMessage(lastMessage)) {
623
- __privateSet(this, _lastSyncedAt, Date.now());
624
- __privateSet(this, _isUpToDate, true);
625
- }
626
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
627
- if (!prevUpToDate && __privateGet(this, _isUpToDate)) {
628
- __privateMethod(this, _ShapeStream_instances, notifyUpToDateSubscribers_fn).call(this);
629
- }
630
- }
631
- }
632
- } catch (err) {
633
- __privateSet(this, _error, err);
634
- } finally {
635
- __privateSet(this, _connected, false);
636
- }
637
- });
638
- }
639
- subscribe(callback, onError) {
565
+ subscribe(callback, onError = () => {
566
+ }) {
640
567
  const subscriptionId = Math.random();
641
568
  __privateGet(this, _subscribers).set(subscriptionId, [callback, onError]);
642
569
  return () => {
@@ -646,16 +573,6 @@ var _ShapeStream = class _ShapeStream {
646
573
  unsubscribeAll() {
647
574
  __privateGet(this, _subscribers).clear();
648
575
  }
649
- subscribeOnceToUpToDate(callback, error) {
650
- const subscriptionId = Math.random();
651
- __privateGet(this, _upToDateSubscribers).set(subscriptionId, [callback, error]);
652
- return () => {
653
- __privateGet(this, _upToDateSubscribers).delete(subscriptionId);
654
- };
655
- }
656
- unsubscribeAllUpToDateSubscribers() {
657
- __privateGet(this, _upToDateSubscribers).clear();
658
- }
659
576
  /** Unix time at which we last synced. Undefined when `isLoading` is true. */
660
577
  lastSyncedAt() {
661
578
  return __privateGet(this, _lastSyncedAt);
@@ -671,24 +588,145 @@ var _ShapeStream = class _ShapeStream {
671
588
  }
672
589
  /** True during initial fetch. False afterwise. */
673
590
  isLoading() {
674
- return !this.isUpToDate;
591
+ return !__privateGet(this, _isUpToDate);
675
592
  }
676
593
  };
594
+ _error = new WeakMap();
677
595
  _fetchClient2 = new WeakMap();
678
596
  _messageParser = new WeakMap();
679
597
  _subscribers = new WeakMap();
680
- _upToDateSubscribers = new WeakMap();
681
598
  _lastOffset = new WeakMap();
682
599
  _liveCacheBuster = new WeakMap();
683
600
  _lastSyncedAt = new WeakMap();
684
601
  _isUpToDate = new WeakMap();
685
602
  _connected = new WeakMap();
686
603
  _shapeHandle = new WeakMap();
687
- _databaseId = new WeakMap();
688
604
  _schema = new WeakMap();
689
- _error = new WeakMap();
690
- _replica = new WeakMap();
605
+ _onError = new WeakMap();
691
606
  _ShapeStream_instances = new WeakSet();
607
+ start_fn = function() {
608
+ return __async(this, null, function* () {
609
+ var _a, _b;
610
+ try {
611
+ while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
612
+ const { url, signal } = this.options;
613
+ const fetchUrl = new URL(url);
614
+ if (this.options.params) {
615
+ const reservedParams = Object.keys(this.options.params).filter(
616
+ (key) => RESERVED_PARAMS.has(key)
617
+ );
618
+ if (reservedParams.length > 0) {
619
+ throw new Error(
620
+ `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
621
+ );
622
+ }
623
+ const params = toInternalParams(this.options.params);
624
+ if (params.table)
625
+ fetchUrl.searchParams.set(TABLE_QUERY_PARAM, params.table);
626
+ if (params.where)
627
+ fetchUrl.searchParams.set(WHERE_QUERY_PARAM, params.where);
628
+ if (params.columns)
629
+ fetchUrl.searchParams.set(COLUMNS_QUERY_PARAM, params.columns);
630
+ if (params.replica)
631
+ fetchUrl.searchParams.set(REPLICA_PARAM, params.replica);
632
+ const customParams = __spreadValues({}, params);
633
+ delete customParams.table;
634
+ delete customParams.where;
635
+ delete customParams.columns;
636
+ delete customParams.replica;
637
+ for (const [key, value] of Object.entries(customParams)) {
638
+ fetchUrl.searchParams.set(key, value);
639
+ }
640
+ }
641
+ fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
642
+ if (__privateGet(this, _isUpToDate)) {
643
+ fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
644
+ fetchUrl.searchParams.set(
645
+ LIVE_CACHE_BUSTER_QUERY_PARAM,
646
+ __privateGet(this, _liveCacheBuster)
647
+ );
648
+ }
649
+ if (__privateGet(this, _shapeHandle)) {
650
+ fetchUrl.searchParams.set(
651
+ SHAPE_HANDLE_QUERY_PARAM,
652
+ __privateGet(this, _shapeHandle)
653
+ );
654
+ }
655
+ fetchUrl.searchParams.sort();
656
+ let response;
657
+ try {
658
+ response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
659
+ signal,
660
+ headers: this.options.headers
661
+ });
662
+ __privateSet(this, _connected, true);
663
+ } catch (e) {
664
+ if (e instanceof FetchBackoffAbortError) break;
665
+ if (!(e instanceof FetchError)) throw e;
666
+ if (e.status == 409) {
667
+ const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
668
+ __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
669
+ yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
670
+ continue;
671
+ } else if (e.status >= 400 && e.status < 500) {
672
+ __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
673
+ throw e;
674
+ }
675
+ }
676
+ const { headers, status } = response;
677
+ const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
678
+ if (shapeHandle) {
679
+ __privateSet(this, _shapeHandle, shapeHandle);
680
+ }
681
+ const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
682
+ if (lastOffset) {
683
+ __privateSet(this, _lastOffset, lastOffset);
684
+ }
685
+ const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
686
+ if (liveCacheBuster) {
687
+ __privateSet(this, _liveCacheBuster, liveCacheBuster);
688
+ }
689
+ const getSchema = () => {
690
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
691
+ return schemaHeader ? JSON.parse(schemaHeader) : {};
692
+ };
693
+ __privateSet(this, _schema, (_b = __privateGet(this, _schema)) != null ? _b : getSchema());
694
+ const messages = status === 204 ? `[]` : yield response.text();
695
+ if (status === 204) {
696
+ __privateSet(this, _lastSyncedAt, Date.now());
697
+ }
698
+ const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
699
+ if (batch.length > 0) {
700
+ const lastMessage = batch[batch.length - 1];
701
+ if (isUpToDateMessage(lastMessage)) {
702
+ __privateSet(this, _lastSyncedAt, Date.now());
703
+ __privateSet(this, _isUpToDate, true);
704
+ }
705
+ yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
706
+ }
707
+ }
708
+ } catch (err) {
709
+ __privateSet(this, _error, err);
710
+ if (__privateGet(this, _onError)) {
711
+ const retryOpts = yield __privateGet(this, _onError).call(this, err);
712
+ if (typeof retryOpts === `object`) {
713
+ __privateMethod(this, _ShapeStream_instances, reset_fn).call(this);
714
+ if (`params` in retryOpts) {
715
+ this.options.params = retryOpts.params;
716
+ }
717
+ if (`headers` in retryOpts) {
718
+ this.options.headers = retryOpts.headers;
719
+ }
720
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
721
+ }
722
+ return;
723
+ }
724
+ throw err;
725
+ } finally {
726
+ __privateSet(this, _connected, false);
727
+ }
728
+ });
729
+ };
692
730
  publish_fn = function(messages) {
693
731
  return __async(this, null, function* () {
694
732
  yield Promise.all(
@@ -709,55 +747,38 @@ sendErrorToSubscribers_fn = function(error) {
709
747
  errorFn == null ? void 0 : errorFn(error);
710
748
  });
711
749
  };
712
- notifyUpToDateSubscribers_fn = function() {
713
- __privateGet(this, _upToDateSubscribers).forEach(([callback]) => {
714
- callback();
715
- });
716
- };
717
- sendErrorToUpToDateSubscribers_fn = function(error) {
718
- __privateGet(this, _upToDateSubscribers).forEach(
719
- ([_, errorCallback]) => errorCallback(error)
720
- );
721
- };
722
750
  /**
723
751
  * Resets the state of the stream, optionally with a provided
724
752
  * shape handle
725
753
  */
726
- reset_fn = function(shapeHandle) {
754
+ reset_fn = function(handle) {
727
755
  __privateSet(this, _lastOffset, `-1`);
728
756
  __privateSet(this, _liveCacheBuster, ``);
729
- __privateSet(this, _shapeHandle, shapeHandle);
757
+ __privateSet(this, _shapeHandle, handle);
730
758
  __privateSet(this, _isUpToDate, false);
731
759
  __privateSet(this, _connected, false);
732
760
  __privateSet(this, _schema, void 0);
733
761
  };
734
- _ShapeStream.Replica = {
762
+ ShapeStream.Replica = {
735
763
  FULL: `full`,
736
764
  DEFAULT: `default`
737
765
  };
738
- var ShapeStream = _ShapeStream;
739
766
  function validateOptions(options) {
740
767
  if (!options.url) {
741
- throw new Error(`Invalid shape options. It must provide the url`);
768
+ throw new MissingShapeUrlError();
742
769
  }
743
770
  if (options.signal && !(options.signal instanceof AbortSignal)) {
744
- throw new Error(
745
- `Invalid signal option. It must be an instance of AbortSignal.`
746
- );
771
+ throw new InvalidSignalError();
747
772
  }
748
- if (options.offset !== void 0 && options.offset !== `-1` && !options.shapeHandle) {
749
- throw new Error(
750
- `shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`
751
- );
773
+ if (options.offset !== void 0 && options.offset !== `-1` && !options.handle) {
774
+ throw new MissingShapeHandleError();
752
775
  }
753
776
  if (options.params) {
754
777
  const reservedParams = Object.keys(options.params).filter(
755
778
  (key) => RESERVED_PARAMS.has(key)
756
779
  );
757
780
  if (reservedParams.length > 0) {
758
- throw new Error(
759
- `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`
760
- );
781
+ throw new ReservedParamError(reservedParams);
761
782
  }
762
783
  }
763
784
  return;
@@ -778,15 +799,6 @@ var Shape = class {
778
799
  __privateMethod(this, _Shape_instances, process_fn).bind(this),
779
800
  __privateMethod(this, _Shape_instances, handleError_fn).bind(this)
780
801
  );
781
- const unsubscribe = __privateGet(this, _stream).subscribeOnceToUpToDate(
782
- () => {
783
- unsubscribe();
784
- },
785
- (e) => {
786
- __privateMethod(this, _Shape_instances, handleError_fn).call(this, e);
787
- throw e;
788
- }
789
- );
790
802
  }
791
803
  get isUpToDate() {
792
804
  return __privateGet(this, _stream).isUpToDate;
@@ -794,6 +806,9 @@ var Shape = class {
794
806
  get lastOffset() {
795
807
  return __privateGet(this, _stream).lastOffset;
796
808
  }
809
+ get handle() {
810
+ return __privateGet(this, _stream).shapeHandle;
811
+ }
797
812
  get rows() {
798
813
  return this.value.then((v) => Array.from(v.values()));
799
814
  }