@electric-sql/client 1.1.5 → 1.2.1
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 +350 -14
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +245 -3
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +245 -3
- package/dist/index.legacy-esm.js +345 -13
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +345 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/client.ts +190 -11
- package/src/column-mapper.ts +357 -0
- package/src/index.ts +7 -0
- package/src/types.ts +33 -2
- package/src/up-to-date-tracker.ts +157 -0
package/dist/index.legacy-esm.js
CHANGED
|
@@ -269,6 +269,151 @@ function makeNullableParser(parser, columnInfo, columnName) {
|
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
// src/column-mapper.ts
|
|
273
|
+
function snakeToCamel(str) {
|
|
274
|
+
var _a, _b, _c, _d;
|
|
275
|
+
const leadingUnderscores = (_b = (_a = str.match(/^_+/)) == null ? void 0 : _a[0]) != null ? _b : ``;
|
|
276
|
+
const withoutLeading = str.slice(leadingUnderscores.length);
|
|
277
|
+
const trailingUnderscores = (_d = (_c = withoutLeading.match(/_+$/)) == null ? void 0 : _c[0]) != null ? _d : ``;
|
|
278
|
+
const core = trailingUnderscores ? withoutLeading.slice(
|
|
279
|
+
0,
|
|
280
|
+
withoutLeading.length - trailingUnderscores.length
|
|
281
|
+
) : withoutLeading;
|
|
282
|
+
const normalized = core.toLowerCase();
|
|
283
|
+
const camelCased = normalized.replace(
|
|
284
|
+
/_+([a-z])/g,
|
|
285
|
+
(_, letter) => letter.toUpperCase()
|
|
286
|
+
);
|
|
287
|
+
return leadingUnderscores + camelCased + trailingUnderscores;
|
|
288
|
+
}
|
|
289
|
+
function camelToSnake(str) {
|
|
290
|
+
return str.replace(/([a-z])([A-Z])/g, `$1_$2`).replace(/([A-Z]+)([A-Z][a-z])/g, `$1_$2`).toLowerCase();
|
|
291
|
+
}
|
|
292
|
+
function createColumnMapper(mapping) {
|
|
293
|
+
const reverseMapping = {};
|
|
294
|
+
for (const [dbName, appName] of Object.entries(mapping)) {
|
|
295
|
+
reverseMapping[appName] = dbName;
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
decode: (dbColumnName) => {
|
|
299
|
+
var _a;
|
|
300
|
+
return (_a = mapping[dbColumnName]) != null ? _a : dbColumnName;
|
|
301
|
+
},
|
|
302
|
+
encode: (appColumnName) => {
|
|
303
|
+
var _a;
|
|
304
|
+
return (_a = reverseMapping[appColumnName]) != null ? _a : appColumnName;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function encodeWhereClause(whereClause, encode) {
|
|
309
|
+
if (!whereClause || !encode) return whereClause != null ? whereClause : ``;
|
|
310
|
+
const sqlKeywords = /* @__PURE__ */ new Set([
|
|
311
|
+
`SELECT`,
|
|
312
|
+
`FROM`,
|
|
313
|
+
`WHERE`,
|
|
314
|
+
`AND`,
|
|
315
|
+
`OR`,
|
|
316
|
+
`NOT`,
|
|
317
|
+
`IN`,
|
|
318
|
+
`IS`,
|
|
319
|
+
`NULL`,
|
|
320
|
+
`NULLS`,
|
|
321
|
+
`FIRST`,
|
|
322
|
+
`LAST`,
|
|
323
|
+
`TRUE`,
|
|
324
|
+
`FALSE`,
|
|
325
|
+
`LIKE`,
|
|
326
|
+
`ILIKE`,
|
|
327
|
+
`BETWEEN`,
|
|
328
|
+
`ASC`,
|
|
329
|
+
`DESC`,
|
|
330
|
+
`LIMIT`,
|
|
331
|
+
`OFFSET`,
|
|
332
|
+
`ORDER`,
|
|
333
|
+
`BY`,
|
|
334
|
+
`GROUP`,
|
|
335
|
+
`HAVING`,
|
|
336
|
+
`DISTINCT`,
|
|
337
|
+
`AS`,
|
|
338
|
+
`ON`,
|
|
339
|
+
`JOIN`,
|
|
340
|
+
`LEFT`,
|
|
341
|
+
`RIGHT`,
|
|
342
|
+
`INNER`,
|
|
343
|
+
`OUTER`,
|
|
344
|
+
`CROSS`,
|
|
345
|
+
`CASE`,
|
|
346
|
+
`WHEN`,
|
|
347
|
+
`THEN`,
|
|
348
|
+
`ELSE`,
|
|
349
|
+
`END`,
|
|
350
|
+
`CAST`,
|
|
351
|
+
`LOWER`,
|
|
352
|
+
`UPPER`,
|
|
353
|
+
`COALESCE`,
|
|
354
|
+
`NULLIF`
|
|
355
|
+
]);
|
|
356
|
+
const quotedRanges = [];
|
|
357
|
+
let pos = 0;
|
|
358
|
+
while (pos < whereClause.length) {
|
|
359
|
+
const ch = whereClause[pos];
|
|
360
|
+
if (ch === `'` || ch === `"`) {
|
|
361
|
+
const start = pos;
|
|
362
|
+
const quoteChar = ch;
|
|
363
|
+
pos++;
|
|
364
|
+
while (pos < whereClause.length) {
|
|
365
|
+
if (whereClause[pos] === quoteChar) {
|
|
366
|
+
if (whereClause[pos + 1] === quoteChar) {
|
|
367
|
+
pos += 2;
|
|
368
|
+
} else {
|
|
369
|
+
pos++;
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
pos++;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
quotedRanges.push({ start, end: pos });
|
|
377
|
+
} else {
|
|
378
|
+
pos++;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const isInQuotedString = (pos2) => {
|
|
382
|
+
return quotedRanges.some((range) => pos2 >= range.start && pos2 < range.end);
|
|
383
|
+
};
|
|
384
|
+
const identifierPattern = new RegExp("(?<![a-zA-Z0-9_])([a-zA-Z_][a-zA-Z0-9_]*)(?![a-zA-Z0-9_])", "g");
|
|
385
|
+
return whereClause.replace(identifierPattern, (match, _p1, offset) => {
|
|
386
|
+
if (isInQuotedString(offset)) {
|
|
387
|
+
return match;
|
|
388
|
+
}
|
|
389
|
+
if (sqlKeywords.has(match.toUpperCase())) {
|
|
390
|
+
return match;
|
|
391
|
+
}
|
|
392
|
+
if (match.startsWith(`$`)) {
|
|
393
|
+
return match;
|
|
394
|
+
}
|
|
395
|
+
const encoded = encode(match);
|
|
396
|
+
return encoded;
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
function snakeCamelMapper(schema) {
|
|
400
|
+
if (schema) {
|
|
401
|
+
const mapping = {};
|
|
402
|
+
for (const dbColumn of Object.keys(schema)) {
|
|
403
|
+
mapping[dbColumn] = snakeToCamel(dbColumn);
|
|
404
|
+
}
|
|
405
|
+
return createColumnMapper(mapping);
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
decode: (dbColumnName) => {
|
|
409
|
+
return snakeToCamel(dbColumnName);
|
|
410
|
+
},
|
|
411
|
+
encode: (appColumnName) => {
|
|
412
|
+
return camelToSnake(appColumnName);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
272
417
|
// src/helpers.ts
|
|
273
418
|
function isChangeMessage(message) {
|
|
274
419
|
return `key` in message;
|
|
@@ -664,6 +809,127 @@ var ExpiredShapesCache = class {
|
|
|
664
809
|
};
|
|
665
810
|
var expiredShapesCache = new ExpiredShapesCache();
|
|
666
811
|
|
|
812
|
+
// src/up-to-date-tracker.ts
|
|
813
|
+
var UpToDateTracker = class {
|
|
814
|
+
constructor() {
|
|
815
|
+
this.data = {};
|
|
816
|
+
this.storageKey = `electric_up_to_date_tracker`;
|
|
817
|
+
this.cacheTTL = 6e4;
|
|
818
|
+
// 60s to match typical CDN s-maxage cache duration
|
|
819
|
+
this.maxEntries = 250;
|
|
820
|
+
this.writeThrottleMs = 6e4;
|
|
821
|
+
// Throttle localStorage writes to once per 60s
|
|
822
|
+
this.lastWriteTime = 0;
|
|
823
|
+
this.load();
|
|
824
|
+
this.cleanup();
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Records that a shape received an up-to-date message with a specific cursor.
|
|
828
|
+
* This timestamp and cursor are used to detect cache replay scenarios.
|
|
829
|
+
* Updates in-memory immediately, but throttles localStorage writes.
|
|
830
|
+
*/
|
|
831
|
+
recordUpToDate(shapeKey, cursor) {
|
|
832
|
+
this.data[shapeKey] = {
|
|
833
|
+
timestamp: Date.now(),
|
|
834
|
+
cursor
|
|
835
|
+
};
|
|
836
|
+
const keys = Object.keys(this.data);
|
|
837
|
+
if (keys.length > this.maxEntries) {
|
|
838
|
+
const oldest = keys.reduce(
|
|
839
|
+
(min, k) => this.data[k].timestamp < this.data[min].timestamp ? k : min
|
|
840
|
+
);
|
|
841
|
+
delete this.data[oldest];
|
|
842
|
+
}
|
|
843
|
+
this.scheduleSave();
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Schedules a throttled save to localStorage.
|
|
847
|
+
* Writes immediately if enough time has passed, otherwise schedules for later.
|
|
848
|
+
*/
|
|
849
|
+
scheduleSave() {
|
|
850
|
+
const now = Date.now();
|
|
851
|
+
const timeSinceLastWrite = now - this.lastWriteTime;
|
|
852
|
+
if (timeSinceLastWrite >= this.writeThrottleMs) {
|
|
853
|
+
this.lastWriteTime = now;
|
|
854
|
+
this.save();
|
|
855
|
+
} else if (!this.pendingSaveTimer) {
|
|
856
|
+
const delay = this.writeThrottleMs - timeSinceLastWrite;
|
|
857
|
+
this.pendingSaveTimer = setTimeout(() => {
|
|
858
|
+
this.lastWriteTime = Date.now();
|
|
859
|
+
this.pendingSaveTimer = void 0;
|
|
860
|
+
this.save();
|
|
861
|
+
}, delay);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Checks if we should enter replay mode for this shape.
|
|
866
|
+
* Returns the last seen cursor if there's a recent up-to-date (< 60s),
|
|
867
|
+
* which means we'll likely be replaying cached responses.
|
|
868
|
+
* Returns null if no recent up-to-date exists.
|
|
869
|
+
*/
|
|
870
|
+
shouldEnterReplayMode(shapeKey) {
|
|
871
|
+
const entry = this.data[shapeKey];
|
|
872
|
+
if (!entry) {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
const age = Date.now() - entry.timestamp;
|
|
876
|
+
if (age >= this.cacheTTL) {
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
return entry.cursor;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Cleans up expired entries from the cache.
|
|
883
|
+
* Called on initialization and can be called periodically.
|
|
884
|
+
*/
|
|
885
|
+
cleanup() {
|
|
886
|
+
const now = Date.now();
|
|
887
|
+
const keys = Object.keys(this.data);
|
|
888
|
+
let modified = false;
|
|
889
|
+
for (const key of keys) {
|
|
890
|
+
const age = now - this.data[key].timestamp;
|
|
891
|
+
if (age > this.cacheTTL) {
|
|
892
|
+
delete this.data[key];
|
|
893
|
+
modified = true;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (modified) {
|
|
897
|
+
this.save();
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
save() {
|
|
901
|
+
if (typeof localStorage === `undefined`) return;
|
|
902
|
+
try {
|
|
903
|
+
localStorage.setItem(this.storageKey, JSON.stringify(this.data));
|
|
904
|
+
} catch (e) {
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
load() {
|
|
908
|
+
if (typeof localStorage === `undefined`) return;
|
|
909
|
+
try {
|
|
910
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
911
|
+
if (stored) {
|
|
912
|
+
this.data = JSON.parse(stored);
|
|
913
|
+
}
|
|
914
|
+
} catch (e) {
|
|
915
|
+
this.data = {};
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Clears all tracked up-to-date timestamps.
|
|
920
|
+
* Useful for testing or manual cache invalidation.
|
|
921
|
+
*/
|
|
922
|
+
clear() {
|
|
923
|
+
this.data = {};
|
|
924
|
+
if (this.pendingSaveTimer) {
|
|
925
|
+
clearTimeout(this.pendingSaveTimer);
|
|
926
|
+
this.pendingSaveTimer = void 0;
|
|
927
|
+
}
|
|
928
|
+
this.save();
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
var upToDateTracker = new UpToDateTracker();
|
|
932
|
+
|
|
667
933
|
// src/snapshot-tracker.ts
|
|
668
934
|
var SnapshotTracker = class {
|
|
669
935
|
constructor() {
|
|
@@ -773,7 +1039,7 @@ function canonicalShapeKey(url) {
|
|
|
773
1039
|
cleanUrl.searchParams.sort();
|
|
774
1040
|
return cleanUrl.toString();
|
|
775
1041
|
}
|
|
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;
|
|
1042
|
+
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, _lastSeenCursor, _currentFetchUrl, _lastSseConnectionStartTime, _minSseConnectionDuration, _consecutiveShortSseConnections, _maxShortSseConnections, _sseFallbackToLongPolling, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _unsubscribeFromVisibilityChanges, _ShapeStream_instances, replayMode_get, 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;
|
|
777
1043
|
var ShapeStream = class {
|
|
778
1044
|
constructor(options) {
|
|
779
1045
|
__privateAdd(this, _ShapeStream_instances);
|
|
@@ -808,6 +1074,10 @@ var ShapeStream = class {
|
|
|
808
1074
|
// counter for concurrent snapshot requests
|
|
809
1075
|
__privateAdd(this, _midStreamPromise);
|
|
810
1076
|
__privateAdd(this, _midStreamPromiseResolver);
|
|
1077
|
+
__privateAdd(this, _lastSeenCursor);
|
|
1078
|
+
// Last seen cursor from previous session (used to detect cached responses)
|
|
1079
|
+
__privateAdd(this, _currentFetchUrl);
|
|
1080
|
+
// Current fetch URL for computing shape key
|
|
811
1081
|
__privateAdd(this, _lastSseConnectionStartTime);
|
|
812
1082
|
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
813
1083
|
// Minimum expected SSE connection duration (1 second)
|
|
@@ -826,10 +1096,21 @@ var ShapeStream = class {
|
|
|
826
1096
|
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
827
1097
|
__privateSet(this, _liveCacheBuster, ``);
|
|
828
1098
|
__privateSet(this, _shapeHandle, this.options.handle);
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1099
|
+
let transformer;
|
|
1100
|
+
if (options.columnMapper) {
|
|
1101
|
+
const applyColumnMapper = (row) => {
|
|
1102
|
+
const result = {};
|
|
1103
|
+
for (const [dbKey, value] of Object.entries(row)) {
|
|
1104
|
+
const appKey = options.columnMapper.decode(dbKey);
|
|
1105
|
+
result[appKey] = value;
|
|
1106
|
+
}
|
|
1107
|
+
return result;
|
|
1108
|
+
};
|
|
1109
|
+
transformer = options.transformer ? (row) => options.transformer(applyColumnMapper(row)) : applyColumnMapper;
|
|
1110
|
+
} else {
|
|
1111
|
+
transformer = options.transformer;
|
|
1112
|
+
}
|
|
1113
|
+
__privateSet(this, _messageParser, new MessageParser(options.parser, transformer));
|
|
833
1114
|
__privateSet(this, _onError, this.options.onError);
|
|
834
1115
|
__privateSet(this, _mode, (_b = this.options.log) != null ? _b : `full`);
|
|
835
1116
|
const baseFetchClient = (_c = options.fetchClient) != null ? _c : (...args) => fetch(...args);
|
|
@@ -1028,6 +1309,8 @@ _snapshotTracker = new WeakMap();
|
|
|
1028
1309
|
_activeSnapshotRequests = new WeakMap();
|
|
1029
1310
|
_midStreamPromise = new WeakMap();
|
|
1030
1311
|
_midStreamPromiseResolver = new WeakMap();
|
|
1312
|
+
_lastSeenCursor = new WeakMap();
|
|
1313
|
+
_currentFetchUrl = new WeakMap();
|
|
1031
1314
|
_lastSseConnectionStartTime = new WeakMap();
|
|
1032
1315
|
_minSseConnectionDuration = new WeakMap();
|
|
1033
1316
|
_consecutiveShortSseConnections = new WeakMap();
|
|
@@ -1037,6 +1320,9 @@ _sseBackoffBaseDelay = new WeakMap();
|
|
|
1037
1320
|
_sseBackoffMaxDelay = new WeakMap();
|
|
1038
1321
|
_unsubscribeFromVisibilityChanges = new WeakMap();
|
|
1039
1322
|
_ShapeStream_instances = new WeakSet();
|
|
1323
|
+
replayMode_get = function() {
|
|
1324
|
+
return __privateGet(this, _lastSeenCursor) !== void 0;
|
|
1325
|
+
};
|
|
1040
1326
|
start_fn = async function() {
|
|
1041
1327
|
var _a, _b, _c, _d, _e;
|
|
1042
1328
|
__privateSet(this, _started, true);
|
|
@@ -1131,6 +1417,7 @@ requestShape_fn = async function() {
|
|
|
1131
1417
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1132
1418
|
};
|
|
1133
1419
|
constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
1420
|
+
var _a, _b, _c;
|
|
1134
1421
|
const [requestHeaders, params] = await Promise.all([
|
|
1135
1422
|
resolveHeaders(this.options.headers),
|
|
1136
1423
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
@@ -1139,7 +1426,13 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
|
1139
1426
|
const fetchUrl = new URL(url);
|
|
1140
1427
|
if (params) {
|
|
1141
1428
|
if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
|
|
1142
|
-
if (params.where
|
|
1429
|
+
if (params.where && typeof params.where === `string`) {
|
|
1430
|
+
const encodedWhere = encodeWhereClause(
|
|
1431
|
+
params.where,
|
|
1432
|
+
(_a = this.options.columnMapper) == null ? void 0 : _a.encode
|
|
1433
|
+
);
|
|
1434
|
+
setQueryParam(fetchUrl, WHERE_QUERY_PARAM, encodedWhere);
|
|
1435
|
+
}
|
|
1143
1436
|
if (params.columns)
|
|
1144
1437
|
setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
|
|
1145
1438
|
if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
|
|
@@ -1156,16 +1449,29 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
|
1156
1449
|
}
|
|
1157
1450
|
}
|
|
1158
1451
|
if (subsetParams) {
|
|
1159
|
-
if (subsetParams.where)
|
|
1160
|
-
|
|
1452
|
+
if (subsetParams.where && typeof subsetParams.where === `string`) {
|
|
1453
|
+
const encodedWhere = encodeWhereClause(
|
|
1454
|
+
subsetParams.where,
|
|
1455
|
+
(_b = this.options.columnMapper) == null ? void 0 : _b.encode
|
|
1456
|
+
);
|
|
1457
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, encodedWhere);
|
|
1458
|
+
}
|
|
1161
1459
|
if (subsetParams.params)
|
|
1162
|
-
|
|
1460
|
+
fetchUrl.searchParams.set(
|
|
1461
|
+
SUBSET_PARAM_WHERE_PARAMS,
|
|
1462
|
+
JSON.stringify(subsetParams.params)
|
|
1463
|
+
);
|
|
1163
1464
|
if (subsetParams.limit)
|
|
1164
1465
|
setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
|
|
1165
1466
|
if (subsetParams.offset)
|
|
1166
1467
|
setQueryParam(fetchUrl, SUBSET_PARAM_OFFSET, subsetParams.offset);
|
|
1167
|
-
if (subsetParams.orderBy)
|
|
1168
|
-
|
|
1468
|
+
if (subsetParams.orderBy && typeof subsetParams.orderBy === `string`) {
|
|
1469
|
+
const encodedOrderBy = encodeWhereClause(
|
|
1470
|
+
subsetParams.orderBy,
|
|
1471
|
+
(_c = this.options.columnMapper) == null ? void 0 : _c.encode
|
|
1472
|
+
);
|
|
1473
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
|
|
1474
|
+
}
|
|
1169
1475
|
}
|
|
1170
1476
|
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
1171
1477
|
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
@@ -1244,6 +1550,17 @@ onMessages_fn = async function(batch, isSseMessage = false) {
|
|
|
1244
1550
|
__privateSet(this, _isUpToDate, true);
|
|
1245
1551
|
__privateSet(this, _isMidStream, false);
|
|
1246
1552
|
(_a = __privateGet(this, _midStreamPromiseResolver)) == null ? void 0 : _a.call(this);
|
|
1553
|
+
if (__privateGet(this, _ShapeStream_instances, replayMode_get) && !isSseMessage) {
|
|
1554
|
+
const currentCursor = __privateGet(this, _liveCacheBuster);
|
|
1555
|
+
if (currentCursor === __privateGet(this, _lastSeenCursor)) {
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
__privateSet(this, _lastSeenCursor, void 0);
|
|
1560
|
+
if (__privateGet(this, _currentFetchUrl)) {
|
|
1561
|
+
const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
|
|
1562
|
+
upToDateTracker.recordUpToDate(shapeKey, __privateGet(this, _liveCacheBuster));
|
|
1563
|
+
}
|
|
1247
1564
|
}
|
|
1248
1565
|
const messagesToProcess = batch.filter((message) => {
|
|
1249
1566
|
if (isChangeMessage(message)) {
|
|
@@ -1256,6 +1573,14 @@ onMessages_fn = async function(batch, isSseMessage = false) {
|
|
|
1256
1573
|
};
|
|
1257
1574
|
fetchShape_fn = async function(opts) {
|
|
1258
1575
|
var _a;
|
|
1576
|
+
__privateSet(this, _currentFetchUrl, opts.fetchUrl);
|
|
1577
|
+
if (!__privateGet(this, _isUpToDate) && !__privateGet(this, _ShapeStream_instances, replayMode_get)) {
|
|
1578
|
+
const shapeKey = canonicalShapeKey(opts.fetchUrl);
|
|
1579
|
+
const lastSeenCursor = upToDateTracker.shouldEnterReplayMode(shapeKey);
|
|
1580
|
+
if (lastSeenCursor) {
|
|
1581
|
+
__privateSet(this, _lastSeenCursor, lastSeenCursor);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1259
1584
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1260
1585
|
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling)) {
|
|
1261
1586
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
@@ -1282,10 +1607,13 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1282
1607
|
const { fetchUrl, requestAbortController, headers } = opts;
|
|
1283
1608
|
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
1284
1609
|
__privateSet(this, _lastSseConnectionStartTime, Date.now());
|
|
1610
|
+
const sseHeaders = __spreadProps(__spreadValues({}, headers), {
|
|
1611
|
+
Accept: `text/event-stream`
|
|
1612
|
+
});
|
|
1285
1613
|
try {
|
|
1286
1614
|
let buffer = [];
|
|
1287
1615
|
await fetchEventSource(fetchUrl.toString(), {
|
|
1288
|
-
headers,
|
|
1616
|
+
headers: sseHeaders,
|
|
1289
1617
|
fetch: fetch2,
|
|
1290
1618
|
onopen: async (response) => {
|
|
1291
1619
|
__privateSet(this, _connected, true);
|
|
@@ -1708,9 +2036,13 @@ export {
|
|
|
1708
2036
|
FetchError,
|
|
1709
2037
|
Shape,
|
|
1710
2038
|
ShapeStream,
|
|
2039
|
+
camelToSnake,
|
|
2040
|
+
createColumnMapper,
|
|
1711
2041
|
isChangeMessage,
|
|
1712
2042
|
isControlMessage,
|
|
1713
2043
|
isVisibleInSnapshot,
|
|
1714
|
-
resolveValue
|
|
2044
|
+
resolveValue,
|
|
2045
|
+
snakeCamelMapper,
|
|
2046
|
+
snakeToCamel
|
|
1715
2047
|
};
|
|
1716
2048
|
//# sourceMappingURL=index.legacy-esm.js.map
|