@electric-sql/client 1.2.1 → 1.3.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/index.d.ts CHANGED
@@ -45,13 +45,22 @@ type MoveOutPattern = {
45
45
  pos: number;
46
46
  value: string;
47
47
  };
48
+ type SubsetParams = {
49
+ where?: string;
50
+ params?: Record<string, string>;
51
+ limit?: number;
52
+ offset?: number;
53
+ orderBy?: string;
54
+ };
48
55
  type ControlMessage = {
49
56
  headers: (Header & {
50
57
  control: `up-to-date` | `must-refetch`;
51
58
  global_last_seen_lsn?: string;
52
59
  }) | (Header & {
53
60
  control: `snapshot-end`;
54
- } & PostgresSnapshot);
61
+ } & PostgresSnapshot) | (Header & {
62
+ control: `subset-end`;
63
+ } & SubsetParams);
55
64
  };
56
65
  type EventMessage = {
57
66
  headers: Header & {
@@ -377,13 +386,6 @@ type ExternalParamsRecord<T extends Row<unknown> = Row> = {
377
386
  } & Partial<PostgresParams<T>> & {
378
387
  [K in ReservedParamKeys]?: never;
379
388
  };
380
- type SubsetParams = {
381
- where?: string;
382
- params?: Record<string, string>;
383
- limit?: number;
384
- offset?: number;
385
- orderBy?: string;
386
- };
387
389
  type ReservedParamKeys = typeof LIVE_CACHE_BUSTER_QUERY_PARAM | typeof SHAPE_HANDLE_QUERY_PARAM | typeof LIVE_QUERY_PARAM | typeof OFFSET_QUERY_PARAM | `subset__${string}`;
388
390
  /**
389
391
  * External headers type - what users provide.
@@ -270,6 +270,10 @@ function makeNullableParser(parser, columnInfo, columnName) {
270
270
  }
271
271
 
272
272
  // src/column-mapper.ts
273
+ function quoteIdentifier(identifier) {
274
+ const escaped = identifier.replace(/"/g, `""`);
275
+ return `"${escaped}"`;
276
+ }
273
277
  function snakeToCamel(str) {
274
278
  var _a, _b, _c, _d;
275
279
  const leadingUnderscores = (_b = (_a = str.match(/^_+/)) == null ? void 0 : _a[0]) != null ? _b : ``;
@@ -425,11 +429,9 @@ function isUpToDateMessage(message) {
425
429
  return isControlMessage(message) && message.headers.control === `up-to-date`;
426
430
  }
427
431
  function getOffset(message) {
432
+ if (message.headers.control != `up-to-date`) return;
428
433
  const lsn = message.headers.global_last_seen_lsn;
429
- if (!lsn) {
430
- return;
431
- }
432
- return `${lsn}_0`;
434
+ return lsn ? `${lsn}_0` : void 0;
433
435
  }
434
436
  function isVisibleInSnapshot(txid, snapshot) {
435
437
  const xid = BigInt(txid);
@@ -599,6 +601,7 @@ function createFetchWithChunkBuffer(fetchClient, prefetchOptions = ChunkPrefetch
599
601
  return prefetchedRequest;
600
602
  }
601
603
  prefetchQueue == null ? void 0 : prefetchQueue.abort();
604
+ prefetchQueue = void 0;
602
605
  const response = await fetchClient(...args);
603
606
  const nextUrl = getNextChunkUrl(url, response);
604
607
  if (nextUrl) {
@@ -671,12 +674,17 @@ var PrefetchQueue = class {
671
674
  }
672
675
  abort() {
673
676
  __privateGet(this, _prefetchQueue).forEach(([_, aborter]) => aborter.abort());
677
+ __privateGet(this, _prefetchQueue).clear();
674
678
  }
675
679
  consume(...args) {
676
- var _a;
677
680
  const url = args[0].toString();
678
- const request = (_a = __privateGet(this, _prefetchQueue).get(url)) == null ? void 0 : _a[0];
679
- if (!request || url !== __privateGet(this, _queueHeadUrl)) return;
681
+ const entry = __privateGet(this, _prefetchQueue).get(url);
682
+ if (!entry || url !== __privateGet(this, _queueHeadUrl)) return;
683
+ const [request, aborter] = entry;
684
+ if (aborter.signal.aborted) {
685
+ __privateGet(this, _prefetchQueue).delete(url);
686
+ return;
687
+ }
680
688
  __privateGet(this, _prefetchQueue).delete(url);
681
689
  request.then((response) => {
682
690
  const nextUrl = getNextChunkUrl(url, response);
@@ -1227,7 +1235,8 @@ var ShapeStream = class {
1227
1235
  }
1228
1236
  const { metadata, data } = await this.fetchSnapshot(opts);
1229
1237
  const dataWithEndBoundary = data.concat([
1230
- { headers: __spreadValues({ control: `snapshot-end` }, metadata) }
1238
+ { headers: __spreadValues({ control: `snapshot-end` }, metadata) },
1239
+ { headers: __spreadValues({ control: `subset-end` }, opts) }
1231
1240
  ]);
1232
1241
  __privateGet(this, _snapshotTracker).addSnapshot(
1233
1242
  metadata,
@@ -1417,7 +1426,7 @@ requestShape_fn = async function() {
1417
1426
  return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
1418
1427
  };
1419
1428
  constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1420
- var _a, _b, _c;
1429
+ var _a, _b, _c, _d;
1421
1430
  const [requestHeaders, params] = await Promise.all([
1422
1431
  resolveHeaders(this.options.headers),
1423
1432
  this.options.params ? toInternalParams(convertWhereParamsToObj(this.options.params)) : void 0
@@ -1433,8 +1442,21 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1433
1442
  );
1434
1443
  setQueryParam(fetchUrl, WHERE_QUERY_PARAM, encodedWhere);
1435
1444
  }
1436
- if (params.columns)
1437
- setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
1445
+ if (params.columns) {
1446
+ const originalColumns = await resolveValue((_b = this.options.params) == null ? void 0 : _b.columns);
1447
+ if (Array.isArray(originalColumns)) {
1448
+ let encodedColumns = originalColumns.map(String);
1449
+ if (this.options.columnMapper) {
1450
+ encodedColumns = encodedColumns.map(
1451
+ this.options.columnMapper.encode
1452
+ );
1453
+ }
1454
+ const serializedColumns = encodedColumns.map(quoteIdentifier).join(`,`);
1455
+ setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, serializedColumns);
1456
+ } else {
1457
+ setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns);
1458
+ }
1459
+ }
1438
1460
  if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica);
1439
1461
  if (params.params)
1440
1462
  setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params);
@@ -1452,7 +1474,7 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1452
1474
  if (subsetParams.where && typeof subsetParams.where === `string`) {
1453
1475
  const encodedWhere = encodeWhereClause(
1454
1476
  subsetParams.where,
1455
- (_b = this.options.columnMapper) == null ? void 0 : _b.encode
1477
+ (_c = this.options.columnMapper) == null ? void 0 : _c.encode
1456
1478
  );
1457
1479
  setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, encodedWhere);
1458
1480
  }
@@ -1468,7 +1490,7 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1468
1490
  if (subsetParams.orderBy && typeof subsetParams.orderBy === `string`) {
1469
1491
  const encodedOrderBy = encodeWhereClause(
1470
1492
  subsetParams.orderBy,
1471
- (_c = this.options.columnMapper) == null ? void 0 : _c.encode
1493
+ (_d = this.options.columnMapper) == null ? void 0 : _d.encode
1472
1494
  );
1473
1495
  setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
1474
1496
  }
@@ -1674,7 +1696,11 @@ pause_fn = function() {
1674
1696
  }
1675
1697
  };
1676
1698
  resume_fn = function() {
1699
+ var _a;
1677
1700
  if (__privateGet(this, _started) && (__privateGet(this, _state) === `paused` || __privateGet(this, _state) === `pause-requested`)) {
1701
+ if ((_a = this.options.signal) == null ? void 0 : _a.aborted) {
1702
+ return;
1703
+ }
1678
1704
  if (__privateGet(this, _state) === `pause-requested`) {
1679
1705
  __privateSet(this, _state, `active`);
1680
1706
  }