@electric-sql/client 1.1.3 → 1.1.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 +95 -41
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +17 -8
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +17 -8
- package/dist/index.legacy-esm.js +93 -39
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +95 -41
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +96 -34
- package/src/parser.ts +45 -7
package/dist/index.d.ts
CHANGED
|
@@ -368,16 +368,14 @@ interface ShapeStreamInterface<T extends Row<unknown> = Row> {
|
|
|
368
368
|
error?: unknown;
|
|
369
369
|
mode: LogMode;
|
|
370
370
|
forceDisconnectAndRefresh(): Promise<void>;
|
|
371
|
-
requestSnapshot(params: {
|
|
372
|
-
where?: string;
|
|
373
|
-
params?: Record<string, string>;
|
|
374
|
-
limit: number;
|
|
375
|
-
offset?: number;
|
|
376
|
-
orderBy: string;
|
|
377
|
-
}): Promise<{
|
|
371
|
+
requestSnapshot(params: SubsetParams): Promise<{
|
|
378
372
|
metadata: SnapshotMetadata;
|
|
379
373
|
data: Array<Message<T>>;
|
|
380
374
|
}>;
|
|
375
|
+
fetchSnapshot(opts: SubsetParams): Promise<{
|
|
376
|
+
metadata: SnapshotMetadata;
|
|
377
|
+
data: Array<ChangeMessage<T>>;
|
|
378
|
+
}>;
|
|
381
379
|
}
|
|
382
380
|
/**
|
|
383
381
|
* Reads updates to a shape from Electric using HTTP requests and long polling or
|
|
@@ -451,7 +449,7 @@ declare class ShapeStream<T extends Row<unknown> = Row> implements ShapeStreamIn
|
|
|
451
449
|
*/
|
|
452
450
|
forceDisconnectAndRefresh(): Promise<void>;
|
|
453
451
|
/**
|
|
454
|
-
* Request a snapshot for subset of data.
|
|
452
|
+
* Request a snapshot for subset of data and inject it into the subscribed data stream.
|
|
455
453
|
*
|
|
456
454
|
* Only available when mode is `changes_only`.
|
|
457
455
|
* Returns the insertion point & the data, but more importantly injects the data
|
|
@@ -468,6 +466,17 @@ declare class ShapeStream<T extends Row<unknown> = Row> implements ShapeStreamIn
|
|
|
468
466
|
metadata: SnapshotMetadata;
|
|
469
467
|
data: Array<ChangeMessage<T>>;
|
|
470
468
|
}>;
|
|
469
|
+
/**
|
|
470
|
+
* Fetch a snapshot for subset of data.
|
|
471
|
+
* Returns the metadata and the data, but does not inject it into the subscribed data stream.
|
|
472
|
+
*
|
|
473
|
+
* @param opts - The options for the snapshot request.
|
|
474
|
+
* @returns The metadata and the data for the snapshot.
|
|
475
|
+
*/
|
|
476
|
+
fetchSnapshot(opts: SubsetParams): Promise<{
|
|
477
|
+
metadata: SnapshotMetadata;
|
|
478
|
+
data: Array<ChangeMessage<T>>;
|
|
479
|
+
}>;
|
|
471
480
|
}
|
|
472
481
|
|
|
473
482
|
type ShapeData<T extends Row<unknown> = Row> = Map<string, T>;
|
package/dist/index.legacy-esm.js
CHANGED
|
@@ -203,15 +203,37 @@ var MessageParser = class {
|
|
|
203
203
|
parse(messages, schema) {
|
|
204
204
|
return JSON.parse(messages, (key, value) => {
|
|
205
205
|
if ((key === `value` || key === `old_value`) && typeof value === `object` && value !== null) {
|
|
206
|
-
|
|
207
|
-
Object.keys(row).forEach((key2) => {
|
|
208
|
-
row[key2] = this.parseRow(key2, row[key2], schema);
|
|
209
|
-
});
|
|
210
|
-
if (this.transformer) value = this.transformer(value);
|
|
206
|
+
return this.transformMessageValue(value, schema);
|
|
211
207
|
}
|
|
212
208
|
return value;
|
|
213
209
|
});
|
|
214
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Parse an array of ChangeMessages from a snapshot response.
|
|
213
|
+
* Applies type parsing and transformations to the value and old_value properties.
|
|
214
|
+
*/
|
|
215
|
+
parseSnapshotData(messages, schema) {
|
|
216
|
+
return messages.map((message) => {
|
|
217
|
+
const msg = message;
|
|
218
|
+
if (msg.value && typeof msg.value === `object` && msg.value !== null) {
|
|
219
|
+
msg.value = this.transformMessageValue(msg.value, schema);
|
|
220
|
+
}
|
|
221
|
+
if (msg.old_value && typeof msg.old_value === `object` && msg.old_value !== null) {
|
|
222
|
+
msg.old_value = this.transformMessageValue(msg.old_value, schema);
|
|
223
|
+
}
|
|
224
|
+
return msg;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Transform a message value or old_value object by parsing its columns.
|
|
229
|
+
*/
|
|
230
|
+
transformMessageValue(value, schema) {
|
|
231
|
+
const row = value;
|
|
232
|
+
Object.keys(row).forEach((key) => {
|
|
233
|
+
row[key] = this.parseRow(key, row[key], schema);
|
|
234
|
+
});
|
|
235
|
+
return this.transformer ? this.transformer(row) : row;
|
|
236
|
+
}
|
|
215
237
|
// Parses the message values using the provided parser based on the schema information
|
|
216
238
|
parseRow(key, value, schema) {
|
|
217
239
|
var _b;
|
|
@@ -751,9 +773,8 @@ function canonicalShapeKey(url) {
|
|
|
751
773
|
cleanUrl.searchParams.sort();
|
|
752
774
|
return cleanUrl.toString();
|
|
753
775
|
}
|
|
754
|
-
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _isMidStream, _connected, _shapeHandle, _mode, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _snapshotTracker, _activeSnapshotRequests, _midStreamPromise, _midStreamPromiseResolver, _lastSseConnectionStartTime, _minSseConnectionDuration, _consecutiveShortSseConnections, _maxShortSseConnections, _sseFallbackToLongPolling, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _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, waitForStreamEnd_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn
|
|
776
|
+
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _isMidStream, _connected, _shapeHandle, _mode, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _snapshotTracker, _activeSnapshotRequests, _midStreamPromise, _midStreamPromiseResolver, _lastSseConnectionStartTime, _minSseConnectionDuration, _consecutiveShortSseConnections, _maxShortSseConnections, _sseFallbackToLongPolling, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _unsubscribeFromVisibilityChanges, _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, waitForStreamEnd_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn;
|
|
755
777
|
var ShapeStream = class {
|
|
756
|
-
// Maximum delay cap (ms)
|
|
757
778
|
constructor(options) {
|
|
758
779
|
__privateAdd(this, _ShapeStream_instances);
|
|
759
780
|
__privateAdd(this, _error, null);
|
|
@@ -797,6 +818,8 @@ var ShapeStream = class {
|
|
|
797
818
|
__privateAdd(this, _sseBackoffBaseDelay, 100);
|
|
798
819
|
// Base delay for exponential backoff (ms)
|
|
799
820
|
__privateAdd(this, _sseBackoffMaxDelay, 5e3);
|
|
821
|
+
// Maximum delay cap (ms)
|
|
822
|
+
__privateAdd(this, _unsubscribeFromVisibilityChanges);
|
|
800
823
|
var _a, _b, _c, _d;
|
|
801
824
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
802
825
|
validateOptions(this.options);
|
|
@@ -852,7 +875,9 @@ var ShapeStream = class {
|
|
|
852
875
|
};
|
|
853
876
|
}
|
|
854
877
|
unsubscribeAll() {
|
|
878
|
+
var _a;
|
|
855
879
|
__privateGet(this, _subscribers).clear();
|
|
880
|
+
(_a = __privateGet(this, _unsubscribeFromVisibilityChanges)) == null ? void 0 : _a.call(this);
|
|
856
881
|
}
|
|
857
882
|
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
858
883
|
lastSyncedAt() {
|
|
@@ -893,7 +918,7 @@ var ShapeStream = class {
|
|
|
893
918
|
__privateSet(this, _isRefreshing, false);
|
|
894
919
|
}
|
|
895
920
|
/**
|
|
896
|
-
* Request a snapshot for subset of data.
|
|
921
|
+
* Request a snapshot for subset of data and inject it into the subscribed data stream.
|
|
897
922
|
*
|
|
898
923
|
* Only available when mode is `changes_only`.
|
|
899
924
|
* Returns the insertion point & the data, but more importantly injects the data
|
|
@@ -919,8 +944,7 @@ var ShapeStream = class {
|
|
|
919
944
|
if (__privateGet(this, _activeSnapshotRequests) === 1) {
|
|
920
945
|
__privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
|
|
921
946
|
}
|
|
922
|
-
const {
|
|
923
|
-
const { metadata, data } = await __privateMethod(this, _ShapeStream_instances, fetchSnapshot_fn).call(this, fetchUrl, requestHeaders);
|
|
947
|
+
const { metadata, data } = await this.fetchSnapshot(opts);
|
|
924
948
|
const dataWithEndBoundary = data.concat([
|
|
925
949
|
{ headers: __spreadValues({ control: `snapshot-end` }, metadata) }
|
|
926
950
|
]);
|
|
@@ -940,6 +964,42 @@ var ShapeStream = class {
|
|
|
940
964
|
}
|
|
941
965
|
}
|
|
942
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* Fetch a snapshot for subset of data.
|
|
969
|
+
* Returns the metadata and the data, but does not inject it into the subscribed data stream.
|
|
970
|
+
*
|
|
971
|
+
* @param opts - The options for the snapshot request.
|
|
972
|
+
* @returns The metadata and the data for the snapshot.
|
|
973
|
+
*/
|
|
974
|
+
async fetchSnapshot(opts) {
|
|
975
|
+
var _a;
|
|
976
|
+
const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
|
|
977
|
+
const response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
|
|
978
|
+
headers: requestHeaders
|
|
979
|
+
});
|
|
980
|
+
if (!response.ok) {
|
|
981
|
+
throw new FetchError(
|
|
982
|
+
response.status,
|
|
983
|
+
void 0,
|
|
984
|
+
void 0,
|
|
985
|
+
Object.fromEntries([...response.headers.entries()]),
|
|
986
|
+
fetchUrl.toString()
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
const schema = (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(response.headers, {
|
|
990
|
+
required: true,
|
|
991
|
+
url: fetchUrl.toString()
|
|
992
|
+
});
|
|
993
|
+
const { metadata, data: rawData } = await response.json();
|
|
994
|
+
const data = __privateGet(this, _messageParser).parseSnapshotData(
|
|
995
|
+
rawData,
|
|
996
|
+
schema
|
|
997
|
+
);
|
|
998
|
+
return {
|
|
999
|
+
metadata,
|
|
1000
|
+
data
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
943
1003
|
};
|
|
944
1004
|
_error = new WeakMap();
|
|
945
1005
|
_fetchClient2 = new WeakMap();
|
|
@@ -975,6 +1035,7 @@ _maxShortSseConnections = new WeakMap();
|
|
|
975
1035
|
_sseFallbackToLongPolling = new WeakMap();
|
|
976
1036
|
_sseBackoffBaseDelay = new WeakMap();
|
|
977
1037
|
_sseBackoffMaxDelay = new WeakMap();
|
|
1038
|
+
_unsubscribeFromVisibilityChanges = new WeakMap();
|
|
978
1039
|
_ShapeStream_instances = new WeakSet();
|
|
979
1040
|
start_fn = async function() {
|
|
980
1041
|
var _a, _b, _c, _d, _e;
|
|
@@ -1041,7 +1102,8 @@ requestShape_fn = async function() {
|
|
|
1041
1102
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1042
1103
|
}
|
|
1043
1104
|
if (e instanceof FetchBackoffAbortError) {
|
|
1044
|
-
|
|
1105
|
+
const currentState = __privateGet(this, _state);
|
|
1106
|
+
if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM && currentState === `pause-requested`) {
|
|
1045
1107
|
__privateSet(this, _state, `paused`);
|
|
1046
1108
|
}
|
|
1047
1109
|
return;
|
|
@@ -1107,7 +1169,8 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
|
1107
1169
|
}
|
|
1108
1170
|
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
1109
1171
|
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
1110
|
-
|
|
1172
|
+
const isSnapshotRequest = subsetParams !== void 0;
|
|
1173
|
+
if (__privateGet(this, _isUpToDate) && !isSnapshotRequest) {
|
|
1111
1174
|
if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
|
|
1112
1175
|
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
1113
1176
|
}
|
|
@@ -1160,11 +1223,7 @@ onInitialResponse_fn = async function(response) {
|
|
|
1160
1223
|
if (liveCacheBuster) {
|
|
1161
1224
|
__privateSet(this, _liveCacheBuster, liveCacheBuster);
|
|
1162
1225
|
}
|
|
1163
|
-
|
|
1164
|
-
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
1165
|
-
return schemaHeader ? JSON.parse(schemaHeader) : {};
|
|
1166
|
-
};
|
|
1167
|
-
__privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchema());
|
|
1226
|
+
__privateSet(this, _schema, (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(headers));
|
|
1168
1227
|
if (status === 204) {
|
|
1169
1228
|
__privateSet(this, _lastSyncedAt, Date.now());
|
|
1170
1229
|
}
|
|
@@ -1287,7 +1346,10 @@ pause_fn = function() {
|
|
|
1287
1346
|
}
|
|
1288
1347
|
};
|
|
1289
1348
|
resume_fn = function() {
|
|
1290
|
-
if (__privateGet(this, _started) && __privateGet(this, _state) === `paused`) {
|
|
1349
|
+
if (__privateGet(this, _started) && (__privateGet(this, _state) === `paused` || __privateGet(this, _state) === `pause-requested`)) {
|
|
1350
|
+
if (__privateGet(this, _state) === `pause-requested`) {
|
|
1351
|
+
__privateSet(this, _state, `active`);
|
|
1352
|
+
}
|
|
1291
1353
|
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
1292
1354
|
}
|
|
1293
1355
|
};
|
|
@@ -1353,6 +1415,9 @@ subscribeToVisibilityChanges_fn = function() {
|
|
|
1353
1415
|
}
|
|
1354
1416
|
};
|
|
1355
1417
|
document.addEventListener(`visibilitychange`, visibilityHandler);
|
|
1418
|
+
__privateSet(this, _unsubscribeFromVisibilityChanges, () => {
|
|
1419
|
+
document.removeEventListener(`visibilitychange`, visibilityHandler);
|
|
1420
|
+
});
|
|
1356
1421
|
}
|
|
1357
1422
|
};
|
|
1358
1423
|
/**
|
|
@@ -1371,31 +1436,20 @@ reset_fn = function(handle) {
|
|
|
1371
1436
|
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
1372
1437
|
__privateSet(this, _sseFallbackToLongPolling, false);
|
|
1373
1438
|
};
|
|
1374
|
-
fetchSnapshot_fn = async function(url, headers) {
|
|
1375
|
-
const response = await __privateGet(this, _fetchClient2).call(this, url.toString(), { headers });
|
|
1376
|
-
if (!response.ok) {
|
|
1377
|
-
throw new FetchError(
|
|
1378
|
-
response.status,
|
|
1379
|
-
void 0,
|
|
1380
|
-
void 0,
|
|
1381
|
-
Object.fromEntries([...response.headers.entries()]),
|
|
1382
|
-
url.toString()
|
|
1383
|
-
);
|
|
1384
|
-
}
|
|
1385
|
-
const { metadata, data } = await response.json();
|
|
1386
|
-
const batch = __privateGet(this, _messageParser).parse(
|
|
1387
|
-
JSON.stringify(data),
|
|
1388
|
-
__privateGet(this, _schema)
|
|
1389
|
-
);
|
|
1390
|
-
return {
|
|
1391
|
-
metadata,
|
|
1392
|
-
data: batch
|
|
1393
|
-
};
|
|
1394
|
-
};
|
|
1395
1439
|
ShapeStream.Replica = {
|
|
1396
1440
|
FULL: `full`,
|
|
1397
1441
|
DEFAULT: `default`
|
|
1398
1442
|
};
|
|
1443
|
+
function getSchemaFromHeaders(headers, options) {
|
|
1444
|
+
const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER);
|
|
1445
|
+
if (!schemaHeader) {
|
|
1446
|
+
if ((options == null ? void 0 : options.required) && (options == null ? void 0 : options.url)) {
|
|
1447
|
+
throw new MissingHeadersError(options.url, [SHAPE_SCHEMA_HEADER]);
|
|
1448
|
+
}
|
|
1449
|
+
return {};
|
|
1450
|
+
}
|
|
1451
|
+
return JSON.parse(schemaHeader);
|
|
1452
|
+
}
|
|
1399
1453
|
function validateParams(params) {
|
|
1400
1454
|
if (!params) return;
|
|
1401
1455
|
const reservedParams = Object.keys(params).filter(
|