@electric-sql/client 1.0.2 → 1.0.4

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.
@@ -262,6 +262,7 @@ var WHERE_QUERY_PARAM = `where`;
262
262
  var REPLICA_PARAM = `replica`;
263
263
  var WHERE_PARAMS_PARAM = `params`;
264
264
  var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
265
+ var PAUSE_STREAM = `pause-stream`;
265
266
 
266
267
  // src/fetch.ts
267
268
  var HTTP_RETRY_STATUS_CODES = [429];
@@ -307,12 +308,15 @@ function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
307
308
  }
308
309
  };
309
310
  }
311
+ var NO_BODY_STATUS_CODES = [201, 204, 205];
310
312
  function createFetchWithConsumedMessages(fetchClient) {
311
313
  return async (...args) => {
312
314
  const url = args[0];
313
315
  const res = await fetchClient(...args);
314
316
  try {
315
- if (res.body === null) return res;
317
+ if (res.status < 200 || NO_BODY_STATUS_CODES.includes(res.status)) {
318
+ return res;
319
+ }
316
320
  const text = await res.text();
317
321
  return new Response(text, res);
318
322
  } catch (err) {
@@ -519,7 +523,7 @@ async function resolveHeaders(headers) {
519
523
  );
520
524
  return Object.fromEntries(resolvedEntries);
521
525
  }
522
- var _error, _fetchClient2, _messageParser, _subscribers, _started, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _ShapeStream_instances, start_fn, nextTick_fn, publish_fn, sendErrorToSubscribers_fn, reset_fn;
526
+ var _error, _fetchClient2, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _ShapeStream_instances, start_fn, requestShape_fn, pause_fn, resume_fn, nextTick_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn;
523
527
  var ShapeStream = class {
524
528
  constructor(options) {
525
529
  __privateAdd(this, _ShapeStream_instances);
@@ -528,6 +532,7 @@ var ShapeStream = class {
528
532
  __privateAdd(this, _messageParser);
529
533
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
530
534
  __privateAdd(this, _started, false);
535
+ __privateAdd(this, _state, `active`);
531
536
  __privateAdd(this, _lastOffset);
532
537
  __privateAdd(this, _liveCacheBuster);
533
538
  // Seconds since our Electric Epoch 😎
@@ -564,6 +569,7 @@ var ShapeStream = class {
564
569
  createFetchWithChunkBuffer(fetchWithBackoffClient)
565
570
  )
566
571
  ));
572
+ __privateMethod(this, _ShapeStream_instances, subscribeToVisibilityChanges_fn).call(this);
567
573
  }
568
574
  get shapeHandle() {
569
575
  return __privateGet(this, _shapeHandle);
@@ -609,6 +615,9 @@ var ShapeStream = class {
609
615
  hasStarted() {
610
616
  return __privateGet(this, _started);
611
617
  }
618
+ isPaused() {
619
+ return __privateGet(this, _state) === `paused`;
620
+ }
612
621
  /**
613
622
  * Refreshes the shape stream.
614
623
  * This preemptively aborts any ongoing long poll and reconnects without
@@ -630,6 +639,7 @@ _fetchClient2 = new WeakMap();
630
639
  _messageParser = new WeakMap();
631
640
  _subscribers = new WeakMap();
632
641
  _started = new WeakMap();
642
+ _state = new WeakMap();
633
643
  _lastOffset = new WeakMap();
634
644
  _liveCacheBuster = new WeakMap();
635
645
  _lastSyncedAt = new WeakMap();
@@ -645,128 +655,10 @@ _tickPromiseResolver = new WeakMap();
645
655
  _tickPromiseRejecter = new WeakMap();
646
656
  _ShapeStream_instances = new WeakSet();
647
657
  start_fn = async function() {
648
- var _a, _b, _c, _d, _e;
649
- if (__privateGet(this, _started)) throw new Error(`Cannot start stream twice`);
658
+ var _a;
650
659
  __privateSet(this, _started, true);
651
660
  try {
652
- while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
653
- const { url, signal } = this.options;
654
- const [requestHeaders, params] = await Promise.all([
655
- resolveHeaders(this.options.headers),
656
- this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
657
- ]);
658
- if (params) {
659
- validateParams(params);
660
- }
661
- const fetchUrl = new URL(url);
662
- if (params) {
663
- if (params.table)
664
- setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
665
- if (params.where)
666
- setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where);
667
- if (params.columns)
668
- setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
669
- if (params.replica)
670
- setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
671
- if (params.params)
672
- setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
673
- const customParams = __spreadValues({}, params);
674
- delete customParams.table;
675
- delete customParams.where;
676
- delete customParams.columns;
677
- delete customParams.replica;
678
- delete customParams.params;
679
- for (const [key, value] of Object.entries(customParams)) {
680
- setQueryParam(fetchUrl, key, value);
681
- }
682
- }
683
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
684
- if (__privateGet(this, _isUpToDate)) {
685
- if (!__privateGet(this, _isRefreshing)) {
686
- fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
687
- }
688
- fetchUrl.searchParams.set(
689
- LIVE_CACHE_BUSTER_QUERY_PARAM,
690
- __privateGet(this, _liveCacheBuster)
691
- );
692
- }
693
- if (__privateGet(this, _shapeHandle)) {
694
- fetchUrl.searchParams.set(
695
- SHAPE_HANDLE_QUERY_PARAM,
696
- __privateGet(this, _shapeHandle)
697
- );
698
- }
699
- fetchUrl.searchParams.sort();
700
- __privateSet(this, _requestAbortController, new AbortController());
701
- let abortListener;
702
- if (signal) {
703
- abortListener = () => {
704
- var _a2;
705
- (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
706
- };
707
- signal.addEventListener(`abort`, abortListener, { once: true });
708
- if (signal.aborted) {
709
- (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(signal.reason);
710
- }
711
- }
712
- let response;
713
- try {
714
- response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
715
- signal: __privateGet(this, _requestAbortController).signal,
716
- headers: requestHeaders
717
- });
718
- __privateSet(this, _connected, true);
719
- } catch (e) {
720
- if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && __privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
721
- continue;
722
- }
723
- if (e instanceof FetchBackoffAbortError) break;
724
- if (!(e instanceof FetchError)) throw e;
725
- if (e.status == 409) {
726
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
727
- __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
728
- await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
729
- continue;
730
- } else {
731
- __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
732
- throw e;
733
- }
734
- } finally {
735
- if (abortListener && signal) {
736
- signal.removeEventListener(`abort`, abortListener);
737
- }
738
- __privateSet(this, _requestAbortController, void 0);
739
- }
740
- const { headers } = response;
741
- const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
742
- if (shapeHandle) {
743
- __privateSet(this, _shapeHandle, shapeHandle);
744
- }
745
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
746
- if (lastOffset) {
747
- __privateSet(this, _lastOffset, lastOffset);
748
- }
749
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
750
- if (liveCacheBuster) {
751
- __privateSet(this, _liveCacheBuster, liveCacheBuster);
752
- }
753
- const getSchema = () => {
754
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
755
- return schemaHeader ? JSON.parse(schemaHeader) : {};
756
- };
757
- __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
758
- const messages = await response.text();
759
- const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
760
- if (batch.length > 0) {
761
- const lastMessage = batch[batch.length - 1];
762
- if (isUpToDateMessage(lastMessage)) {
763
- __privateSet(this, _lastSyncedAt, Date.now());
764
- __privateSet(this, _isUpToDate, true);
765
- }
766
- await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
767
- }
768
- (_d = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _d.call(this);
769
- }
661
+ await __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
770
662
  } catch (err) {
771
663
  __privateSet(this, _error, err);
772
664
  if (__privateGet(this, _onError)) {
@@ -787,7 +679,150 @@ start_fn = async function() {
787
679
  throw err;
788
680
  } finally {
789
681
  __privateSet(this, _connected, false);
790
- (_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
682
+ (_a = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _a.call(this);
683
+ }
684
+ };
685
+ requestShape_fn = async function() {
686
+ var _a, _b, _c, _d;
687
+ if (__privateGet(this, _state) === `pause-requested`) {
688
+ __privateSet(this, _state, `paused`);
689
+ return;
690
+ }
691
+ if (!this.options.subscribe && (((_a = this.options.signal) == null ? void 0 : _a.aborted) || __privateGet(this, _isUpToDate))) {
692
+ return;
693
+ }
694
+ const resumingFromPause = __privateGet(this, _state) === `paused`;
695
+ __privateSet(this, _state, `active`);
696
+ const { url, signal } = this.options;
697
+ const [requestHeaders, params] = await Promise.all([
698
+ resolveHeaders(this.options.headers),
699
+ this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
700
+ ]);
701
+ if (params) {
702
+ validateParams(params);
703
+ }
704
+ const fetchUrl = new URL(url);
705
+ if (params) {
706
+ if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
707
+ if (params.where) setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where);
708
+ if (params.columns)
709
+ setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
710
+ if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
711
+ if (params.params)
712
+ setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
713
+ const customParams = __spreadValues({}, params);
714
+ delete customParams.table;
715
+ delete customParams.where;
716
+ delete customParams.columns;
717
+ delete customParams.replica;
718
+ delete customParams.params;
719
+ for (const [key, value] of Object.entries(customParams)) {
720
+ setQueryParam(fetchUrl, key, value);
721
+ }
722
+ }
723
+ fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
724
+ if (__privateGet(this, _isUpToDate)) {
725
+ if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
726
+ fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
727
+ }
728
+ fetchUrl.searchParams.set(
729
+ LIVE_CACHE_BUSTER_QUERY_PARAM,
730
+ __privateGet(this, _liveCacheBuster)
731
+ );
732
+ }
733
+ if (__privateGet(this, _shapeHandle)) {
734
+ fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
735
+ }
736
+ fetchUrl.searchParams.sort();
737
+ __privateSet(this, _requestAbortController, new AbortController());
738
+ let abortListener;
739
+ if (signal) {
740
+ abortListener = () => {
741
+ var _a2;
742
+ (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
743
+ };
744
+ signal.addEventListener(`abort`, abortListener, { once: true });
745
+ if (signal.aborted) {
746
+ (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(signal.reason);
747
+ }
748
+ }
749
+ let response;
750
+ try {
751
+ response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
752
+ signal: __privateGet(this, _requestAbortController).signal,
753
+ headers: requestHeaders
754
+ });
755
+ __privateSet(this, _connected, true);
756
+ } catch (e) {
757
+ if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && __privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
758
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
759
+ }
760
+ if (e instanceof FetchBackoffAbortError) {
761
+ if (__privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === PAUSE_STREAM) {
762
+ __privateSet(this, _state, `paused`);
763
+ }
764
+ return;
765
+ }
766
+ if (!(e instanceof FetchError)) throw e;
767
+ if (e.status == 409) {
768
+ const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
769
+ __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
770
+ await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
771
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
772
+ } else {
773
+ __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
774
+ throw e;
775
+ }
776
+ } finally {
777
+ if (abortListener && signal) {
778
+ signal.removeEventListener(`abort`, abortListener);
779
+ }
780
+ __privateSet(this, _requestAbortController, void 0);
781
+ }
782
+ const { headers, status } = response;
783
+ const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
784
+ if (shapeHandle) {
785
+ __privateSet(this, _shapeHandle, shapeHandle);
786
+ }
787
+ const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
788
+ if (lastOffset) {
789
+ __privateSet(this, _lastOffset, lastOffset);
790
+ }
791
+ const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
792
+ if (liveCacheBuster) {
793
+ __privateSet(this, _liveCacheBuster, liveCacheBuster);
794
+ }
795
+ const getSchema = () => {
796
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
797
+ return schemaHeader ? JSON.parse(schemaHeader) : {};
798
+ };
799
+ __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
800
+ if (status === 204) {
801
+ __privateSet(this, _lastSyncedAt, Date.now());
802
+ }
803
+ const messages = await response.text() || `[]`;
804
+ const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
805
+ if (batch.length > 0) {
806
+ const lastMessage = batch[batch.length - 1];
807
+ if (isUpToDateMessage(lastMessage)) {
808
+ __privateSet(this, _lastSyncedAt, Date.now());
809
+ __privateSet(this, _isUpToDate, true);
810
+ }
811
+ await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
812
+ }
813
+ (_d = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _d.call(this);
814
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
815
+ };
816
+ pause_fn = function() {
817
+ var _a;
818
+ if (__privateGet(this, _started) && __privateGet(this, _state) === `active`) {
819
+ __privateSet(this, _state, `pause-requested`);
820
+ (_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(PAUSE_STREAM);
821
+ }
822
+ };
823
+ resume_fn = function() {
824
+ if (__privateGet(this, _started) && __privateGet(this, _state) === `paused`) {
825
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
791
826
  }
792
827
  };
793
828
  nextTick_fn = async function() {
@@ -823,6 +858,18 @@ sendErrorToSubscribers_fn = function(error) {
823
858
  errorFn == null ? void 0 : errorFn(error);
824
859
  });
825
860
  };
861
+ subscribeToVisibilityChanges_fn = function() {
862
+ if (typeof document === `object` && typeof document.hidden === `boolean` && typeof document.addEventListener === `function`) {
863
+ const visibilityHandler = () => {
864
+ if (document.hidden) {
865
+ __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
866
+ } else {
867
+ __privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
868
+ }
869
+ };
870
+ document.addEventListener(`visibilitychange`, visibilityHandler);
871
+ }
872
+ };
826
873
  /**
827
874
  * Resets the state of the stream, optionally with a provided
828
875
  * shape handle