@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.legacy-esm.js
CHANGED
|
@@ -245,6 +245,13 @@ function isControlMessage(message) {
|
|
|
245
245
|
function isUpToDateMessage(message) {
|
|
246
246
|
return isControlMessage(message) && message.headers.control === `up-to-date`;
|
|
247
247
|
}
|
|
248
|
+
function getOffset(message) {
|
|
249
|
+
const lsn = message.headers.global_last_seen_lsn;
|
|
250
|
+
if (!lsn) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
return `${lsn}_0`;
|
|
254
|
+
}
|
|
248
255
|
|
|
249
256
|
// src/constants.ts
|
|
250
257
|
var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
|
|
@@ -261,6 +268,7 @@ var TABLE_QUERY_PARAM = `table`;
|
|
|
261
268
|
var WHERE_QUERY_PARAM = `where`;
|
|
262
269
|
var REPLICA_PARAM = `replica`;
|
|
263
270
|
var WHERE_PARAMS_PARAM = `params`;
|
|
271
|
+
var EXPERIMENTAL_LIVE_SSE_QUERY_PARAM = `experimental_live_sse`;
|
|
264
272
|
var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
|
|
265
273
|
var PAUSE_STREAM = `pause-stream`;
|
|
266
274
|
|
|
@@ -289,7 +297,8 @@ function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
|
|
|
289
297
|
try {
|
|
290
298
|
const result = await fetchClient(...args);
|
|
291
299
|
if (result.ok) return result;
|
|
292
|
-
|
|
300
|
+
const err = await FetchError.fromResponse(result, url.toString());
|
|
301
|
+
throw err;
|
|
293
302
|
} catch (e) {
|
|
294
303
|
onFailedAttempt == null ? void 0 : onFailedAttempt();
|
|
295
304
|
if ((_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.aborted) {
|
|
@@ -487,6 +496,9 @@ function noop() {
|
|
|
487
496
|
}
|
|
488
497
|
|
|
489
498
|
// src/client.ts
|
|
499
|
+
import {
|
|
500
|
+
fetchEventSource
|
|
501
|
+
} from "@microsoft/fetch-event-source";
|
|
490
502
|
var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
491
503
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
492
504
|
SHAPE_HANDLE_QUERY_PARAM,
|
|
@@ -523,12 +535,14 @@ async function resolveHeaders(headers) {
|
|
|
523
535
|
);
|
|
524
536
|
return Object.fromEntries(resolvedEntries);
|
|
525
537
|
}
|
|
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;
|
|
538
|
+
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;
|
|
527
539
|
var ShapeStream = class {
|
|
540
|
+
// promise chain for incoming messages
|
|
528
541
|
constructor(options) {
|
|
529
542
|
__privateAdd(this, _ShapeStream_instances);
|
|
530
543
|
__privateAdd(this, _error, null);
|
|
531
544
|
__privateAdd(this, _fetchClient2);
|
|
545
|
+
__privateAdd(this, _sseFetchClient);
|
|
532
546
|
__privateAdd(this, _messageParser);
|
|
533
547
|
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
534
548
|
__privateAdd(this, _started, false);
|
|
@@ -548,6 +562,7 @@ var ShapeStream = class {
|
|
|
548
562
|
__privateAdd(this, _tickPromise);
|
|
549
563
|
__privateAdd(this, _tickPromiseResolver);
|
|
550
564
|
__privateAdd(this, _tickPromiseRejecter);
|
|
565
|
+
__privateAdd(this, _messageChain, Promise.resolve([]));
|
|
551
566
|
var _a, _b, _c;
|
|
552
567
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
553
568
|
validateOptions(this.options);
|
|
@@ -557,18 +572,21 @@ var ShapeStream = class {
|
|
|
557
572
|
__privateSet(this, _messageParser, new MessageParser(options.parser));
|
|
558
573
|
__privateSet(this, _onError, this.options.onError);
|
|
559
574
|
const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
|
|
560
|
-
const
|
|
575
|
+
const backOffOpts = __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
|
|
561
576
|
onFailedAttempt: () => {
|
|
562
577
|
var _a2, _b2;
|
|
563
578
|
__privateSet(this, _connected, false);
|
|
564
579
|
(_b2 = (_a2 = options.backoffOptions) == null ? void 0 : _a2.onFailedAttempt) == null ? void 0 : _b2.call(_a2);
|
|
565
580
|
}
|
|
566
|
-
})
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
581
|
+
});
|
|
582
|
+
const fetchWithBackoffClient = createFetchWithBackoff(
|
|
583
|
+
baseFetchClient,
|
|
584
|
+
backOffOpts
|
|
585
|
+
);
|
|
586
|
+
__privateSet(this, _sseFetchClient, createFetchWithResponseHeadersCheck(
|
|
587
|
+
createFetchWithChunkBuffer(fetchWithBackoffClient)
|
|
571
588
|
));
|
|
589
|
+
__privateSet(this, _fetchClient2, createFetchWithConsumedMessages(__privateGet(this, _sseFetchClient)));
|
|
572
590
|
__privateMethod(this, _ShapeStream_instances, subscribeToVisibilityChanges_fn).call(this);
|
|
573
591
|
}
|
|
574
592
|
get shapeHandle() {
|
|
@@ -636,6 +654,7 @@ var ShapeStream = class {
|
|
|
636
654
|
};
|
|
637
655
|
_error = new WeakMap();
|
|
638
656
|
_fetchClient2 = new WeakMap();
|
|
657
|
+
_sseFetchClient = new WeakMap();
|
|
639
658
|
_messageParser = new WeakMap();
|
|
640
659
|
_subscribers = new WeakMap();
|
|
641
660
|
_started = new WeakMap();
|
|
@@ -653,6 +672,7 @@ _isRefreshing = new WeakMap();
|
|
|
653
672
|
_tickPromise = new WeakMap();
|
|
654
673
|
_tickPromiseResolver = new WeakMap();
|
|
655
674
|
_tickPromiseRejecter = new WeakMap();
|
|
675
|
+
_messageChain = new WeakMap();
|
|
656
676
|
_ShapeStream_instances = new WeakSet();
|
|
657
677
|
start_fn = async function() {
|
|
658
678
|
var _a;
|
|
@@ -683,7 +703,7 @@ start_fn = async function() {
|
|
|
683
703
|
}
|
|
684
704
|
};
|
|
685
705
|
requestShape_fn = async function() {
|
|
686
|
-
var _a, _b
|
|
706
|
+
var _a, _b;
|
|
687
707
|
if (__privateGet(this, _state) === `pause-requested`) {
|
|
688
708
|
__privateSet(this, _state, `paused`);
|
|
689
709
|
return;
|
|
@@ -694,6 +714,46 @@ requestShape_fn = async function() {
|
|
|
694
714
|
const resumingFromPause = __privateGet(this, _state) === `paused`;
|
|
695
715
|
__privateSet(this, _state, `active`);
|
|
696
716
|
const { url, signal } = this.options;
|
|
717
|
+
const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, url, resumingFromPause);
|
|
718
|
+
const abortListener = await __privateMethod(this, _ShapeStream_instances, createAbortListener_fn).call(this, signal);
|
|
719
|
+
const requestAbortController = __privateGet(this, _requestAbortController);
|
|
720
|
+
try {
|
|
721
|
+
await __privateMethod(this, _ShapeStream_instances, fetchShape_fn).call(this, {
|
|
722
|
+
fetchUrl,
|
|
723
|
+
requestAbortController,
|
|
724
|
+
headers: requestHeaders,
|
|
725
|
+
resumingFromPause
|
|
726
|
+
});
|
|
727
|
+
} catch (e) {
|
|
728
|
+
if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && requestAbortController.signal.aborted && requestAbortController.signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
|
|
729
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
730
|
+
}
|
|
731
|
+
if (e instanceof FetchBackoffAbortError) {
|
|
732
|
+
if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM) {
|
|
733
|
+
__privateSet(this, _state, `paused`);
|
|
734
|
+
}
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
if (!(e instanceof FetchError)) throw e;
|
|
738
|
+
if (e.status == 409) {
|
|
739
|
+
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
|
|
740
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
|
|
741
|
+
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
742
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
743
|
+
} else {
|
|
744
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
745
|
+
throw e;
|
|
746
|
+
}
|
|
747
|
+
} finally {
|
|
748
|
+
if (abortListener && signal) {
|
|
749
|
+
signal.removeEventListener(`abort`, abortListener);
|
|
750
|
+
}
|
|
751
|
+
__privateSet(this, _requestAbortController, void 0);
|
|
752
|
+
}
|
|
753
|
+
(_b = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _b.call(this);
|
|
754
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
755
|
+
};
|
|
756
|
+
constructUrl_fn = async function(url, resumingFromPause) {
|
|
697
757
|
const [requestHeaders, params] = await Promise.all([
|
|
698
758
|
resolveHeaders(this.options.headers),
|
|
699
759
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
@@ -734,51 +794,28 @@ requestShape_fn = async function() {
|
|
|
734
794
|
fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
|
|
735
795
|
}
|
|
736
796
|
fetchUrl.searchParams.sort();
|
|
797
|
+
return {
|
|
798
|
+
fetchUrl,
|
|
799
|
+
requestHeaders
|
|
800
|
+
};
|
|
801
|
+
};
|
|
802
|
+
createAbortListener_fn = async function(signal) {
|
|
803
|
+
var _a;
|
|
737
804
|
__privateSet(this, _requestAbortController, new AbortController());
|
|
738
|
-
let abortListener;
|
|
739
805
|
if (signal) {
|
|
740
|
-
abortListener = () => {
|
|
806
|
+
const abortListener = () => {
|
|
741
807
|
var _a2;
|
|
742
808
|
(_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
|
|
743
809
|
};
|
|
744
810
|
signal.addEventListener(`abort`, abortListener, { once: true });
|
|
745
811
|
if (signal.aborted) {
|
|
746
|
-
(
|
|
812
|
+
(_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(signal.reason);
|
|
747
813
|
}
|
|
814
|
+
return abortListener;
|
|
748
815
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
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
|
-
}
|
|
816
|
+
};
|
|
817
|
+
onInitialResponse_fn = async function(response) {
|
|
818
|
+
var _a;
|
|
782
819
|
const { headers, status } = response;
|
|
783
820
|
const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
|
|
784
821
|
if (shapeHandle) {
|
|
@@ -796,22 +833,85 @@ requestShape_fn = async function() {
|
|
|
796
833
|
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
797
834
|
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
798
835
|
};
|
|
799
|
-
__privateSet(this, _schema, (
|
|
836
|
+
__privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
|
|
800
837
|
if (status === 204) {
|
|
801
838
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
802
839
|
}
|
|
803
|
-
|
|
804
|
-
|
|
840
|
+
};
|
|
841
|
+
onMessages_fn = async function(batch, isSseMessage = false) {
|
|
805
842
|
if (batch.length > 0) {
|
|
806
843
|
const lastMessage = batch[batch.length - 1];
|
|
807
844
|
if (isUpToDateMessage(lastMessage)) {
|
|
845
|
+
if (isSseMessage) {
|
|
846
|
+
const offset = getOffset(lastMessage);
|
|
847
|
+
if (offset) {
|
|
848
|
+
__privateSet(this, _lastOffset, offset);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
808
851
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
809
852
|
__privateSet(this, _isUpToDate, true);
|
|
810
853
|
}
|
|
811
854
|
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
|
|
812
855
|
}
|
|
813
|
-
|
|
814
|
-
|
|
856
|
+
};
|
|
857
|
+
fetchShape_fn = async function(opts) {
|
|
858
|
+
if (__privateGet(this, _isUpToDate) && this.options.experimentalLiveSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
|
|
859
|
+
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
860
|
+
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
861
|
+
}
|
|
862
|
+
return __privateMethod(this, _ShapeStream_instances, requestShapeLongPoll_fn).call(this, opts);
|
|
863
|
+
};
|
|
864
|
+
requestShapeLongPoll_fn = async function(opts) {
|
|
865
|
+
const { fetchUrl, requestAbortController, headers } = opts;
|
|
866
|
+
const response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
|
|
867
|
+
signal: requestAbortController.signal,
|
|
868
|
+
headers
|
|
869
|
+
});
|
|
870
|
+
__privateSet(this, _connected, true);
|
|
871
|
+
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
872
|
+
const schema = __privateGet(this, _schema);
|
|
873
|
+
const res = await response.text();
|
|
874
|
+
const messages = res || `[]`;
|
|
875
|
+
const batch = __privateGet(this, _messageParser).parse(messages, schema);
|
|
876
|
+
await __privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, batch);
|
|
877
|
+
};
|
|
878
|
+
requestShapeSSE_fn = async function(opts) {
|
|
879
|
+
const { fetchUrl, requestAbortController, headers } = opts;
|
|
880
|
+
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
881
|
+
try {
|
|
882
|
+
let buffer = [];
|
|
883
|
+
await fetchEventSource(fetchUrl.toString(), {
|
|
884
|
+
headers,
|
|
885
|
+
fetch: fetch2,
|
|
886
|
+
onopen: async (response) => {
|
|
887
|
+
__privateSet(this, _connected, true);
|
|
888
|
+
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
889
|
+
},
|
|
890
|
+
onmessage: (event) => {
|
|
891
|
+
if (event.data) {
|
|
892
|
+
const schema = __privateGet(this, _schema);
|
|
893
|
+
const message = __privateGet(this, _messageParser).parse(
|
|
894
|
+
event.data,
|
|
895
|
+
schema
|
|
896
|
+
);
|
|
897
|
+
buffer.push(message);
|
|
898
|
+
if (isUpToDateMessage(message)) {
|
|
899
|
+
__privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, buffer, true);
|
|
900
|
+
buffer = [];
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
onerror: (error) => {
|
|
905
|
+
throw error;
|
|
906
|
+
},
|
|
907
|
+
signal: requestAbortController.signal
|
|
908
|
+
});
|
|
909
|
+
} catch (error) {
|
|
910
|
+
if (requestAbortController.signal.aborted) {
|
|
911
|
+
throw new FetchBackoffAbortError();
|
|
912
|
+
}
|
|
913
|
+
throw error;
|
|
914
|
+
}
|
|
815
915
|
};
|
|
816
916
|
pause_fn = function() {
|
|
817
917
|
var _a;
|
|
@@ -841,17 +941,20 @@ nextTick_fn = async function() {
|
|
|
841
941
|
return __privateGet(this, _tickPromise);
|
|
842
942
|
};
|
|
843
943
|
publish_fn = async function(messages) {
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
944
|
+
__privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
|
|
945
|
+
() => Promise.all(
|
|
946
|
+
Array.from(__privateGet(this, _subscribers).values()).map(async ([callback, __]) => {
|
|
947
|
+
try {
|
|
948
|
+
await callback(messages);
|
|
949
|
+
} catch (err) {
|
|
950
|
+
queueMicrotask(() => {
|
|
951
|
+
throw err;
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
})
|
|
955
|
+
)
|
|
956
|
+
));
|
|
957
|
+
return __privateGet(this, _messageChain);
|
|
855
958
|
};
|
|
856
959
|
sendErrorToSubscribers_fn = function(error) {
|
|
857
960
|
__privateGet(this, _subscribers).forEach(([_, errorFn]) => {
|