@electric-sql/client 1.1.5 → 1.2.0
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 +346 -13
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +212 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +212 -1
- package/dist/index.legacy-esm.js +341 -12
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +341 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +183 -10
- package/src/column-mapper.ts +357 -0
- package/src/index.ts +7 -0
- package/src/up-to-date-tracker.ts +157 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -90,10 +90,14 @@ __export(src_exports, {
|
|
|
90
90
|
FetchError: () => FetchError,
|
|
91
91
|
Shape: () => Shape,
|
|
92
92
|
ShapeStream: () => ShapeStream,
|
|
93
|
+
camelToSnake: () => camelToSnake,
|
|
94
|
+
createColumnMapper: () => createColumnMapper,
|
|
93
95
|
isChangeMessage: () => isChangeMessage,
|
|
94
96
|
isControlMessage: () => isControlMessage,
|
|
95
97
|
isVisibleInSnapshot: () => isVisibleInSnapshot,
|
|
96
|
-
resolveValue: () => resolveValue
|
|
98
|
+
resolveValue: () => resolveValue,
|
|
99
|
+
snakeCamelMapper: () => snakeCamelMapper,
|
|
100
|
+
snakeToCamel: () => snakeToCamel
|
|
97
101
|
});
|
|
98
102
|
module.exports = __toCommonJS(src_exports);
|
|
99
103
|
|
|
@@ -322,6 +326,151 @@ function makeNullableParser(parser, columnInfo, columnName) {
|
|
|
322
326
|
};
|
|
323
327
|
}
|
|
324
328
|
|
|
329
|
+
// src/column-mapper.ts
|
|
330
|
+
function snakeToCamel(str) {
|
|
331
|
+
var _a, _b, _c, _d;
|
|
332
|
+
const leadingUnderscores = (_b = (_a = str.match(/^_+/)) == null ? void 0 : _a[0]) != null ? _b : ``;
|
|
333
|
+
const withoutLeading = str.slice(leadingUnderscores.length);
|
|
334
|
+
const trailingUnderscores = (_d = (_c = withoutLeading.match(/_+$/)) == null ? void 0 : _c[0]) != null ? _d : ``;
|
|
335
|
+
const core = trailingUnderscores ? withoutLeading.slice(
|
|
336
|
+
0,
|
|
337
|
+
withoutLeading.length - trailingUnderscores.length
|
|
338
|
+
) : withoutLeading;
|
|
339
|
+
const normalized = core.toLowerCase();
|
|
340
|
+
const camelCased = normalized.replace(
|
|
341
|
+
/_+([a-z])/g,
|
|
342
|
+
(_, letter) => letter.toUpperCase()
|
|
343
|
+
);
|
|
344
|
+
return leadingUnderscores + camelCased + trailingUnderscores;
|
|
345
|
+
}
|
|
346
|
+
function camelToSnake(str) {
|
|
347
|
+
return str.replace(/([a-z])([A-Z])/g, `$1_$2`).replace(/([A-Z]+)([A-Z][a-z])/g, `$1_$2`).toLowerCase();
|
|
348
|
+
}
|
|
349
|
+
function createColumnMapper(mapping) {
|
|
350
|
+
const reverseMapping = {};
|
|
351
|
+
for (const [dbName, appName] of Object.entries(mapping)) {
|
|
352
|
+
reverseMapping[appName] = dbName;
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
decode: (dbColumnName) => {
|
|
356
|
+
var _a;
|
|
357
|
+
return (_a = mapping[dbColumnName]) != null ? _a : dbColumnName;
|
|
358
|
+
},
|
|
359
|
+
encode: (appColumnName) => {
|
|
360
|
+
var _a;
|
|
361
|
+
return (_a = reverseMapping[appColumnName]) != null ? _a : appColumnName;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function encodeWhereClause(whereClause, encode) {
|
|
366
|
+
if (!whereClause || !encode) return whereClause != null ? whereClause : ``;
|
|
367
|
+
const sqlKeywords = /* @__PURE__ */ new Set([
|
|
368
|
+
`SELECT`,
|
|
369
|
+
`FROM`,
|
|
370
|
+
`WHERE`,
|
|
371
|
+
`AND`,
|
|
372
|
+
`OR`,
|
|
373
|
+
`NOT`,
|
|
374
|
+
`IN`,
|
|
375
|
+
`IS`,
|
|
376
|
+
`NULL`,
|
|
377
|
+
`NULLS`,
|
|
378
|
+
`FIRST`,
|
|
379
|
+
`LAST`,
|
|
380
|
+
`TRUE`,
|
|
381
|
+
`FALSE`,
|
|
382
|
+
`LIKE`,
|
|
383
|
+
`ILIKE`,
|
|
384
|
+
`BETWEEN`,
|
|
385
|
+
`ASC`,
|
|
386
|
+
`DESC`,
|
|
387
|
+
`LIMIT`,
|
|
388
|
+
`OFFSET`,
|
|
389
|
+
`ORDER`,
|
|
390
|
+
`BY`,
|
|
391
|
+
`GROUP`,
|
|
392
|
+
`HAVING`,
|
|
393
|
+
`DISTINCT`,
|
|
394
|
+
`AS`,
|
|
395
|
+
`ON`,
|
|
396
|
+
`JOIN`,
|
|
397
|
+
`LEFT`,
|
|
398
|
+
`RIGHT`,
|
|
399
|
+
`INNER`,
|
|
400
|
+
`OUTER`,
|
|
401
|
+
`CROSS`,
|
|
402
|
+
`CASE`,
|
|
403
|
+
`WHEN`,
|
|
404
|
+
`THEN`,
|
|
405
|
+
`ELSE`,
|
|
406
|
+
`END`,
|
|
407
|
+
`CAST`,
|
|
408
|
+
`LOWER`,
|
|
409
|
+
`UPPER`,
|
|
410
|
+
`COALESCE`,
|
|
411
|
+
`NULLIF`
|
|
412
|
+
]);
|
|
413
|
+
const quotedRanges = [];
|
|
414
|
+
let pos = 0;
|
|
415
|
+
while (pos < whereClause.length) {
|
|
416
|
+
const ch = whereClause[pos];
|
|
417
|
+
if (ch === `'` || ch === `"`) {
|
|
418
|
+
const start = pos;
|
|
419
|
+
const quoteChar = ch;
|
|
420
|
+
pos++;
|
|
421
|
+
while (pos < whereClause.length) {
|
|
422
|
+
if (whereClause[pos] === quoteChar) {
|
|
423
|
+
if (whereClause[pos + 1] === quoteChar) {
|
|
424
|
+
pos += 2;
|
|
425
|
+
} else {
|
|
426
|
+
pos++;
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
} else {
|
|
430
|
+
pos++;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
quotedRanges.push({ start, end: pos });
|
|
434
|
+
} else {
|
|
435
|
+
pos++;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const isInQuotedString = (pos2) => {
|
|
439
|
+
return quotedRanges.some((range) => pos2 >= range.start && pos2 < range.end);
|
|
440
|
+
};
|
|
441
|
+
const identifierPattern = new RegExp("(?<![a-zA-Z0-9_])([a-zA-Z_][a-zA-Z0-9_]*)(?![a-zA-Z0-9_])", "g");
|
|
442
|
+
return whereClause.replace(identifierPattern, (match, _p1, offset) => {
|
|
443
|
+
if (isInQuotedString(offset)) {
|
|
444
|
+
return match;
|
|
445
|
+
}
|
|
446
|
+
if (sqlKeywords.has(match.toUpperCase())) {
|
|
447
|
+
return match;
|
|
448
|
+
}
|
|
449
|
+
if (match.startsWith(`$`)) {
|
|
450
|
+
return match;
|
|
451
|
+
}
|
|
452
|
+
const encoded = encode(match);
|
|
453
|
+
return encoded;
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
function snakeCamelMapper(schema) {
|
|
457
|
+
if (schema) {
|
|
458
|
+
const mapping = {};
|
|
459
|
+
for (const dbColumn of Object.keys(schema)) {
|
|
460
|
+
mapping[dbColumn] = snakeToCamel(dbColumn);
|
|
461
|
+
}
|
|
462
|
+
return createColumnMapper(mapping);
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
decode: (dbColumnName) => {
|
|
466
|
+
return snakeToCamel(dbColumnName);
|
|
467
|
+
},
|
|
468
|
+
encode: (appColumnName) => {
|
|
469
|
+
return camelToSnake(appColumnName);
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
325
474
|
// src/helpers.ts
|
|
326
475
|
function isChangeMessage(message) {
|
|
327
476
|
return `key` in message;
|
|
@@ -715,6 +864,127 @@ var ExpiredShapesCache = class {
|
|
|
715
864
|
};
|
|
716
865
|
var expiredShapesCache = new ExpiredShapesCache();
|
|
717
866
|
|
|
867
|
+
// src/up-to-date-tracker.ts
|
|
868
|
+
var UpToDateTracker = class {
|
|
869
|
+
constructor() {
|
|
870
|
+
this.data = {};
|
|
871
|
+
this.storageKey = `electric_up_to_date_tracker`;
|
|
872
|
+
this.cacheTTL = 6e4;
|
|
873
|
+
// 60s to match typical CDN s-maxage cache duration
|
|
874
|
+
this.maxEntries = 250;
|
|
875
|
+
this.writeThrottleMs = 6e4;
|
|
876
|
+
// Throttle localStorage writes to once per 60s
|
|
877
|
+
this.lastWriteTime = 0;
|
|
878
|
+
this.load();
|
|
879
|
+
this.cleanup();
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Records that a shape received an up-to-date message with a specific cursor.
|
|
883
|
+
* This timestamp and cursor are used to detect cache replay scenarios.
|
|
884
|
+
* Updates in-memory immediately, but throttles localStorage writes.
|
|
885
|
+
*/
|
|
886
|
+
recordUpToDate(shapeKey, cursor) {
|
|
887
|
+
this.data[shapeKey] = {
|
|
888
|
+
timestamp: Date.now(),
|
|
889
|
+
cursor
|
|
890
|
+
};
|
|
891
|
+
const keys = Object.keys(this.data);
|
|
892
|
+
if (keys.length > this.maxEntries) {
|
|
893
|
+
const oldest = keys.reduce(
|
|
894
|
+
(min, k) => this.data[k].timestamp < this.data[min].timestamp ? k : min
|
|
895
|
+
);
|
|
896
|
+
delete this.data[oldest];
|
|
897
|
+
}
|
|
898
|
+
this.scheduleSave();
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Schedules a throttled save to localStorage.
|
|
902
|
+
* Writes immediately if enough time has passed, otherwise schedules for later.
|
|
903
|
+
*/
|
|
904
|
+
scheduleSave() {
|
|
905
|
+
const now = Date.now();
|
|
906
|
+
const timeSinceLastWrite = now - this.lastWriteTime;
|
|
907
|
+
if (timeSinceLastWrite >= this.writeThrottleMs) {
|
|
908
|
+
this.lastWriteTime = now;
|
|
909
|
+
this.save();
|
|
910
|
+
} else if (!this.pendingSaveTimer) {
|
|
911
|
+
const delay = this.writeThrottleMs - timeSinceLastWrite;
|
|
912
|
+
this.pendingSaveTimer = setTimeout(() => {
|
|
913
|
+
this.lastWriteTime = Date.now();
|
|
914
|
+
this.pendingSaveTimer = void 0;
|
|
915
|
+
this.save();
|
|
916
|
+
}, delay);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Checks if we should enter replay mode for this shape.
|
|
921
|
+
* Returns the last seen cursor if there's a recent up-to-date (< 60s),
|
|
922
|
+
* which means we'll likely be replaying cached responses.
|
|
923
|
+
* Returns null if no recent up-to-date exists.
|
|
924
|
+
*/
|
|
925
|
+
shouldEnterReplayMode(shapeKey) {
|
|
926
|
+
const entry = this.data[shapeKey];
|
|
927
|
+
if (!entry) {
|
|
928
|
+
return null;
|
|
929
|
+
}
|
|
930
|
+
const age = Date.now() - entry.timestamp;
|
|
931
|
+
if (age >= this.cacheTTL) {
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
return entry.cursor;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Cleans up expired entries from the cache.
|
|
938
|
+
* Called on initialization and can be called periodically.
|
|
939
|
+
*/
|
|
940
|
+
cleanup() {
|
|
941
|
+
const now = Date.now();
|
|
942
|
+
const keys = Object.keys(this.data);
|
|
943
|
+
let modified = false;
|
|
944
|
+
for (const key of keys) {
|
|
945
|
+
const age = now - this.data[key].timestamp;
|
|
946
|
+
if (age > this.cacheTTL) {
|
|
947
|
+
delete this.data[key];
|
|
948
|
+
modified = true;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (modified) {
|
|
952
|
+
this.save();
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
save() {
|
|
956
|
+
if (typeof localStorage === `undefined`) return;
|
|
957
|
+
try {
|
|
958
|
+
localStorage.setItem(this.storageKey, JSON.stringify(this.data));
|
|
959
|
+
} catch (e) {
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
load() {
|
|
963
|
+
if (typeof localStorage === `undefined`) return;
|
|
964
|
+
try {
|
|
965
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
966
|
+
if (stored) {
|
|
967
|
+
this.data = JSON.parse(stored);
|
|
968
|
+
}
|
|
969
|
+
} catch (e) {
|
|
970
|
+
this.data = {};
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Clears all tracked up-to-date timestamps.
|
|
975
|
+
* Useful for testing or manual cache invalidation.
|
|
976
|
+
*/
|
|
977
|
+
clear() {
|
|
978
|
+
this.data = {};
|
|
979
|
+
if (this.pendingSaveTimer) {
|
|
980
|
+
clearTimeout(this.pendingSaveTimer);
|
|
981
|
+
this.pendingSaveTimer = void 0;
|
|
982
|
+
}
|
|
983
|
+
this.save();
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
var upToDateTracker = new UpToDateTracker();
|
|
987
|
+
|
|
718
988
|
// src/snapshot-tracker.ts
|
|
719
989
|
var SnapshotTracker = class {
|
|
720
990
|
constructor() {
|
|
@@ -832,7 +1102,7 @@ function canonicalShapeKey(url) {
|
|
|
832
1102
|
cleanUrl.searchParams.sort();
|
|
833
1103
|
return cleanUrl.toString();
|
|
834
1104
|
}
|
|
835
|
-
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;
|
|
1105
|
+
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;
|
|
836
1106
|
var ShapeStream = class {
|
|
837
1107
|
constructor(options) {
|
|
838
1108
|
__privateAdd(this, _ShapeStream_instances);
|
|
@@ -867,6 +1137,10 @@ var ShapeStream = class {
|
|
|
867
1137
|
// counter for concurrent snapshot requests
|
|
868
1138
|
__privateAdd(this, _midStreamPromise);
|
|
869
1139
|
__privateAdd(this, _midStreamPromiseResolver);
|
|
1140
|
+
__privateAdd(this, _lastSeenCursor);
|
|
1141
|
+
// Last seen cursor from previous session (used to detect cached responses)
|
|
1142
|
+
__privateAdd(this, _currentFetchUrl);
|
|
1143
|
+
// Current fetch URL for computing shape key
|
|
870
1144
|
__privateAdd(this, _lastSseConnectionStartTime);
|
|
871
1145
|
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
872
1146
|
// Minimum expected SSE connection duration (1 second)
|
|
@@ -885,10 +1159,21 @@ var ShapeStream = class {
|
|
|
885
1159
|
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
886
1160
|
__privateSet(this, _liveCacheBuster, ``);
|
|
887
1161
|
__privateSet(this, _shapeHandle, this.options.handle);
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1162
|
+
let transformer;
|
|
1163
|
+
if (options.columnMapper) {
|
|
1164
|
+
const applyColumnMapper = (row) => {
|
|
1165
|
+
const result = {};
|
|
1166
|
+
for (const [dbKey, value] of Object.entries(row)) {
|
|
1167
|
+
const appKey = options.columnMapper.decode(dbKey);
|
|
1168
|
+
result[appKey] = value;
|
|
1169
|
+
}
|
|
1170
|
+
return result;
|
|
1171
|
+
};
|
|
1172
|
+
transformer = options.transformer ? (row) => options.transformer(applyColumnMapper(row)) : applyColumnMapper;
|
|
1173
|
+
} else {
|
|
1174
|
+
transformer = options.transformer;
|
|
1175
|
+
}
|
|
1176
|
+
__privateSet(this, _messageParser, new MessageParser(options.parser, transformer));
|
|
892
1177
|
__privateSet(this, _onError, this.options.onError);
|
|
893
1178
|
__privateSet(this, _mode, (_b = this.options.log) != null ? _b : `full`);
|
|
894
1179
|
const baseFetchClient = (_c = options.fetchClient) != null ? _c : (...args) => fetch(...args);
|
|
@@ -1093,6 +1378,8 @@ _snapshotTracker = new WeakMap();
|
|
|
1093
1378
|
_activeSnapshotRequests = new WeakMap();
|
|
1094
1379
|
_midStreamPromise = new WeakMap();
|
|
1095
1380
|
_midStreamPromiseResolver = new WeakMap();
|
|
1381
|
+
_lastSeenCursor = new WeakMap();
|
|
1382
|
+
_currentFetchUrl = new WeakMap();
|
|
1096
1383
|
_lastSseConnectionStartTime = new WeakMap();
|
|
1097
1384
|
_minSseConnectionDuration = new WeakMap();
|
|
1098
1385
|
_consecutiveShortSseConnections = new WeakMap();
|
|
@@ -1102,6 +1389,9 @@ _sseBackoffBaseDelay = new WeakMap();
|
|
|
1102
1389
|
_sseBackoffMaxDelay = new WeakMap();
|
|
1103
1390
|
_unsubscribeFromVisibilityChanges = new WeakMap();
|
|
1104
1391
|
_ShapeStream_instances = new WeakSet();
|
|
1392
|
+
replayMode_get = function() {
|
|
1393
|
+
return __privateGet(this, _lastSeenCursor) !== void 0;
|
|
1394
|
+
};
|
|
1105
1395
|
start_fn = function() {
|
|
1106
1396
|
return __async(this, null, function* () {
|
|
1107
1397
|
var _a, _b, _c, _d, _e;
|
|
@@ -1201,6 +1491,7 @@ requestShape_fn = function() {
|
|
|
1201
1491
|
};
|
|
1202
1492
|
constructUrl_fn = function(url, resumingFromPause, subsetParams) {
|
|
1203
1493
|
return __async(this, null, function* () {
|
|
1494
|
+
var _a, _b, _c;
|
|
1204
1495
|
const [requestHeaders, params] = yield Promise.all([
|
|
1205
1496
|
resolveHeaders(this.options.headers),
|
|
1206
1497
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
@@ -1209,7 +1500,13 @@ constructUrl_fn = function(url, resumingFromPause, subsetParams) {
|
|
|
1209
1500
|
const fetchUrl = new URL(url);
|
|
1210
1501
|
if (params) {
|
|
1211
1502
|
if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
|
|
1212
|
-
if (params.where
|
|
1503
|
+
if (params.where && typeof params.where === `string`) {
|
|
1504
|
+
const encodedWhere = encodeWhereClause(
|
|
1505
|
+
params.where,
|
|
1506
|
+
(_a = this.options.columnMapper) == null ? void 0 : _a.encode
|
|
1507
|
+
);
|
|
1508
|
+
setQueryParam(fetchUrl, WHERE_QUERY_PARAM, encodedWhere);
|
|
1509
|
+
}
|
|
1213
1510
|
if (params.columns)
|
|
1214
1511
|
setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
|
|
1215
1512
|
if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
|
|
@@ -1226,16 +1523,29 @@ constructUrl_fn = function(url, resumingFromPause, subsetParams) {
|
|
|
1226
1523
|
}
|
|
1227
1524
|
}
|
|
1228
1525
|
if (subsetParams) {
|
|
1229
|
-
if (subsetParams.where)
|
|
1230
|
-
|
|
1526
|
+
if (subsetParams.where && typeof subsetParams.where === `string`) {
|
|
1527
|
+
const encodedWhere = encodeWhereClause(
|
|
1528
|
+
subsetParams.where,
|
|
1529
|
+
(_b = this.options.columnMapper) == null ? void 0 : _b.encode
|
|
1530
|
+
);
|
|
1531
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, encodedWhere);
|
|
1532
|
+
}
|
|
1231
1533
|
if (subsetParams.params)
|
|
1232
|
-
|
|
1534
|
+
fetchUrl.searchParams.set(
|
|
1535
|
+
SUBSET_PARAM_WHERE_PARAMS,
|
|
1536
|
+
JSON.stringify(subsetParams.params)
|
|
1537
|
+
);
|
|
1233
1538
|
if (subsetParams.limit)
|
|
1234
1539
|
setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
|
|
1235
1540
|
if (subsetParams.offset)
|
|
1236
1541
|
setQueryParam(fetchUrl, SUBSET_PARAM_OFFSET, subsetParams.offset);
|
|
1237
|
-
if (subsetParams.orderBy)
|
|
1238
|
-
|
|
1542
|
+
if (subsetParams.orderBy && typeof subsetParams.orderBy === `string`) {
|
|
1543
|
+
const encodedOrderBy = encodeWhereClause(
|
|
1544
|
+
subsetParams.orderBy,
|
|
1545
|
+
(_c = this.options.columnMapper) == null ? void 0 : _c.encode
|
|
1546
|
+
);
|
|
1547
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
|
|
1548
|
+
}
|
|
1239
1549
|
}
|
|
1240
1550
|
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
1241
1551
|
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
@@ -1320,6 +1630,17 @@ onMessages_fn = function(batch, isSseMessage = false) {
|
|
|
1320
1630
|
__privateSet(this, _isUpToDate, true);
|
|
1321
1631
|
__privateSet(this, _isMidStream, false);
|
|
1322
1632
|
(_a = __privateGet(this, _midStreamPromiseResolver)) == null ? void 0 : _a.call(this);
|
|
1633
|
+
if (__privateGet(this, _ShapeStream_instances, replayMode_get) && !isSseMessage) {
|
|
1634
|
+
const currentCursor = __privateGet(this, _liveCacheBuster);
|
|
1635
|
+
if (currentCursor === __privateGet(this, _lastSeenCursor)) {
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
__privateSet(this, _lastSeenCursor, void 0);
|
|
1640
|
+
if (__privateGet(this, _currentFetchUrl)) {
|
|
1641
|
+
const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
|
|
1642
|
+
upToDateTracker.recordUpToDate(shapeKey, __privateGet(this, _liveCacheBuster));
|
|
1643
|
+
}
|
|
1323
1644
|
}
|
|
1324
1645
|
const messagesToProcess = batch.filter((message) => {
|
|
1325
1646
|
if (isChangeMessage(message)) {
|
|
@@ -1334,6 +1655,14 @@ onMessages_fn = function(batch, isSseMessage = false) {
|
|
|
1334
1655
|
fetchShape_fn = function(opts) {
|
|
1335
1656
|
return __async(this, null, function* () {
|
|
1336
1657
|
var _a;
|
|
1658
|
+
__privateSet(this, _currentFetchUrl, opts.fetchUrl);
|
|
1659
|
+
if (!__privateGet(this, _isUpToDate) && !__privateGet(this, _ShapeStream_instances, replayMode_get)) {
|
|
1660
|
+
const shapeKey = canonicalShapeKey(opts.fetchUrl);
|
|
1661
|
+
const lastSeenCursor = upToDateTracker.shouldEnterReplayMode(shapeKey);
|
|
1662
|
+
if (lastSeenCursor) {
|
|
1663
|
+
__privateSet(this, _lastSeenCursor, lastSeenCursor);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1337
1666
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1338
1667
|
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling)) {
|
|
1339
1668
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
@@ -1804,9 +2133,13 @@ notify_fn = function() {
|
|
|
1804
2133
|
FetchError,
|
|
1805
2134
|
Shape,
|
|
1806
2135
|
ShapeStream,
|
|
2136
|
+
camelToSnake,
|
|
2137
|
+
createColumnMapper,
|
|
1807
2138
|
isChangeMessage,
|
|
1808
2139
|
isControlMessage,
|
|
1809
2140
|
isVisibleInSnapshot,
|
|
1810
|
-
resolveValue
|
|
2141
|
+
resolveValue,
|
|
2142
|
+
snakeCamelMapper,
|
|
2143
|
+
snakeToCamel
|
|
1811
2144
|
});
|
|
1812
2145
|
//# sourceMappingURL=index.cjs.map
|