@electric-sql/client 1.0.4 → 1.0.5
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 -58
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +28 -8
- package/dist/index.browser.mjs +3 -3
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +28 -8
- package/dist/index.legacy-esm.js +164 -58
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +178 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -3
- package/src/client.ts +252 -85
- package/src/constants.ts +1 -0
- package/src/fetch.ts +12 -2
- package/src/helpers.ts +13 -1
- package/src/types.ts +4 -1
package/dist/index.legacy-esm.js
CHANGED
|
@@ -245,6 +245,12 @@ 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 = Number(message.headers.global_last_seen_lsn);
|
|
250
|
+
if (lsn && !isNaN(lsn)) {
|
|
251
|
+
return `${lsn}_0`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
248
254
|
|
|
249
255
|
// src/constants.ts
|
|
250
256
|
var LIVE_CACHE_BUSTER_HEADER = `electric-cursor`;
|
|
@@ -261,6 +267,7 @@ var TABLE_QUERY_PARAM = `table`;
|
|
|
261
267
|
var WHERE_QUERY_PARAM = `where`;
|
|
262
268
|
var REPLICA_PARAM = `replica`;
|
|
263
269
|
var WHERE_PARAMS_PARAM = `params`;
|
|
270
|
+
var EXPERIMENTAL_LIVE_SSE_QUERY_PARAM = `experimental_live_sse`;
|
|
264
271
|
var FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`;
|
|
265
272
|
var PAUSE_STREAM = `pause-stream`;
|
|
266
273
|
|
|
@@ -271,7 +278,7 @@ var BackoffDefaults = {
|
|
|
271
278
|
maxDelay: 1e4,
|
|
272
279
|
multiplier: 1.3
|
|
273
280
|
};
|
|
274
|
-
function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
|
|
281
|
+
function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults, sseMode = false) {
|
|
275
282
|
const {
|
|
276
283
|
initialDelay,
|
|
277
284
|
maxDelay,
|
|
@@ -289,7 +296,11 @@ function createFetchWithBackoff(fetchClient, backoffOptions = BackoffDefaults) {
|
|
|
289
296
|
try {
|
|
290
297
|
const result = await fetchClient(...args);
|
|
291
298
|
if (result.ok) return result;
|
|
292
|
-
|
|
299
|
+
const err = await FetchError.fromResponse(result, url.toString());
|
|
300
|
+
if (err.status === 409 && sseMode) {
|
|
301
|
+
err.json = [err.json];
|
|
302
|
+
}
|
|
303
|
+
throw err;
|
|
293
304
|
} catch (e) {
|
|
294
305
|
onFailedAttempt == null ? void 0 : onFailedAttempt();
|
|
295
306
|
if ((_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.aborted) {
|
|
@@ -487,6 +498,9 @@ function noop() {
|
|
|
487
498
|
}
|
|
488
499
|
|
|
489
500
|
// src/client.ts
|
|
501
|
+
import {
|
|
502
|
+
fetchEventSource
|
|
503
|
+
} from "@microsoft/fetch-event-source";
|
|
490
504
|
var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
491
505
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
492
506
|
SHAPE_HANDLE_QUERY_PARAM,
|
|
@@ -523,12 +537,14 @@ async function resolveHeaders(headers) {
|
|
|
523
537
|
);
|
|
524
538
|
return Object.fromEntries(resolvedEntries);
|
|
525
539
|
}
|
|
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;
|
|
540
|
+
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
541
|
var ShapeStream = class {
|
|
542
|
+
// promise chain for incoming messages
|
|
528
543
|
constructor(options) {
|
|
529
544
|
__privateAdd(this, _ShapeStream_instances);
|
|
530
545
|
__privateAdd(this, _error, null);
|
|
531
546
|
__privateAdd(this, _fetchClient2);
|
|
547
|
+
__privateAdd(this, _sseFetchClient);
|
|
532
548
|
__privateAdd(this, _messageParser);
|
|
533
549
|
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
534
550
|
__privateAdd(this, _started, false);
|
|
@@ -548,6 +564,7 @@ var ShapeStream = class {
|
|
|
548
564
|
__privateAdd(this, _tickPromise);
|
|
549
565
|
__privateAdd(this, _tickPromiseResolver);
|
|
550
566
|
__privateAdd(this, _tickPromiseRejecter);
|
|
567
|
+
__privateAdd(this, _messageChain, Promise.resolve([]));
|
|
551
568
|
var _a, _b, _c;
|
|
552
569
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
553
570
|
validateOptions(this.options);
|
|
@@ -557,18 +574,30 @@ var ShapeStream = class {
|
|
|
557
574
|
__privateSet(this, _messageParser, new MessageParser(options.parser));
|
|
558
575
|
__privateSet(this, _onError, this.options.onError);
|
|
559
576
|
const baseFetchClient = (_b = options.fetchClient) != null ? _b : (...args) => fetch(...args);
|
|
560
|
-
const
|
|
577
|
+
const backOffOpts = __spreadProps(__spreadValues({}, (_c = options.backoffOptions) != null ? _c : BackoffDefaults), {
|
|
561
578
|
onFailedAttempt: () => {
|
|
562
579
|
var _a2, _b2;
|
|
563
580
|
__privateSet(this, _connected, false);
|
|
564
581
|
(_b2 = (_a2 = options.backoffOptions) == null ? void 0 : _a2.onFailedAttempt) == null ? void 0 : _b2.call(_a2);
|
|
565
582
|
}
|
|
566
|
-
})
|
|
583
|
+
});
|
|
584
|
+
const fetchWithBackoffClient = createFetchWithBackoff(
|
|
585
|
+
baseFetchClient,
|
|
586
|
+
backOffOpts
|
|
587
|
+
);
|
|
567
588
|
__privateSet(this, _fetchClient2, createFetchWithConsumedMessages(
|
|
568
589
|
createFetchWithResponseHeadersCheck(
|
|
569
590
|
createFetchWithChunkBuffer(fetchWithBackoffClient)
|
|
570
591
|
)
|
|
571
592
|
));
|
|
593
|
+
const sseFetchWithBackoffClient = createFetchWithBackoff(
|
|
594
|
+
baseFetchClient,
|
|
595
|
+
backOffOpts,
|
|
596
|
+
true
|
|
597
|
+
);
|
|
598
|
+
__privateSet(this, _sseFetchClient, createFetchWithResponseHeadersCheck(
|
|
599
|
+
createFetchWithChunkBuffer(sseFetchWithBackoffClient)
|
|
600
|
+
));
|
|
572
601
|
__privateMethod(this, _ShapeStream_instances, subscribeToVisibilityChanges_fn).call(this);
|
|
573
602
|
}
|
|
574
603
|
get shapeHandle() {
|
|
@@ -636,6 +665,7 @@ var ShapeStream = class {
|
|
|
636
665
|
};
|
|
637
666
|
_error = new WeakMap();
|
|
638
667
|
_fetchClient2 = new WeakMap();
|
|
668
|
+
_sseFetchClient = new WeakMap();
|
|
639
669
|
_messageParser = new WeakMap();
|
|
640
670
|
_subscribers = new WeakMap();
|
|
641
671
|
_started = new WeakMap();
|
|
@@ -653,6 +683,7 @@ _isRefreshing = new WeakMap();
|
|
|
653
683
|
_tickPromise = new WeakMap();
|
|
654
684
|
_tickPromiseResolver = new WeakMap();
|
|
655
685
|
_tickPromiseRejecter = new WeakMap();
|
|
686
|
+
_messageChain = new WeakMap();
|
|
656
687
|
_ShapeStream_instances = new WeakSet();
|
|
657
688
|
start_fn = async function() {
|
|
658
689
|
var _a;
|
|
@@ -683,7 +714,7 @@ start_fn = async function() {
|
|
|
683
714
|
}
|
|
684
715
|
};
|
|
685
716
|
requestShape_fn = async function() {
|
|
686
|
-
var _a, _b
|
|
717
|
+
var _a, _b;
|
|
687
718
|
if (__privateGet(this, _state) === `pause-requested`) {
|
|
688
719
|
__privateSet(this, _state, `paused`);
|
|
689
720
|
return;
|
|
@@ -694,6 +725,46 @@ requestShape_fn = async function() {
|
|
|
694
725
|
const resumingFromPause = __privateGet(this, _state) === `paused`;
|
|
695
726
|
__privateSet(this, _state, `active`);
|
|
696
727
|
const { url, signal } = this.options;
|
|
728
|
+
const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, url, resumingFromPause);
|
|
729
|
+
const abortListener = await __privateMethod(this, _ShapeStream_instances, createAbortListener_fn).call(this, signal);
|
|
730
|
+
const requestAbortController = __privateGet(this, _requestAbortController);
|
|
731
|
+
try {
|
|
732
|
+
await __privateMethod(this, _ShapeStream_instances, fetchShape_fn).call(this, {
|
|
733
|
+
fetchUrl,
|
|
734
|
+
requestAbortController,
|
|
735
|
+
headers: requestHeaders,
|
|
736
|
+
resumingFromPause: true
|
|
737
|
+
});
|
|
738
|
+
} catch (e) {
|
|
739
|
+
if ((e instanceof FetchError || e instanceof FetchBackoffAbortError) && requestAbortController.signal.aborted && requestAbortController.signal.reason === FORCE_DISCONNECT_AND_REFRESH) {
|
|
740
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
741
|
+
}
|
|
742
|
+
if (e instanceof FetchBackoffAbortError) {
|
|
743
|
+
if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM) {
|
|
744
|
+
__privateSet(this, _state, `paused`);
|
|
745
|
+
}
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
if (!(e instanceof FetchError)) throw e;
|
|
749
|
+
if (e.status == 409) {
|
|
750
|
+
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER];
|
|
751
|
+
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
|
|
752
|
+
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, e.json);
|
|
753
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
754
|
+
} else {
|
|
755
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
756
|
+
throw e;
|
|
757
|
+
}
|
|
758
|
+
} finally {
|
|
759
|
+
if (abortListener && signal) {
|
|
760
|
+
signal.removeEventListener(`abort`, abortListener);
|
|
761
|
+
}
|
|
762
|
+
__privateSet(this, _requestAbortController, void 0);
|
|
763
|
+
}
|
|
764
|
+
(_b = __privateGet(this, _tickPromiseResolver)) == null ? void 0 : _b.call(this);
|
|
765
|
+
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
766
|
+
};
|
|
767
|
+
constructUrl_fn = async function(url, resumingFromPause) {
|
|
697
768
|
const [requestHeaders, params] = await Promise.all([
|
|
698
769
|
resolveHeaders(this.options.headers),
|
|
699
770
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
@@ -734,51 +805,28 @@ requestShape_fn = async function() {
|
|
|
734
805
|
fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
|
|
735
806
|
}
|
|
736
807
|
fetchUrl.searchParams.sort();
|
|
808
|
+
return {
|
|
809
|
+
fetchUrl,
|
|
810
|
+
requestHeaders
|
|
811
|
+
};
|
|
812
|
+
};
|
|
813
|
+
createAbortListener_fn = async function(signal) {
|
|
814
|
+
var _a;
|
|
737
815
|
__privateSet(this, _requestAbortController, new AbortController());
|
|
738
|
-
let abortListener;
|
|
739
816
|
if (signal) {
|
|
740
|
-
abortListener = () => {
|
|
817
|
+
const abortListener = () => {
|
|
741
818
|
var _a2;
|
|
742
819
|
(_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(signal.reason);
|
|
743
820
|
};
|
|
744
821
|
signal.addEventListener(`abort`, abortListener, { once: true });
|
|
745
822
|
if (signal.aborted) {
|
|
746
|
-
(
|
|
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;
|
|
823
|
+
(_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(signal.reason);
|
|
775
824
|
}
|
|
776
|
-
|
|
777
|
-
if (abortListener && signal) {
|
|
778
|
-
signal.removeEventListener(`abort`, abortListener);
|
|
779
|
-
}
|
|
780
|
-
__privateSet(this, _requestAbortController, void 0);
|
|
825
|
+
return abortListener;
|
|
781
826
|
}
|
|
827
|
+
};
|
|
828
|
+
onInitialResponse_fn = async function(response) {
|
|
829
|
+
var _a;
|
|
782
830
|
const { headers, status } = response;
|
|
783
831
|
const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
|
|
784
832
|
if (shapeHandle) {
|
|
@@ -796,22 +844,77 @@ requestShape_fn = async function() {
|
|
|
796
844
|
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
797
845
|
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
798
846
|
};
|
|
799
|
-
__privateSet(this, _schema, (
|
|
847
|
+
__privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
|
|
800
848
|
if (status === 204) {
|
|
801
849
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
802
850
|
}
|
|
803
|
-
|
|
804
|
-
|
|
851
|
+
};
|
|
852
|
+
onMessages_fn = async function(messages, schema, isSseMessage = false) {
|
|
853
|
+
const batch = __privateGet(this, _messageParser).parse(messages, schema);
|
|
805
854
|
if (batch.length > 0) {
|
|
806
855
|
const lastMessage = batch[batch.length - 1];
|
|
807
856
|
if (isUpToDateMessage(lastMessage)) {
|
|
857
|
+
if (isSseMessage) {
|
|
858
|
+
const offset = getOffset(lastMessage);
|
|
859
|
+
if (offset) {
|
|
860
|
+
__privateSet(this, _lastOffset, offset);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
808
863
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
809
864
|
__privateSet(this, _isUpToDate, true);
|
|
810
865
|
}
|
|
811
866
|
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, batch);
|
|
812
867
|
}
|
|
813
|
-
|
|
814
|
-
|
|
868
|
+
};
|
|
869
|
+
fetchShape_fn = async function(opts) {
|
|
870
|
+
if (__privateGet(this, _isUpToDate) && this.options.experimentalLiveSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
|
|
871
|
+
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
872
|
+
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
873
|
+
}
|
|
874
|
+
return __privateMethod(this, _ShapeStream_instances, requestShapeLongPoll_fn).call(this, opts);
|
|
875
|
+
};
|
|
876
|
+
requestShapeLongPoll_fn = async function(opts) {
|
|
877
|
+
const { fetchUrl, requestAbortController, headers } = opts;
|
|
878
|
+
const response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
|
|
879
|
+
signal: requestAbortController.signal,
|
|
880
|
+
headers
|
|
881
|
+
});
|
|
882
|
+
__privateSet(this, _connected, true);
|
|
883
|
+
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
884
|
+
const schema = __privateGet(this, _schema);
|
|
885
|
+
const res = await response.text();
|
|
886
|
+
const messages = res || `[]`;
|
|
887
|
+
await __privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, messages, schema);
|
|
888
|
+
};
|
|
889
|
+
requestShapeSSE_fn = async function(opts) {
|
|
890
|
+
const { fetchUrl, requestAbortController, headers } = opts;
|
|
891
|
+
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
892
|
+
try {
|
|
893
|
+
await fetchEventSource(fetchUrl.toString(), {
|
|
894
|
+
headers,
|
|
895
|
+
fetch: fetch2,
|
|
896
|
+
onopen: async (response) => {
|
|
897
|
+
__privateSet(this, _connected, true);
|
|
898
|
+
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
899
|
+
},
|
|
900
|
+
onmessage: (event) => {
|
|
901
|
+
if (event.data) {
|
|
902
|
+
const messages = `[${event.data}]`;
|
|
903
|
+
const schema = __privateGet(this, _schema);
|
|
904
|
+
__privateMethod(this, _ShapeStream_instances, onMessages_fn).call(this, messages, schema, true);
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
onerror: (error) => {
|
|
908
|
+
throw error;
|
|
909
|
+
},
|
|
910
|
+
signal: requestAbortController.signal
|
|
911
|
+
});
|
|
912
|
+
} catch (error) {
|
|
913
|
+
if (requestAbortController.signal.aborted) {
|
|
914
|
+
throw new FetchBackoffAbortError();
|
|
915
|
+
}
|
|
916
|
+
throw error;
|
|
917
|
+
}
|
|
815
918
|
};
|
|
816
919
|
pause_fn = function() {
|
|
817
920
|
var _a;
|
|
@@ -841,17 +944,20 @@ nextTick_fn = async function() {
|
|
|
841
944
|
return __privateGet(this, _tickPromise);
|
|
842
945
|
};
|
|
843
946
|
publish_fn = async function(messages) {
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
947
|
+
__privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
|
|
948
|
+
() => Promise.all(
|
|
949
|
+
Array.from(__privateGet(this, _subscribers).values()).map(async ([callback, __]) => {
|
|
950
|
+
try {
|
|
951
|
+
await callback(messages);
|
|
952
|
+
} catch (err) {
|
|
953
|
+
queueMicrotask(() => {
|
|
954
|
+
throw err;
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
})
|
|
958
|
+
)
|
|
959
|
+
));
|
|
960
|
+
return __privateGet(this, _messageChain);
|
|
855
961
|
};
|
|
856
962
|
sendErrorToSubscribers_fn = function(error) {
|
|
857
963
|
__privateGet(this, _subscribers).forEach(([_, errorFn]) => {
|