@electric-sql/client 1.0.3 → 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.
package/dist/index.mjs CHANGED
@@ -284,6 +284,7 @@ var WHERE_QUERY_PARAM = `where`;
284
284
  var REPLICA_PARAM = `replica`;
285
285
  var WHERE_PARAMS_PARAM = `params`;
286
286
  var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
287
+ var PAUSE_STREAM = `pause-stream`;
287
288
 
288
289
  // src/fetch.ts
289
290
  var HTTP_RETRY_STATUS_CODES = [429];
@@ -552,7 +553,7 @@ function resolveHeaders(headers) {
552
553
  return Object.fromEntries(resolvedEntries);
553
554
  });
554
555
  }
555
- 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;
556
+ 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;
556
557
  var ShapeStream = class {
557
558
  constructor(options) {
558
559
  __privateAdd(this, _ShapeStream_instances);
@@ -561,6 +562,7 @@ var ShapeStream = class {
561
562
  __privateAdd(this, _messageParser);
562
563
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
563
564
  __privateAdd(this, _started, false);
565
+ __privateAdd(this, _state, `active`);
564
566
  __privateAdd(this, _lastOffset);
565
567
  __privateAdd(this, _liveCacheBuster);
566
568
  // Seconds since our Electric Epoch 😎
@@ -597,6 +599,7 @@ var ShapeStream = class {
597
599
  createFetchWithChunkBuffer(fetchWithBackoffClient)
598
600
  )
599
601
  ));
602
+ __privateMethod(this, _ShapeStream_instances, subscribeToVisibilityChanges_fn).call(this);
600
603
  }
601
604
  get shapeHandle() {
602
605
  return __privateGet(this, _shapeHandle);
@@ -642,6 +645,9 @@ var ShapeStream = class {
642
645
  hasStarted() {
643
646
  return __privateGet(this, _started);
644
647
  }
648
+ isPaused() {
649
+ return __privateGet(this, _state) === `paused`;
650
+ }
645
651
  /**
646
652
  * Refreshes the shape stream.
647
653
  * This preemptively aborts any ongoing long poll and reconnects without
@@ -665,6 +671,7 @@ _fetchClient2 = new WeakMap();
665
671
  _messageParser = new WeakMap();
666
672
  _subscribers = new WeakMap();
667
673
  _started = new WeakMap();
674
+ _state = new WeakMap();
668
675
  _lastOffset = new WeakMap();
669
676
  _liveCacheBuster = new WeakMap();
670
677
  _lastSyncedAt = new WeakMap();
@@ -681,131 +688,10 @@ _tickPromiseRejecter = new WeakMap();
681
688
  _ShapeStream_instances = new WeakSet();
682
689
  start_fn = function() {
683
690
  return __async(this, null, function* () {
684
- var _a, _b, _c, _d, _e;
685
- if (__privateGet(this, _started)) throw new Error(`Cannot start stream twice`);
691
+ var _a;
686
692
  __privateSet(this, _started, true);
687
693
  try {
688
- while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
689
- const { url, signal } = this.options;
690
- const [requestHeaders, params] = yield Promise.all([
691
- resolveHeaders(this.options.headers),
692
- this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
693
- ]);
694
- if (params) {
695
- validateParams(params);
696
- }
697
- const fetchUrl = new URL(url);
698
- if (params) {
699
- if (params.table)
700
- setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
701
- if (params.where)
702
- setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where);
703
- if (params.columns)
704
- setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
705
- if (params.replica)
706
- setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
707
- if (params.params)
708
- setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
709
- const customParams = __spreadValues({}, params);
710
- delete customParams.table;
711
- delete customParams.where;
712
- delete customParams.columns;
713
- delete customParams.replica;
714
- delete customParams.params;
715
- for (const [key, value] of Object.entries(customParams)) {
716
- setQueryParam(fetchUrl, key, value);
717
- }
718
- }
719
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
720
- if (__privateGet(this, _isUpToDate)) {
721
- if (!__privateGet(this, _isRefreshing)) {
722
- fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
723
- }
724
- fetchUrl.searchParams.set(
725
- LIVE_CACHE_BUSTER_QUERY_PARAM,
726
- __privateGet(this, _liveCacheBuster)
727
- );
728
- }
729
- if (__privateGet(this, _shapeHandle)) {
730
- fetchUrl.searchParams.set(
731
- SHAPE_HANDLE_QUERY_PARAM,
732
- __privateGet(this, _shapeHandle)
733
- );
734
- }
735
- fetchUrl.searchParams.sort();
736
- __privateSet(this, _requestAbortController, new AbortController());
737
- let abortListener;
738
- if (signal) {
739
- abortListener = () => {
740
- var _a2;
741
- (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
742
- };
743
- signal.addEventListener(`abort`, abortListener, { once: true });
744
- if (signal.aborted) {
745
- (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(signal.reason);
746
- }
747
- }
748
- let response;
749
- try {
750
- response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
751
- signal: __privateGet(this, _requestAbortController).signal,
752
- headers: requestHeaders
753
- });
754
- __privateSet(this, _connected, true);
755
- } catch (e) {
756
- if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && __privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
757
- continue;
758
- }
759
- if (e instanceof FetchBackoffAbortError) break;
760
- if (!(e instanceof FetchError)) throw e;
761
- if (e.status == 409) {
762
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
763
- __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
764
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
765
- continue;
766
- } else {
767
- __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
768
- throw e;
769
- }
770
- } finally {
771
- if (abortListener && signal) {
772
- signal.removeEventListener(`abort`, abortListener);
773
- }
774
- __privateSet(this, _requestAbortController, void 0);
775
- }
776
- const { headers, status } = response;
777
- const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
778
- if (shapeHandle) {
779
- __privateSet(this, _shapeHandle, shapeHandle);
780
- }
781
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
782
- if (lastOffset) {
783
- __privateSet(this, _lastOffset, lastOffset);
784
- }
785
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
786
- if (liveCacheBuster) {
787
- __privateSet(this, _liveCacheBuster, liveCacheBuster);
788
- }
789
- const getSchema = () => {
790
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
791
- return schemaHeader ? JSON.parse(schemaHeader) : {};
792
- };
793
- __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
794
- if (status === 204) {
795
- __privateSet(this, _lastSyncedAt, Date.now());
796
- }
797
- const messages = (yield response.text()) || `[]`;
798
- const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
799
- if (batch.length > 0) {
800
- const lastMessage = batch[batch.length - 1];
801
- if (isUpToDateMessage(lastMessage)) {
802
- __privateSet(this, _lastSyncedAt, Date.now());
803
- __privateSet(this, _isUpToDate, true);
804
- }
805
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
806
- }
807
- (_d = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _d.call(this);
808
- }
694
+ yield __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
809
695
  } catch (err) {
810
696
  __privateSet(this, _error, err);
811
697
  if (__privateGet(this, _onError)) {
@@ -826,10 +712,155 @@ start_fn = function() {
826
712
  throw err;
827
713
  } finally {
828
714
  __privateSet(this, _connected, false);
829
- (_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
715
+ (_a = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _a.call(this);
830
716
  }
831
717
  });
832
718
  };
719
+ requestShape_fn = function() {
720
+ return __async(this, null, function* () {
721
+ var _a, _b, _c, _d;
722
+ if (__privateGet(this, _state) === `pause-requested`) {
723
+ __privateSet(this, _state, `paused`);
724
+ return;
725
+ }
726
+ if (!this.options.subscribe && (((_a = this.options.signal) == null ? void 0 : _a.aborted) || __privateGet(this, _isUpToDate))) {
727
+ return;
728
+ }
729
+ const resumingFromPause = __privateGet(this, _state) === `paused`;
730
+ __privateSet(this, _state, `active`);
731
+ const { url, signal } = this.options;
732
+ const [requestHeaders, params] = yield Promise.all([
733
+ resolveHeaders(this.options.headers),
734
+ this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
735
+ ]);
736
+ if (params) {
737
+ validateParams(params);
738
+ }
739
+ const fetchUrl = new URL(url);
740
+ if (params) {
741
+ if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
742
+ if (params.where) setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where);
743
+ if (params.columns)
744
+ setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
745
+ if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
746
+ if (params.params)
747
+ setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
748
+ const customParams = __spreadValues({}, params);
749
+ delete customParams.table;
750
+ delete customParams.where;
751
+ delete customParams.columns;
752
+ delete customParams.replica;
753
+ delete customParams.params;
754
+ for (const [key, value] of Object.entries(customParams)) {
755
+ setQueryParam(fetchUrl, key, value);
756
+ }
757
+ }
758
+ fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
759
+ if (__privateGet(this, _isUpToDate)) {
760
+ if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
761
+ fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
762
+ }
763
+ fetchUrl.searchParams.set(
764
+ LIVE_CACHE_BUSTER_QUERY_PARAM,
765
+ __privateGet(this, _liveCacheBuster)
766
+ );
767
+ }
768
+ if (__privateGet(this, _shapeHandle)) {
769
+ fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
770
+ }
771
+ fetchUrl.searchParams.sort();
772
+ __privateSet(this, _requestAbortController, new AbortController());
773
+ let abortListener;
774
+ if (signal) {
775
+ abortListener = () => {
776
+ var _a2;
777
+ (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
778
+ };
779
+ signal.addEventListener(`abort`, abortListener, { once: true });
780
+ if (signal.aborted) {
781
+ (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(signal.reason);
782
+ }
783
+ }
784
+ let response;
785
+ try {
786
+ response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
787
+ signal: __privateGet(this, _requestAbortController).signal,
788
+ headers: requestHeaders
789
+ });
790
+ __privateSet(this, _connected, true);
791
+ } catch (e) {
792
+ if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && __privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
793
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
794
+ }
795
+ if (e instanceof FetchBackoffAbortError) {
796
+ if (__privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === PAUSE_STREAM) {
797
+ __privateSet(this, _state, `paused`);
798
+ }
799
+ return;
800
+ }
801
+ if (!(e instanceof FetchError)) throw e;
802
+ if (e.status == 409) {
803
+ const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
804
+ __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
805
+ yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
806
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
807
+ } else {
808
+ __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
809
+ throw e;
810
+ }
811
+ } finally {
812
+ if (abortListener && signal) {
813
+ signal.removeEventListener(`abort`, abortListener);
814
+ }
815
+ __privateSet(this, _requestAbortController, void 0);
816
+ }
817
+ const { headers, status } = response;
818
+ const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
819
+ if (shapeHandle) {
820
+ __privateSet(this, _shapeHandle, shapeHandle);
821
+ }
822
+ const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
823
+ if (lastOffset) {
824
+ __privateSet(this, _lastOffset, lastOffset);
825
+ }
826
+ const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
827
+ if (liveCacheBuster) {
828
+ __privateSet(this, _liveCacheBuster, liveCacheBuster);
829
+ }
830
+ const getSchema = () => {
831
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
832
+ return schemaHeader ? JSON.parse(schemaHeader) : {};
833
+ };
834
+ __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
835
+ if (status === 204) {
836
+ __privateSet(this, _lastSyncedAt, Date.now());
837
+ }
838
+ const messages = (yield response.text()) || `[]`;
839
+ const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
840
+ if (batch.length > 0) {
841
+ const lastMessage = batch[batch.length - 1];
842
+ if (isUpToDateMessage(lastMessage)) {
843
+ __privateSet(this, _lastSyncedAt, Date.now());
844
+ __privateSet(this, _isUpToDate, true);
845
+ }
846
+ yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
847
+ }
848
+ (_d = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _d.call(this);
849
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
850
+ });
851
+ };
852
+ pause_fn = function() {
853
+ var _a;
854
+ if (__privateGet(this, _started) && __privateGet(this, _state) === `active`) {
855
+ __privateSet(this, _state, `pause-requested`);
856
+ (_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(PAUSE_STREAM);
857
+ }
858
+ };
859
+ resume_fn = function() {
860
+ if (__privateGet(this, _started) && __privateGet(this, _state) === `paused`) {
861
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
862
+ }
863
+ };
833
864
  nextTick_fn = function() {
834
865
  return __async(this, null, function* () {
835
866
  if (__privateGet(this, _tickPromise)) {
@@ -867,6 +898,18 @@ sendErrorToSubscribers_fn = function(error) {
867
898
  errorFn == null ? void 0 : errorFn(error);
868
899
  });
869
900
  };
901
+ subscribeToVisibilityChanges_fn = function() {
902
+ if (typeof document === `object` && typeof document.hidden === `boolean` && typeof document.addEventListener === `function`) {
903
+ const visibilityHandler = () => {
904
+ if (document.hidden) {
905
+ __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
906
+ } else {
907
+ __privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
908
+ }
909
+ };
910
+ document.addEventListener(`visibilitychange`, visibilityHandler);
911
+ }
912
+ };
870
913
  /**
871
914
  * Resets the state of the stream, optionally with a provided
872
915
  * shape handle