@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.
@@ -313,6 +313,7 @@ var WHERE_QUERY_PARAM = `where`;
313
313
  var REPLICA_PARAM = `replica`;
314
314
  var WHERE_PARAMS_PARAM = `params`;
315
315
  var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
316
+ var PAUSE_STREAM = `pause-stream`;
316
317
 
317
318
  // src/fetch.ts
318
319
  var HTTP_RETRY_STATUS_CODES = [429];
@@ -358,12 +359,15 @@ function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
358
359
  }
359
360
  });
360
361
  }
362
+ var NO_BODY_STATUS_CODES = [201, 204, 205];
361
363
  function createFetchWithConsumedMessages(fetchClient) {
362
364
  return (...args) => __async(this, null, function* () {
363
365
  const url = args[0];
364
366
  const res = yield fetchClient(...args);
365
367
  try {
366
- if (res.body === null) return res;
368
+ if (res.status < 200 || NO_BODY_STATUS_CODES.includes(res.status)) {
369
+ return res;
370
+ }
367
371
  const text = yield res.text();
368
372
  return new Response(text, res);
369
373
  } catch (err) {
@@ -578,7 +582,7 @@ function resolveHeaders(headers) {
578
582
  return Object.fromEntries(resolvedEntries);
579
583
  });
580
584
  }
581
- 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;
585
+ 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;
582
586
  var ShapeStream = class {
583
587
  constructor(options) {
584
588
  __privateAdd(this, _ShapeStream_instances);
@@ -587,6 +591,7 @@ var ShapeStream = class {
587
591
  __privateAdd(this, _messageParser);
588
592
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
589
593
  __privateAdd(this, _started, false);
594
+ __privateAdd(this, _state, `active`);
590
595
  __privateAdd(this, _lastOffset);
591
596
  __privateAdd(this, _liveCacheBuster);
592
597
  // Seconds since our Electric Epoch 😎
@@ -623,6 +628,7 @@ var ShapeStream = class {
623
628
  createFetchWithChunkBuffer(fetchWithBackoffClient)
624
629
  )
625
630
  ));
631
+ __privateMethod(this, _ShapeStream_instances, subscribeToVisibilityChanges_fn).call(this);
626
632
  }
627
633
  get shapeHandle() {
628
634
  return __privateGet(this, _shapeHandle);
@@ -668,6 +674,9 @@ var ShapeStream = class {
668
674
  hasStarted() {
669
675
  return __privateGet(this, _started);
670
676
  }
677
+ isPaused() {
678
+ return __privateGet(this, _state) === `paused`;
679
+ }
671
680
  /**
672
681
  * Refreshes the shape stream.
673
682
  * This preemptively aborts any ongoing long poll and reconnects without
@@ -691,6 +700,7 @@ _fetchClient2 = new WeakMap();
691
700
  _messageParser = new WeakMap();
692
701
  _subscribers = new WeakMap();
693
702
  _started = new WeakMap();
703
+ _state = new WeakMap();
694
704
  _lastOffset = new WeakMap();
695
705
  _liveCacheBuster = new WeakMap();
696
706
  _lastSyncedAt = new WeakMap();
@@ -707,128 +717,10 @@ _tickPromiseRejecter = new WeakMap();
707
717
  _ShapeStream_instances = new WeakSet();
708
718
  start_fn = function() {
709
719
  return __async(this, null, function* () {
710
- var _a, _b, _c, _d, _e;
711
- if (__privateGet(this, _started)) throw new Error(`Cannot start stream twice`);
720
+ var _a;
712
721
  __privateSet(this, _started, true);
713
722
  try {
714
- while (!((_a = this.options.signal) == null ? void 0 : _a.aborted) && !__privateGet(this, _isUpToDate) || this.options.subscribe) {
715
- const { url, signal } = this.options;
716
- const [requestHeaders, params] = yield Promise.all([
717
- resolveHeaders(this.options.headers),
718
- this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
719
- ]);
720
- if (params) {
721
- validateParams(params);
722
- }
723
- const fetchUrl = new URL(url);
724
- if (params) {
725
- if (params.table)
726
- setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
727
- if (params.where)
728
- setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where);
729
- if (params.columns)
730
- setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
731
- if (params.replica)
732
- setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
733
- if (params.params)
734
- setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
735
- const customParams = __spreadValues({}, params);
736
- delete customParams.table;
737
- delete customParams.where;
738
- delete customParams.columns;
739
- delete customParams.replica;
740
- delete customParams.params;
741
- for (const [key, value] of Object.entries(customParams)) {
742
- setQueryParam(fetchUrl, key, value);
743
- }
744
- }
745
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
746
- if (__privateGet(this, _isUpToDate)) {
747
- if (!__privateGet(this, _isRefreshing)) {
748
- fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
749
- }
750
- fetchUrl.searchParams.set(
751
- LIVE_CACHE_BUSTER_QUERY_PARAM,
752
- __privateGet(this, _liveCacheBuster)
753
- );
754
- }
755
- if (__privateGet(this, _shapeHandle)) {
756
- fetchUrl.searchParams.set(
757
- SHAPE_HANDLE_QUERY_PARAM,
758
- __privateGet(this, _shapeHandle)
759
- );
760
- }
761
- fetchUrl.searchParams.sort();
762
- __privateSet(this, _requestAbortController, new AbortController());
763
- let abortListener;
764
- if (signal) {
765
- abortListener = () => {
766
- var _a2;
767
- (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
768
- };
769
- signal.addEventListener(`abort`, abortListener, { once: true });
770
- if (signal.aborted) {
771
- (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(signal.reason);
772
- }
773
- }
774
- let response;
775
- try {
776
- response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
777
- signal: __privateGet(this, _requestAbortController).signal,
778
- headers: requestHeaders
779
- });
780
- __privateSet(this, _connected, true);
781
- } catch (e) {
782
- if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && __privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
783
- continue;
784
- }
785
- if (e instanceof FetchBackoffAbortError) break;
786
- if (!(e instanceof FetchError)) throw e;
787
- if (e.status == 409) {
788
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
789
- __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
790
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
791
- continue;
792
- } else {
793
- __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
794
- throw e;
795
- }
796
- } finally {
797
- if (abortListener && signal) {
798
- signal.removeEventListener(`abort`, abortListener);
799
- }
800
- __privateSet(this, _requestAbortController, void 0);
801
- }
802
- const { headers } = response;
803
- const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
804
- if (shapeHandle) {
805
- __privateSet(this, _shapeHandle, shapeHandle);
806
- }
807
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
808
- if (lastOffset) {
809
- __privateSet(this, _lastOffset, lastOffset);
810
- }
811
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
812
- if (liveCacheBuster) {
813
- __privateSet(this, _liveCacheBuster, liveCacheBuster);
814
- }
815
- const getSchema = () => {
816
- const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
817
- return schemaHeader ? JSON.parse(schemaHeader) : {};
818
- };
819
- __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
820
- const messages = yield response.text();
821
- const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
822
- if (batch.length > 0) {
823
- const lastMessage = batch[batch.length - 1];
824
- if (isUpToDateMessage(lastMessage)) {
825
- __privateSet(this, _lastSyncedAt, Date.now());
826
- __privateSet(this, _isUpToDate, true);
827
- }
828
- yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
829
- }
830
- (_d = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _d.call(this);
831
- }
723
+ yield __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
832
724
  } catch (err) {
833
725
  __privateSet(this, _error, err);
834
726
  if (__privateGet(this, _onError)) {
@@ -849,10 +741,155 @@ start_fn = function() {
849
741
  throw err;
850
742
  } finally {
851
743
  __privateSet(this, _connected, false);
852
- (_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
744
+ (_a = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _a.call(this);
853
745
  }
854
746
  });
855
747
  };
748
+ requestShape_fn = function() {
749
+ return __async(this, null, function* () {
750
+ var _a, _b, _c, _d;
751
+ if (__privateGet(this, _state) === `pause-requested`) {
752
+ __privateSet(this, _state, `paused`);
753
+ return;
754
+ }
755
+ if (!this.options.subscribe && (((_a = this.options.signal) == null ? void 0 : _a.aborted) || __privateGet(this, _isUpToDate))) {
756
+ return;
757
+ }
758
+ const resumingFromPause = __privateGet(this, _state) === `paused`;
759
+ __privateSet(this, _state, `active`);
760
+ const { url, signal } = this.options;
761
+ const [requestHeaders, params] = yield Promise.all([
762
+ resolveHeaders(this.options.headers),
763
+ this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
764
+ ]);
765
+ if (params) {
766
+ validateParams(params);
767
+ }
768
+ const fetchUrl = new URL(url);
769
+ if (params) {
770
+ if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
771
+ if (params.where) setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where);
772
+ if (params.columns)
773
+ setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
774
+ if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
775
+ if (params.params)
776
+ setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
777
+ const customParams = __spreadValues({}, params);
778
+ delete customParams.table;
779
+ delete customParams.where;
780
+ delete customParams.columns;
781
+ delete customParams.replica;
782
+ delete customParams.params;
783
+ for (const [key, value] of Object.entries(customParams)) {
784
+ setQueryParam(fetchUrl, key, value);
785
+ }
786
+ }
787
+ fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
788
+ if (__privateGet(this, _isUpToDate)) {
789
+ if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
790
+ fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
791
+ }
792
+ fetchUrl.searchParams.set(
793
+ LIVE_CACHE_BUSTER_QUERY_PARAM,
794
+ __privateGet(this, _liveCacheBuster)
795
+ );
796
+ }
797
+ if (__privateGet(this, _shapeHandle)) {
798
+ fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
799
+ }
800
+ fetchUrl.searchParams.sort();
801
+ __privateSet(this, _requestAbortController, new AbortController());
802
+ let abortListener;
803
+ if (signal) {
804
+ abortListener = () => {
805
+ var _a2;
806
+ (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
807
+ };
808
+ signal.addEventListener(`abort`, abortListener, { once: true });
809
+ if (signal.aborted) {
810
+ (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(signal.reason);
811
+ }
812
+ }
813
+ let response;
814
+ try {
815
+ response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
816
+ signal: __privateGet(this, _requestAbortController).signal,
817
+ headers: requestHeaders
818
+ });
819
+ __privateSet(this, _connected, true);
820
+ } catch (e) {
821
+ if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && __privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
822
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
823
+ }
824
+ if (e instanceof FetchBackoffAbortError) {
825
+ if (__privateGet(this, _requestAbortController).signal.aborted && __privateGet(this, _requestAbortController).signal.reason === PAUSE_STREAM) {
826
+ __privateSet(this, _state, `paused`);
827
+ }
828
+ return;
829
+ }
830
+ if (!(e instanceof FetchError)) throw e;
831
+ if (e.status == 409) {
832
+ const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
833
+ __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
834
+ yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
835
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
836
+ } else {
837
+ __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
838
+ throw e;
839
+ }
840
+ } finally {
841
+ if (abortListener && signal) {
842
+ signal.removeEventListener(`abort`, abortListener);
843
+ }
844
+ __privateSet(this, _requestAbortController, void 0);
845
+ }
846
+ const { headers, status } = response;
847
+ const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
848
+ if (shapeHandle) {
849
+ __privateSet(this, _shapeHandle, shapeHandle);
850
+ }
851
+ const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
852
+ if (lastOffset) {
853
+ __privateSet(this, _lastOffset, lastOffset);
854
+ }
855
+ const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
856
+ if (liveCacheBuster) {
857
+ __privateSet(this, _liveCacheBuster, liveCacheBuster);
858
+ }
859
+ const getSchema = () => {
860
+ const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
861
+ return schemaHeader ? JSON.parse(schemaHeader) : {};
862
+ };
863
+ __privateSet(this, _schema, (_c = __privateGet(this, _schema)) != null ? _c : getSchema());
864
+ if (status === 204) {
865
+ __privateSet(this, _lastSyncedAt, Date.now());
866
+ }
867
+ const messages = (yield response.text()) || `[]`;
868
+ const batch = __privateGet(this, _messageParser).parse(messages, __privateGet(this, _schema));
869
+ if (batch.length > 0) {
870
+ const lastMessage = batch[batch.length - 1];
871
+ if (isUpToDateMessage(lastMessage)) {
872
+ __privateSet(this, _lastSyncedAt, Date.now());
873
+ __privateSet(this, _isUpToDate, true);
874
+ }
875
+ yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
876
+ }
877
+ (_d = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _d.call(this);
878
+ return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
879
+ });
880
+ };
881
+ pause_fn = function() {
882
+ var _a;
883
+ if (__privateGet(this, _started) && __privateGet(this, _state) === `active`) {
884
+ __privateSet(this, _state, `pause-requested`);
885
+ (_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(PAUSE_STREAM);
886
+ }
887
+ };
888
+ resume_fn = function() {
889
+ if (__privateGet(this, _started) && __privateGet(this, _state) === `paused`) {
890
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
891
+ }
892
+ };
856
893
  nextTick_fn = function() {
857
894
  return __async(this, null, function* () {
858
895
  if (__privateGet(this, _tickPromise)) {
@@ -890,6 +927,18 @@ sendErrorToSubscribers_fn = function(error) {
890
927
  errorFn == null ? void 0 : errorFn(error);
891
928
  });
892
929
  };
930
+ subscribeToVisibilityChanges_fn = function() {
931
+ if (typeof document === `object` && typeof document.hidden === `boolean` && typeof document.addEventListener === `function`) {
932
+ const visibilityHandler = () => {
933
+ if (document.hidden) {
934
+ __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
935
+ } else {
936
+ __privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
937
+ }
938
+ };
939
+ document.addEventListener(`visibilitychange`, visibilityHandler);
940
+ }
941
+ };
893
942
  /**
894
943
  * Resets the state of the stream, optionally with a provided
895
944
  * shape handle