@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.
@@ -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];
@@ -522,7 +523,7 @@ async function resolveHeaders(headers) {
522
523
  );
523
524
  return Object.fromEntries(resolvedEntries);
524
525
  }
525
- 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;
526
527
  var ShapeStream = class {
527
528
  constructor(options) {
528
529
  __privateAdd(this, _ShapeStream_instances);
@@ -531,6 +532,7 @@ var ShapeStream = class {
531
532
  __privateAdd(this, _messageParser);
532
533
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
533
534
  __privateAdd(this, _started, false);
535
+ __privateAdd(this, _state, `active`);
534
536
  __privateAdd(this, _lastOffset);
535
537
  __privateAdd(this, _liveCacheBuster);
536
538
  // Seconds since our Electric Epoch 😎
@@ -567,6 +569,7 @@ var ShapeStream = class {
567
569
  createFetchWithChunkBuffer(fetchWithBackoffClient)
568
570
  )
569
571
  ));
572
+ __privateMethod(this, _ShapeStream_instances, subscribeToVisibilityChanges_fn).call(this);
570
573
  }
571
574
  get shapeHandle() {
572
575
  return __privateGet(this, _shapeHandle);
@@ -612,6 +615,9 @@ var ShapeStream = class {
612
615
  hasStarted() {
613
616
  return __privateGet(this, _started);
614
617
  }
618
+ isPaused() {
619
+ return __privateGet(this, _state) === `paused`;
620
+ }
615
621
  /**
616
622
  * Refreshes the shape stream.
617
623
  * This preemptively aborts any ongoing long poll and reconnects without
@@ -633,6 +639,7 @@ _fetchClient2 = new WeakMap();
633
639
  _messageParser = new WeakMap();
634
640
  _subscribers = new WeakMap();
635
641
  _started = new WeakMap();
642
+ _state = new WeakMap();
636
643
  _lastOffset = new WeakMap();
637
644
  _liveCacheBuster = new WeakMap();
638
645
  _lastSyncedAt = new WeakMap();
@@ -648,131 +655,10 @@ _tickPromiseResolver = new WeakMap();
648
655
  _tickPromiseRejecter = new WeakMap();
649
656
  _ShapeStream_instances = new WeakSet();
650
657
  start_fn = async function() {
651
- var _a, _b, _c, _d, _e;
652
- if (__privateGet(this, _started)) throw new Error(`Cannot start stream twice`);
658
+ var _a;
653
659
  __privateSet(this, _started, true);
654
660
  try {
655
- while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
656
- const { url, signal } = this.options;
657
- const [requestHeaders, params] = await Promise.all([
658
- resolveHeaders(this.options.headers),
659
- this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
660
- ]);
661
- if (params) {
662
- validateParams(params);
663
- }
664
- const fetchUrl = new URL(url);
665
- if (params) {
666
- if (params.table)
667
- setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
668
- if (params.where)
669
- setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where);
670
- if (params.columns)
671
- setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
672
- if (params.replica)
673
- setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
674
- if (params.params)
675
- setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
676
- const customParams = __spreadValues({}, params);
677
- delete customParams.table;
678
- delete customParams.where;
679
- delete customParams.columns;
680
- delete customParams.replica;
681
- delete customParams.params;
682
- for (const [key, value] of Object.entries(customParams)) {
683
- setQueryParam(fetchUrl, key, value);
684
- }
685
- }
686
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
687
- if (__privateGet(this, _isUpToDate)) {
688
- if (!__privateGet(this, _isRefreshing)) {
689
- fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
690
- }
691
- fetchUrl.searchParams.set(
692
- LIVE_CACHE_BUSTER_QUERY_PARAM,
693
- __privateGet(this, _liveCacheBuster)
694
- );
695
- }
696
- if (__privateGet(this, _shapeHandle)) {
697
- fetchUrl.searchParams.set(
698
- SHAPE_HANDLE_QUERY_PARAM,
699
- __privateGet(this, _shapeHandle)
700
- );
701
- }
702
- fetchUrl.searchParams.sort();
703
- __privateSet(this, _requestAbortController, new AbortController());
704
- let abortListener;
705
- if (signal) {
706
- abortListener = () => {
707
- var _a2;
708
- (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
709
- };
710
- signal.addEventListener(`abort`, abortListener, { once: true });
711
- if (signal.aborted) {
712
- (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(signal.reason);
713
- }
714
- }
715
- let response;
716
- try {
717
- response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
718
- signal: __privateGet(this, _requestAbortController).signal,
719
- headers: requestHeaders
720
- });
721
- __privateSet(this, _connected, true);
722
- } catch (e) {
723
- if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && __privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
724
- continue;
725
- }
726
- if (e instanceof FetchBackoffAbortError) break;
727
- if (!(e instanceof FetchError)) throw e;
728
- if (e.status == 409) {
729
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
730
- __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
731
- await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
732
- continue;
733
- } else {
734
- __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
735
- throw e;
736
- }
737
- } finally {
738
- if (abortListener && signal) {
739
- signal.removeEventListener(`abort`, abortListener);
740
- }
741
- __privateSet(this, _requestAbortController, void 0);
742
- }
743
- const { headers, status } = response;
744
- const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
745
- if (shapeHandle) {
746
- __privateSet(this, _shapeHandle, shapeHandle);
747
- }
748
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
749
- if (lastOffset) {
750
- __privateSet(this, _lastOffset, lastOffset);
751
- }
752
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
753
- if (liveCacheBuster) {
754
- __privateSet(this, _liveCacheBuster, liveCacheBuster);
755
- }
756
- const getSchema = () => {
757
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
758
- return schemaHeader ? JSON.parse(schemaHeader) : {};
759
- };
760
- __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
761
- if (status === 204) {
762
- __privateSet(this, _lastSyncedAt, Date.now());
763
- }
764
- const messages = await response.text() || `[]`;
765
- const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
766
- if (batch.length > 0) {
767
- const lastMessage = batch[batch.length - 1];
768
- if (isUpToDateMessage(lastMessage)) {
769
- __privateSet(this, _lastSyncedAt, Date.now());
770
- __privateSet(this, _isUpToDate, true);
771
- }
772
- await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
773
- }
774
- (_d = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _d.call(this);
775
- }
661
+ await __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
776
662
  } catch (err) {
777
663
  __privateSet(this, _error, err);
778
664
  if (__privateGet(this, _onError)) {
@@ -793,7 +679,150 @@ start_fn = async function() {
793
679
  throw err;
794
680
  } finally {
795
681
  __privateSet(this, _connected, false);
796
- (_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);
797
826
  }
798
827
  };
799
828
  nextTick_fn = async function() {
@@ -829,6 +858,18 @@ sendErrorToSubscribers_fn = function(error) {
829
858
  errorFn == null ? void 0 : errorFn(error);
830
859
  });
831
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
+ };
832
873
  /**
833
874
  * Resets the state of the stream, optionally with a provided
834
875
  * shape handle