@electric-sql/client 1.0.4 → 1.0.6
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/cjs/index.cjs +176 -61
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +29 -9
- package/dist/index.browser.mjs +3 -3
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +29 -9
- package/dist/index.legacy-esm.js +164 -61
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +178 -61
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -3
- package/src/client.ts +256 -90
- package/src/constants.ts +1 -0
- package/src/fetch.ts +4 -1
- package/src/helpers.ts +14 -1
- package/src/parser.ts +3 -3
- package/src/types.ts +5 -2
package/dist/index.mjs
CHANGED
|
@@ -267,6 +267,13 @@ function isControlMessage(message) {
|
|
|
267
267
|
function isUpToDateMessage(message) {
|
|
268
268
|
return isControlMessage(message) && message.headers.control === `up-to-date`;
|
|
269
269
|
}
|
|
270
|
+
function getOffset(message) {
|
|
271
|
+
const lsn = message.headers.global_last_seen_lsn;
|
|
272
|
+
if (!lsn) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
return `${lsn}_0`;
|
|
276
|
+
}
|
|
270
277
|
|
|
271
278
|
// src/constants.ts
|
|
272
279
|
var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
|
|
@@ -283,6 +290,7 @@ var TABLE_QUERY_PARAM = `table`;
|
|
|
283
290
|
var WHERE_QUERY_PARAM = `where`;
|
|
284
291
|
var REPLICA_PARAM = `replica`;
|
|
285
292
|
var WHERE_PARAMS_PARAM = `params`;
|
|
293
|
+
var EXPERIMENTAL_LIVE_SSE_QUERY_PARAM = `experimental_live_sse`;
|
|
286
294
|
var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
|
|
287
295
|
var PAUSE_STREAM = `pause-stream`;
|
|
288
296
|
|
|
@@ -311,7 +319,8 @@ function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
|
|
|
311
319
|
try {
|
|
312
320
|
const result = yield fetchClient(...args);
|
|
313
321
|
if (result.ok) return result;
|
|
314
|
-
|
|
322
|
+
const err = yield FetchError.fromResponse(result, url.toString());
|
|
323
|
+
throw err;
|
|
315
324
|
} catch (e) {
|
|
316
325
|
onFailedAttempt == null ? void 0 : onFailedAttempt();
|
|
317
326
|
if ((_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.aborted) {
|
|
@@ -509,6 +518,9 @@ function noop() {
|
|
|
509
518
|
}
|
|
510
519
|
|
|
511
520
|
// src/client.ts
|
|
521
|
+
import {
|
|
522
|
+
fetchEventSource
|
|
523
|
+
} from "@microsoft/fetch-event-source";
|
|
512
524
|
var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
513
525
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
514
526
|
SHAPE_HANDLE_QUERY_PARAM,
|
|
@@ -553,12 +565,14 @@ function resolveHeaders(headers) {
|
|
|
553
565
|
return Object.fromEntries(resolvedEntries);
|
|
554
566
|
});
|
|
555
567
|
}
|
|
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;
|
|
568
|
+
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _connected, _shapeHandle, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _ShapeStream_instances, start_fn, requestShape_fn, constructUrl_fn, createAbortListener_fn, onInitialResponse_fn, onMessages_fn, fetchShape_fn, requestShapeLongPoll_fn, requestShapeSSE_fn, pause_fn, resume_fn, nextTick_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn;
|
|
557
569
|
var ShapeStream = class {
|
|
570
|
+
// promise chain for incoming messages
|
|
558
571
|
constructor(options) {
|
|
559
572
|
__privateAdd(this, _ShapeStream_instances);
|
|
560
573
|
__privateAdd(this, _error, null);
|
|
561
574
|
__privateAdd(this, _fetchClient2);
|
|
575
|
+
__privateAdd(this, _sseFetchClient);
|
|
562
576
|
__privateAdd(this, _messageParser);
|
|
563
577
|
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
564
578
|
__privateAdd(this, _started, false);
|
|
@@ -578,6 +592,7 @@ var ShapeStream = class {
|
|
|
578
592
|
__privateAdd(this, _tickPromise);
|
|
579
593
|
__privateAdd(this, _tickPromiseResolver);
|
|
580
594
|
__privateAdd(this, _tickPromiseRejecter);
|
|
595
|
+
__privateAdd(this, _messageChain, Promise.resolve([]));
|
|
581
596
|
var _a, _b, _c;
|
|
582
597
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
583
598
|
validateOptions(this.options);
|
|
@@ -587,18 +602,21 @@ var ShapeStream = class {
|
|
|
587
602
|
__privateSet(this, _messageParser, new MessageParser(options.parser));
|
|
588
603
|
__privateSet(this, _onError, this.options.onError);
|
|
589
604
|
const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
|
|
590
|
-
const
|
|
605
|
+
const backOffOpts = __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
|
|
591
606
|
onFailedAttempt: () => {
|
|
592
607
|
var _a2, _b2;
|
|
593
608
|
__privateSet(this, _connected, false);
|
|
594
609
|
(_b2 = (_a2 = options.backoffOptions) == null ? void 0 : _a2.onFailedAttempt) == null ? void 0 : _b2.call(_a2);
|
|
595
610
|
}
|
|
596
|
-
})
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
611
|
+
});
|
|
612
|
+
const fetchWithBackoffClient = createFetchWithBackoff(
|
|
613
|
+
baseFetchClient,
|
|
614
|
+
backOffOpts
|
|
615
|
+
);
|
|
616
|
+
__privateSet(this, _sseFetchClient, createFetchWithResponseHeadersCheck(
|
|
617
|
+
createFetchWithChunkBuffer(fetchWithBackoffClient)
|
|
601
618
|
));
|
|
619
|
+
__privateSet(this, _fetchClient2, createFetchWithConsumedMessages(__privateGet(this, _sseFetchClient)));
|
|
602
620
|
__privateMethod(this, _ShapeStream_instances, subscribeToVisibilityChanges_fn).call(this);
|
|
603
621
|
}
|
|
604
622
|
get shapeHandle() {
|
|
@@ -668,6 +686,7 @@ var ShapeStream = class {
|
|
|
668
686
|
};
|
|
669
687
|
_error = new WeakMap();
|
|
670
688
|
_fetchClient2 = new WeakMap();
|
|
689
|
+
_sseFetchClient = new WeakMap();
|
|
671
690
|
_messageParser = new WeakMap();
|
|
672
691
|
_subscribers = new WeakMap();
|
|
673
692
|
_started = new WeakMap();
|
|
@@ -685,6 +704,7 @@ _isRefreshing = new WeakMap();
|
|
|
685
704
|
_tickPromise = new WeakMap();
|
|
686
705
|
_tickPromiseResolver = new WeakMap();
|
|
687
706
|
_tickPromiseRejecter = new WeakMap();
|
|
707
|
+
_messageChain = new WeakMap();
|
|
688
708
|
_ShapeStream_instances = new WeakSet();
|
|
689
709
|
start_fn = function() {
|
|
690
710
|
return __async(this, null, function* () {
|
|
@@ -718,7 +738,7 @@ start_fn = function() {
|
|
|
718
738
|
};
|
|
719
739
|
requestShape_fn = function() {
|
|
720
740
|
return __async(this, null, function* () {
|
|
721
|
-
var _a, _b
|
|
741
|
+
var _a, _b;
|
|
722
742
|
if (__privateGet(this, _state) === `pause-requested`) {
|
|
723
743
|
__privateSet(this, _state, `paused`);
|
|
724
744
|
return;
|
|
@@ -729,6 +749,48 @@ requestShape_fn = function() {
|
|
|
729
749
|
const resumingFromPause = __privateGet(this, _state) === `paused`;
|
|
730
750
|
__privateSet(this, _state, `active`);
|
|
731
751
|
const { url, signal } = this.options;
|
|
752
|
+
const { fetchUrl, requestHeaders } = yield __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, url, resumingFromPause);
|
|
753
|
+
const abortListener = yield __privateMethod(this, _ShapeStream_instances, createAbortListener_fn).call(this, signal);
|
|
754
|
+
const requestAbortController = __privateGet(this, _requestAbortController);
|
|
755
|
+
try {
|
|
756
|
+
yield __privateMethod(this, _ShapeStream_instances, fetchShape_fn).call(this, {
|
|
757
|
+
fetchUrl,
|
|
758
|
+
requestAbortController,
|
|
759
|
+
headers: requestHeaders,
|
|
760
|
+
resumingFromPause
|
|
761
|
+
});
|
|
762
|
+
} catch (e) {
|
|
763
|
+
if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && requestAbortController.signal.aborted && requestAbortController.signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
|
|
764
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
765
|
+
}
|
|
766
|
+
if (e instanceof FetchBackoffAbortError) {
|
|
767
|
+
if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM) {
|
|
768
|
+
__privateSet(this, _state, `paused`);
|
|
769
|
+
}
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (!(e instanceof FetchError)) throw e;
|
|
773
|
+
if (e.status == 409) {
|
|
774
|
+
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
|
|
775
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
|
|
776
|
+
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
777
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
778
|
+
} else {
|
|
779
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
780
|
+
throw e;
|
|
781
|
+
}
|
|
782
|
+
} finally {
|
|
783
|
+
if (abortListener && signal) {
|
|
784
|
+
signal.removeEventListener(`abort`, abortListener);
|
|
785
|
+
}
|
|
786
|
+
__privateSet(this, _requestAbortController, void 0);
|
|
787
|
+
}
|
|
788
|
+
(_b = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _b.call(this);
|
|
789
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
790
|
+
});
|
|
791
|
+
};
|
|
792
|
+
constructUrl_fn = function(url, resumingFromPause) {
|
|
793
|
+
return __async(this, null, function* () {
|
|
732
794
|
const [requestHeaders, params] = yield Promise.all([
|
|
733
795
|
resolveHeaders(this.options.headers),
|
|
734
796
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
@@ -769,51 +831,32 @@ requestShape_fn = function() {
|
|
|
769
831
|
fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
|
|
770
832
|
}
|
|
771
833
|
fetchUrl.searchParams.sort();
|
|
834
|
+
return {
|
|
835
|
+
fetchUrl,
|
|
836
|
+
requestHeaders
|
|
837
|
+
};
|
|
838
|
+
});
|
|
839
|
+
};
|
|
840
|
+
createAbortListener_fn = function(signal) {
|
|
841
|
+
return __async(this, null, function* () {
|
|
842
|
+
var _a;
|
|
772
843
|
__privateSet(this, _requestAbortController, new AbortController());
|
|
773
|
-
let abortListener;
|
|
774
844
|
if (signal) {
|
|
775
|
-
abortListener = () => {
|
|
845
|
+
const abortListener = () => {
|
|
776
846
|
var _a2;
|
|
777
847
|
(_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
|
|
778
848
|
};
|
|
779
849
|
signal.addEventListener(`abort`, abortListener, { once: true });
|
|
780
850
|
if (signal.aborted) {
|
|
781
|
-
(
|
|
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;
|
|
851
|
+
(_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(signal.reason);
|
|
810
852
|
}
|
|
811
|
-
|
|
812
|
-
if (abortListener && signal) {
|
|
813
|
-
signal.removeEventListener(`abort`, abortListener);
|
|
814
|
-
}
|
|
815
|
-
__privateSet(this, _requestAbortController, void 0);
|
|
853
|
+
return abortListener;
|
|
816
854
|
}
|
|
855
|
+
});
|
|
856
|
+
};
|
|
857
|
+
onInitialResponse_fn = function(response) {
|
|
858
|
+
return __async(this, null, function* () {
|
|
859
|
+
var _a;
|
|
817
860
|
const { headers, status } = response;
|
|
818
861
|
const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
|
|
819
862
|
if (shapeHandle) {
|
|
@@ -831,22 +874,93 @@ requestShape_fn = function() {
|
|
|
831
874
|
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
832
875
|
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
833
876
|
};
|
|
834
|
-
__privateSet(this, _schema, (
|
|
877
|
+
__privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
|
|
835
878
|
if (status === 204) {
|
|
836
879
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
837
880
|
}
|
|
838
|
-
|
|
839
|
-
|
|
881
|
+
});
|
|
882
|
+
};
|
|
883
|
+
onMessages_fn = function(batch, isSseMessage = false) {
|
|
884
|
+
return __async(this, null, function* () {
|
|
840
885
|
if (batch.length > 0) {
|
|
841
886
|
const lastMessage = batch[batch.length - 1];
|
|
842
887
|
if (isUpToDateMessage(lastMessage)) {
|
|
888
|
+
if (isSseMessage) {
|
|
889
|
+
const offset = getOffset(lastMessage);
|
|
890
|
+
if (offset) {
|
|
891
|
+
__privateSet(this, _lastOffset, offset);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
843
894
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
844
895
|
__privateSet(this, _isUpToDate, true);
|
|
845
896
|
}
|
|
846
897
|
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
|
|
847
898
|
}
|
|
848
|
-
|
|
849
|
-
|
|
899
|
+
});
|
|
900
|
+
};
|
|
901
|
+
fetchShape_fn = function(opts) {
|
|
902
|
+
return __async(this, null, function* () {
|
|
903
|
+
if (__privateGet(this, _isUpToDate) && this.options.experimentalLiveSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
|
|
904
|
+
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
905
|
+
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
906
|
+
}
|
|
907
|
+
return __privateMethod(this, _ShapeStream_instances, requestShapeLongPoll_fn).call(this, opts);
|
|
908
|
+
});
|
|
909
|
+
};
|
|
910
|
+
requestShapeLongPoll_fn = function(opts) {
|
|
911
|
+
return __async(this, null, function* () {
|
|
912
|
+
const { fetchUrl, requestAbortController, headers } = opts;
|
|
913
|
+
const response = yield __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
|
|
914
|
+
signal: requestAbortController.signal,
|
|
915
|
+
headers
|
|
916
|
+
});
|
|
917
|
+
__privateSet(this, _connected, true);
|
|
918
|
+
yield __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
919
|
+
const schema = __privateGet(this, _schema);
|
|
920
|
+
const res = yield response.text();
|
|
921
|
+
const messages = res || `[]`;
|
|
922
|
+
const batch = __privateGet(this, _messageParser).parse(messages, schema);
|
|
923
|
+
yield __privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, batch);
|
|
924
|
+
});
|
|
925
|
+
};
|
|
926
|
+
requestShapeSSE_fn = function(opts) {
|
|
927
|
+
return __async(this, null, function* () {
|
|
928
|
+
const { fetchUrl, requestAbortController, headers } = opts;
|
|
929
|
+
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
930
|
+
try {
|
|
931
|
+
let buffer = [];
|
|
932
|
+
yield fetchEventSource(fetchUrl.toString(), {
|
|
933
|
+
headers,
|
|
934
|
+
fetch: fetch2,
|
|
935
|
+
onopen: (response) => __async(this, null, function* () {
|
|
936
|
+
__privateSet(this, _connected, true);
|
|
937
|
+
yield __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
938
|
+
}),
|
|
939
|
+
onmessage: (event) => {
|
|
940
|
+
if (event.data) {
|
|
941
|
+
const schema = __privateGet(this, _schema);
|
|
942
|
+
const message = __privateGet(this, _messageParser).parse(
|
|
943
|
+
event.data,
|
|
944
|
+
schema
|
|
945
|
+
);
|
|
946
|
+
buffer.push(message);
|
|
947
|
+
if (isUpToDateMessage(message)) {
|
|
948
|
+
__privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, buffer, true);
|
|
949
|
+
buffer = [];
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
onerror: (error) => {
|
|
954
|
+
throw error;
|
|
955
|
+
},
|
|
956
|
+
signal: requestAbortController.signal
|
|
957
|
+
});
|
|
958
|
+
} catch (error) {
|
|
959
|
+
if (requestAbortController.signal.aborted) {
|
|
960
|
+
throw new FetchBackoffAbortError();
|
|
961
|
+
}
|
|
962
|
+
throw error;
|
|
963
|
+
}
|
|
850
964
|
});
|
|
851
965
|
};
|
|
852
966
|
pause_fn = function() {
|
|
@@ -880,17 +994,20 @@ nextTick_fn = function() {
|
|
|
880
994
|
};
|
|
881
995
|
publish_fn = function(messages) {
|
|
882
996
|
return __async(this, null, function* () {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
997
|
+
__privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
|
|
998
|
+
() => Promise.all(
|
|
999
|
+
Array.from(__privateGet(this, _subscribers).values()).map((_0) => __async(this, [_0], function* ([callback, __]) {
|
|
1000
|
+
try {
|
|
1001
|
+
yield callback(messages);
|
|
1002
|
+
} catch (err) {
|
|
1003
|
+
queueMicrotask(() => {
|
|
1004
|
+
throw err;
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
}))
|
|
1008
|
+
)
|
|
1009
|
+
));
|
|
1010
|
+
return __privateGet(this, _messageChain);
|
|
894
1011
|
});
|
|
895
1012
|
};
|
|
896
1013
|
sendErrorToSubscribers_fn = function(error) {
|