@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.mjs
CHANGED
|
@@ -291,6 +291,151 @@ function makeNullableParser(parser, columnInfo, columnName) {
|
|
|
291
291
|
};
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
// src/column-mapper.ts
|
|
295
|
+
function snakeToCamel(str) {
|
|
296
|
+
var _a, _b, _c, _d;
|
|
297
|
+
const leadingUnderscores = (_b = (_a = str.match(/^_+/)) == null ? void 0 : _a[0]) != null ? _b : ``;
|
|
298
|
+
const withoutLeading = str.slice(leadingUnderscores.length);
|
|
299
|
+
const trailingUnderscores = (_d = (_c = withoutLeading.match(/_+$/)) == null ? void 0 : _c[0]) != null ? _d : ``;
|
|
300
|
+
const core = trailingUnderscores ? withoutLeading.slice(
|
|
301
|
+
0,
|
|
302
|
+
withoutLeading.length - trailingUnderscores.length
|
|
303
|
+
) : withoutLeading;
|
|
304
|
+
const normalized = core.toLowerCase();
|
|
305
|
+
const camelCased = normalized.replace(
|
|
306
|
+
/_+([a-z])/g,
|
|
307
|
+
(_, letter) => letter.toUpperCase()
|
|
308
|
+
);
|
|
309
|
+
return leadingUnderscores + camelCased + trailingUnderscores;
|
|
310
|
+
}
|
|
311
|
+
function camelToSnake(str) {
|
|
312
|
+
return str.replace(/([a-z])([A-Z])/g, `$1_$2`).replace(/([A-Z]+)([A-Z][a-z])/g, `$1_$2`).toLowerCase();
|
|
313
|
+
}
|
|
314
|
+
function createColumnMapper(mapping) {
|
|
315
|
+
const reverseMapping = {};
|
|
316
|
+
for (const [dbName, appName] of Object.entries(mapping)) {
|
|
317
|
+
reverseMapping[appName] = dbName;
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
decode: (dbColumnName) => {
|
|
321
|
+
var _a;
|
|
322
|
+
return (_a = mapping[dbColumnName]) != null ? _a : dbColumnName;
|
|
323
|
+
},
|
|
324
|
+
encode: (appColumnName) => {
|
|
325
|
+
var _a;
|
|
326
|
+
return (_a = reverseMapping[appColumnName]) != null ? _a : appColumnName;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function encodeWhereClause(whereClause, encode) {
|
|
331
|
+
if (!whereClause || !encode) return whereClause != null ? whereClause : ``;
|
|
332
|
+
const sqlKeywords = /* @__PURE__ */ new Set([
|
|
333
|
+
`SELECT`,
|
|
334
|
+
`FROM`,
|
|
335
|
+
`WHERE`,
|
|
336
|
+
`AND`,
|
|
337
|
+
`OR`,
|
|
338
|
+
`NOT`,
|
|
339
|
+
`IN`,
|
|
340
|
+
`IS`,
|
|
341
|
+
`NULL`,
|
|
342
|
+
`NULLS`,
|
|
343
|
+
`FIRST`,
|
|
344
|
+
`LAST`,
|
|
345
|
+
`TRUE`,
|
|
346
|
+
`FALSE`,
|
|
347
|
+
`LIKE`,
|
|
348
|
+
`ILIKE`,
|
|
349
|
+
`BETWEEN`,
|
|
350
|
+
`ASC`,
|
|
351
|
+
`DESC`,
|
|
352
|
+
`LIMIT`,
|
|
353
|
+
`OFFSET`,
|
|
354
|
+
`ORDER`,
|
|
355
|
+
`BY`,
|
|
356
|
+
`GROUP`,
|
|
357
|
+
`HAVING`,
|
|
358
|
+
`DISTINCT`,
|
|
359
|
+
`AS`,
|
|
360
|
+
`ON`,
|
|
361
|
+
`JOIN`,
|
|
362
|
+
`LEFT`,
|
|
363
|
+
`RIGHT`,
|
|
364
|
+
`INNER`,
|
|
365
|
+
`OUTER`,
|
|
366
|
+
`CROSS`,
|
|
367
|
+
`CASE`,
|
|
368
|
+
`WHEN`,
|
|
369
|
+
`THEN`,
|
|
370
|
+
`ELSE`,
|
|
371
|
+
`END`,
|
|
372
|
+
`CAST`,
|
|
373
|
+
`LOWER`,
|
|
374
|
+
`UPPER`,
|
|
375
|
+
`COALESCE`,
|
|
376
|
+
`NULLIF`
|
|
377
|
+
]);
|
|
378
|
+
const quotedRanges = [];
|
|
379
|
+
let pos = 0;
|
|
380
|
+
while (pos < whereClause.length) {
|
|
381
|
+
const ch = whereClause[pos];
|
|
382
|
+
if (ch === `'` || ch === `"`) {
|
|
383
|
+
const start = pos;
|
|
384
|
+
const quoteChar = ch;
|
|
385
|
+
pos++;
|
|
386
|
+
while (pos < whereClause.length) {
|
|
387
|
+
if (whereClause[pos] === quoteChar) {
|
|
388
|
+
if (whereClause[pos + 1] === quoteChar) {
|
|
389
|
+
pos += 2;
|
|
390
|
+
} else {
|
|
391
|
+
pos++;
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
pos++;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
quotedRanges.push({ start, end: pos });
|
|
399
|
+
} else {
|
|
400
|
+
pos++;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const isInQuotedString = (pos2) => {
|
|
404
|
+
return quotedRanges.some((range) => pos2 >= range.start && pos2 < range.end);
|
|
405
|
+
};
|
|
406
|
+
const identifierPattern = new RegExp("(?<![a-zA-Z0-9_])([a-zA-Z_][a-zA-Z0-9_]*)(?![a-zA-Z0-9_])", "g");
|
|
407
|
+
return whereClause.replace(identifierPattern, (match, _p1, offset) => {
|
|
408
|
+
if (isInQuotedString(offset)) {
|
|
409
|
+
return match;
|
|
410
|
+
}
|
|
411
|
+
if (sqlKeywords.has(match.toUpperCase())) {
|
|
412
|
+
return match;
|
|
413
|
+
}
|
|
414
|
+
if (match.startsWith(`$`)) {
|
|
415
|
+
return match;
|
|
416
|
+
}
|
|
417
|
+
const encoded = encode(match);
|
|
418
|
+
return encoded;
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
function snakeCamelMapper(schema) {
|
|
422
|
+
if (schema) {
|
|
423
|
+
const mapping = {};
|
|
424
|
+
for (const dbColumn of Object.keys(schema)) {
|
|
425
|
+
mapping[dbColumn] = snakeToCamel(dbColumn);
|
|
426
|
+
}
|
|
427
|
+
return createColumnMapper(mapping);
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
decode: (dbColumnName) => {
|
|
431
|
+
return snakeToCamel(dbColumnName);
|
|
432
|
+
},
|
|
433
|
+
encode: (appColumnName) => {
|
|
434
|
+
return camelToSnake(appColumnName);
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
294
439
|
// src/helpers.ts
|
|
295
440
|
function isChangeMessage(message) {
|
|
296
441
|
return `key` in message;
|
|
@@ -686,6 +831,127 @@ var ExpiredShapesCache = class {
|
|
|
686
831
|
};
|
|
687
832
|
var expiredShapesCache = new ExpiredShapesCache();
|
|
688
833
|
|
|
834
|
+
// src/up-to-date-tracker.ts
|
|
835
|
+
var UpToDateTracker = class {
|
|
836
|
+
constructor() {
|
|
837
|
+
this.data = {};
|
|
838
|
+
this.storageKey = `electric_up_to_date_tracker`;
|
|
839
|
+
this.cacheTTL = 6e4;
|
|
840
|
+
// 60s to match typical CDN s-maxage cache duration
|
|
841
|
+
this.maxEntries = 250;
|
|
842
|
+
this.writeThrottleMs = 6e4;
|
|
843
|
+
// Throttle localStorage writes to once per 60s
|
|
844
|
+
this.lastWriteTime = 0;
|
|
845
|
+
this.load();
|
|
846
|
+
this.cleanup();
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Records that a shape received an up-to-date message with a specific cursor.
|
|
850
|
+
* This timestamp and cursor are used to detect cache replay scenarios.
|
|
851
|
+
* Updates in-memory immediately, but throttles localStorage writes.
|
|
852
|
+
*/
|
|
853
|
+
recordUpToDate(shapeKey, cursor) {
|
|
854
|
+
this.data[shapeKey] = {
|
|
855
|
+
timestamp: Date.now(),
|
|
856
|
+
cursor
|
|
857
|
+
};
|
|
858
|
+
const keys = Object.keys(this.data);
|
|
859
|
+
if (keys.length > this.maxEntries) {
|
|
860
|
+
const oldest = keys.reduce(
|
|
861
|
+
(min, k) => this.data[k].timestamp < this.data[min].timestamp ? k : min
|
|
862
|
+
);
|
|
863
|
+
delete this.data[oldest];
|
|
864
|
+
}
|
|
865
|
+
this.scheduleSave();
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Schedules a throttled save to localStorage.
|
|
869
|
+
* Writes immediately if enough time has passed, otherwise schedules for later.
|
|
870
|
+
*/
|
|
871
|
+
scheduleSave() {
|
|
872
|
+
const now = Date.now();
|
|
873
|
+
const timeSinceLastWrite = now - this.lastWriteTime;
|
|
874
|
+
if (timeSinceLastWrite >= this.writeThrottleMs) {
|
|
875
|
+
this.lastWriteTime = now;
|
|
876
|
+
this.save();
|
|
877
|
+
} else if (!this.pendingSaveTimer) {
|
|
878
|
+
const delay = this.writeThrottleMs - timeSinceLastWrite;
|
|
879
|
+
this.pendingSaveTimer = setTimeout(() => {
|
|
880
|
+
this.lastWriteTime = Date.now();
|
|
881
|
+
this.pendingSaveTimer = void 0;
|
|
882
|
+
this.save();
|
|
883
|
+
}, delay);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Checks if we should enter replay mode for this shape.
|
|
888
|
+
* Returns the last seen cursor if there's a recent up-to-date (< 60s),
|
|
889
|
+
* which means we'll likely be replaying cached responses.
|
|
890
|
+
* Returns null if no recent up-to-date exists.
|
|
891
|
+
*/
|
|
892
|
+
shouldEnterReplayMode(shapeKey) {
|
|
893
|
+
const entry = this.data[shapeKey];
|
|
894
|
+
if (!entry) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
const age = Date.now() - entry.timestamp;
|
|
898
|
+
if (age >= this.cacheTTL) {
|
|
899
|
+
return null;
|
|
900
|
+
}
|
|
901
|
+
return entry.cursor;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Cleans up expired entries from the cache.
|
|
905
|
+
* Called on initialization and can be called periodically.
|
|
906
|
+
*/
|
|
907
|
+
cleanup() {
|
|
908
|
+
const now = Date.now();
|
|
909
|
+
const keys = Object.keys(this.data);
|
|
910
|
+
let modified = false;
|
|
911
|
+
for (const key of keys) {
|
|
912
|
+
const age = now - this.data[key].timestamp;
|
|
913
|
+
if (age > this.cacheTTL) {
|
|
914
|
+
delete this.data[key];
|
|
915
|
+
modified = true;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (modified) {
|
|
919
|
+
this.save();
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
save() {
|
|
923
|
+
if (typeof localStorage === `undefined`) return;
|
|
924
|
+
try {
|
|
925
|
+
localStorage.setItem(this.storageKey, JSON.stringify(this.data));
|
|
926
|
+
} catch (e) {
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
load() {
|
|
930
|
+
if (typeof localStorage === `undefined`) return;
|
|
931
|
+
try {
|
|
932
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
933
|
+
if (stored) {
|
|
934
|
+
this.data = JSON.parse(stored);
|
|
935
|
+
}
|
|
936
|
+
} catch (e) {
|
|
937
|
+
this.data = {};
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Clears all tracked up-to-date timestamps.
|
|
942
|
+
* Useful for testing or manual cache invalidation.
|
|
943
|
+
*/
|
|
944
|
+
clear() {
|
|
945
|
+
this.data = {};
|
|
946
|
+
if (this.pendingSaveTimer) {
|
|
947
|
+
clearTimeout(this.pendingSaveTimer);
|
|
948
|
+
this.pendingSaveTimer = void 0;
|
|
949
|
+
}
|
|
950
|
+
this.save();
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
var upToDateTracker = new UpToDateTracker();
|
|
954
|
+
|
|
689
955
|
// src/snapshot-tracker.ts
|
|
690
956
|
var SnapshotTracker = class {
|
|
691
957
|
constructor() {
|
|
@@ -803,7 +1069,7 @@ function canonicalShapeKey(url) {
|
|
|
803
1069
|
cleanUrl.searchParams.sort();
|
|
804
1070
|
return cleanUrl.toString();
|
|
805
1071
|
}
|
|
806
|
-
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;
|
|
1072
|
+
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;
|
|
807
1073
|
var ShapeStream = class {
|
|
808
1074
|
constructor(options) {
|
|
809
1075
|
__privateAdd(this, _ShapeStream_instances);
|
|
@@ -838,6 +1104,10 @@ var ShapeStream = class {
|
|
|
838
1104
|
// counter for concurrent snapshot requests
|
|
839
1105
|
__privateAdd(this, _midStreamPromise);
|
|
840
1106
|
__privateAdd(this, _midStreamPromiseResolver);
|
|
1107
|
+
__privateAdd(this, _lastSeenCursor);
|
|
1108
|
+
// Last seen cursor from previous session (used to detect cached responses)
|
|
1109
|
+
__privateAdd(this, _currentFetchUrl);
|
|
1110
|
+
// Current fetch URL for computing shape key
|
|
841
1111
|
__privateAdd(this, _lastSseConnectionStartTime);
|
|
842
1112
|
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
843
1113
|
// Minimum expected SSE connection duration (1 second)
|
|
@@ -856,10 +1126,21 @@ var ShapeStream = class {
|
|
|
856
1126
|
__privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
|
|
857
1127
|
__privateSet(this, _liveCacheBuster, ``);
|
|
858
1128
|
__privateSet(this, _shapeHandle, this.options.handle);
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1129
|
+
let transformer;
|
|
1130
|
+
if (options.columnMapper) {
|
|
1131
|
+
const applyColumnMapper = (row) => {
|
|
1132
|
+
const result = {};
|
|
1133
|
+
for (const [dbKey, value] of Object.entries(row)) {
|
|
1134
|
+
const appKey = options.columnMapper.decode(dbKey);
|
|
1135
|
+
result[appKey] = value;
|
|
1136
|
+
}
|
|
1137
|
+
return result;
|
|
1138
|
+
};
|
|
1139
|
+
transformer = options.transformer ? (row) => options.transformer(applyColumnMapper(row)) : applyColumnMapper;
|
|
1140
|
+
} else {
|
|
1141
|
+
transformer = options.transformer;
|
|
1142
|
+
}
|
|
1143
|
+
__privateSet(this, _messageParser, new MessageParser(options.parser, transformer));
|
|
863
1144
|
__privateSet(this, _onError, this.options.onError);
|
|
864
1145
|
__privateSet(this, _mode, (_b = this.options.log) != null ? _b : `full`);
|
|
865
1146
|
const baseFetchClient = (_c = options.fetchClient) != null ? _c : (...args) => fetch(...args);
|
|
@@ -1064,6 +1345,8 @@ _snapshotTracker = new WeakMap();
|
|
|
1064
1345
|
_activeSnapshotRequests = new WeakMap();
|
|
1065
1346
|
_midStreamPromise = new WeakMap();
|
|
1066
1347
|
_midStreamPromiseResolver = new WeakMap();
|
|
1348
|
+
_lastSeenCursor = new WeakMap();
|
|
1349
|
+
_currentFetchUrl = new WeakMap();
|
|
1067
1350
|
_lastSseConnectionStartTime = new WeakMap();
|
|
1068
1351
|
_minSseConnectionDuration = new WeakMap();
|
|
1069
1352
|
_consecutiveShortSseConnections = new WeakMap();
|
|
@@ -1073,6 +1356,9 @@ _sseBackoffBaseDelay = new WeakMap();
|
|
|
1073
1356
|
_sseBackoffMaxDelay = new WeakMap();
|
|
1074
1357
|
_unsubscribeFromVisibilityChanges = new WeakMap();
|
|
1075
1358
|
_ShapeStream_instances = new WeakSet();
|
|
1359
|
+
replayMode_get = function() {
|
|
1360
|
+
return __privateGet(this, _lastSeenCursor) !== void 0;
|
|
1361
|
+
};
|
|
1076
1362
|
start_fn = function() {
|
|
1077
1363
|
return __async(this, null, function* () {
|
|
1078
1364
|
var _a, _b, _c, _d, _e;
|
|
@@ -1172,6 +1458,7 @@ requestShape_fn = function() {
|
|
|
1172
1458
|
};
|
|
1173
1459
|
constructUrl_fn = function(url, resumingFromPause, subsetParams) {
|
|
1174
1460
|
return __async(this, null, function* () {
|
|
1461
|
+
var _a, _b, _c;
|
|
1175
1462
|
const [requestHeaders, params] = yield Promise.all([
|
|
1176
1463
|
resolveHeaders(this.options.headers),
|
|
1177
1464
|
this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
|
|
@@ -1180,7 +1467,13 @@ constructUrl_fn = function(url, resumingFromPause, subsetParams) {
|
|
|
1180
1467
|
const fetchUrl = new URL(url);
|
|
1181
1468
|
if (params) {
|
|
1182
1469
|
if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table);
|
|
1183
|
-
if (params.where
|
|
1470
|
+
if (params.where && typeof params.where === `string`) {
|
|
1471
|
+
const encodedWhere = encodeWhereClause(
|
|
1472
|
+
params.where,
|
|
1473
|
+
(_a = this.options.columnMapper) == null ? void 0 : _a.encode
|
|
1474
|
+
);
|
|
1475
|
+
setQueryParam(fetchUrl, WHERE_QUERY_PARAM, encodedWhere);
|
|
1476
|
+
}
|
|
1184
1477
|
if (params.columns)
|
|
1185
1478
|
setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
|
|
1186
1479
|
if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
|
|
@@ -1197,16 +1490,29 @@ constructUrl_fn = function(url, resumingFromPause, subsetParams) {
|
|
|
1197
1490
|
}
|
|
1198
1491
|
}
|
|
1199
1492
|
if (subsetParams) {
|
|
1200
|
-
if (subsetParams.where)
|
|
1201
|
-
|
|
1493
|
+
if (subsetParams.where && typeof subsetParams.where === `string`) {
|
|
1494
|
+
const encodedWhere = encodeWhereClause(
|
|
1495
|
+
subsetParams.where,
|
|
1496
|
+
(_b = this.options.columnMapper) == null ? void 0 : _b.encode
|
|
1497
|
+
);
|
|
1498
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, encodedWhere);
|
|
1499
|
+
}
|
|
1202
1500
|
if (subsetParams.params)
|
|
1203
|
-
|
|
1501
|
+
fetchUrl.searchParams.set(
|
|
1502
|
+
SUBSET_PARAM_WHERE_PARAMS,
|
|
1503
|
+
JSON.stringify(subsetParams.params)
|
|
1504
|
+
);
|
|
1204
1505
|
if (subsetParams.limit)
|
|
1205
1506
|
setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit);
|
|
1206
1507
|
if (subsetParams.offset)
|
|
1207
1508
|
setQueryParam(fetchUrl, SUBSET_PARAM_OFFSET, subsetParams.offset);
|
|
1208
|
-
if (subsetParams.orderBy)
|
|
1209
|
-
|
|
1509
|
+
if (subsetParams.orderBy && typeof subsetParams.orderBy === `string`) {
|
|
1510
|
+
const encodedOrderBy = encodeWhereClause(
|
|
1511
|
+
subsetParams.orderBy,
|
|
1512
|
+
(_c = this.options.columnMapper) == null ? void 0 : _c.encode
|
|
1513
|
+
);
|
|
1514
|
+
setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
|
|
1515
|
+
}
|
|
1210
1516
|
}
|
|
1211
1517
|
fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
|
|
1212
1518
|
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
@@ -1291,6 +1597,17 @@ onMessages_fn = function(batch, isSseMessage = false) {
|
|
|
1291
1597
|
__privateSet(this, _isUpToDate, true);
|
|
1292
1598
|
__privateSet(this, _isMidStream, false);
|
|
1293
1599
|
(_a = __privateGet(this, _midStreamPromiseResolver)) == null ? void 0 : _a.call(this);
|
|
1600
|
+
if (__privateGet(this, _ShapeStream_instances, replayMode_get) && !isSseMessage) {
|
|
1601
|
+
const currentCursor = __privateGet(this, _liveCacheBuster);
|
|
1602
|
+
if (currentCursor === __privateGet(this, _lastSeenCursor)) {
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
__privateSet(this, _lastSeenCursor, void 0);
|
|
1607
|
+
if (__privateGet(this, _currentFetchUrl)) {
|
|
1608
|
+
const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
|
|
1609
|
+
upToDateTracker.recordUpToDate(shapeKey, __privateGet(this, _liveCacheBuster));
|
|
1610
|
+
}
|
|
1294
1611
|
}
|
|
1295
1612
|
const messagesToProcess = batch.filter((message) => {
|
|
1296
1613
|
if (isChangeMessage(message)) {
|
|
@@ -1305,6 +1622,14 @@ onMessages_fn = function(batch, isSseMessage = false) {
|
|
|
1305
1622
|
fetchShape_fn = function(opts) {
|
|
1306
1623
|
return __async(this, null, function* () {
|
|
1307
1624
|
var _a;
|
|
1625
|
+
__privateSet(this, _currentFetchUrl, opts.fetchUrl);
|
|
1626
|
+
if (!__privateGet(this, _isUpToDate) && !__privateGet(this, _ShapeStream_instances, replayMode_get)) {
|
|
1627
|
+
const shapeKey = canonicalShapeKey(opts.fetchUrl);
|
|
1628
|
+
const lastSeenCursor = upToDateTracker.shouldEnterReplayMode(shapeKey);
|
|
1629
|
+
if (lastSeenCursor) {
|
|
1630
|
+
__privateSet(this, _lastSeenCursor, lastSeenCursor);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1308
1633
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1309
1634
|
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling)) {
|
|
1310
1635
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
@@ -1335,10 +1660,13 @@ requestShapeSSE_fn = function(opts) {
|
|
|
1335
1660
|
const { fetchUrl, requestAbortController, headers } = opts;
|
|
1336
1661
|
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
1337
1662
|
__privateSet(this, _lastSseConnectionStartTime, Date.now());
|
|
1663
|
+
const sseHeaders = __spreadProps(__spreadValues({}, headers), {
|
|
1664
|
+
Accept: `text/event-stream`
|
|
1665
|
+
});
|
|
1338
1666
|
try {
|
|
1339
1667
|
let buffer = [];
|
|
1340
1668
|
yield fetchEventSource(fetchUrl.toString(), {
|
|
1341
|
-
headers,
|
|
1669
|
+
headers: sseHeaders,
|
|
1342
1670
|
fetch: fetch2,
|
|
1343
1671
|
onopen: (response) => __async(this, null, function* () {
|
|
1344
1672
|
__privateSet(this, _connected, true);
|
|
@@ -1774,9 +2102,13 @@ export {
|
|
|
1774
2102
|
FetchError,
|
|
1775
2103
|
Shape,
|
|
1776
2104
|
ShapeStream,
|
|
2105
|
+
camelToSnake,
|
|
2106
|
+
createColumnMapper,
|
|
1777
2107
|
isChangeMessage,
|
|
1778
2108
|
isControlMessage,
|
|
1779
2109
|
isVisibleInSnapshot,
|
|
1780
|
-
resolveValue
|
|
2110
|
+
resolveValue,
|
|
2111
|
+
snakeCamelMapper,
|
|
2112
|
+
snakeToCamel
|
|
1781
2113
|
};
|
|
1782
2114
|
//# sourceMappingURL=index.mjs.map
|