@electric-sql/client 1.4.2 → 1.5.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
@@ -84,6 +84,16 @@ type SubsetParams = {
84
84
  whereExpr?: SerializedExpression;
85
85
  /** Structured ORDER BY clauses (preferred when available) */
86
86
  orderByExpr?: SerializedOrderByClause[];
87
+ /**
88
+ * HTTP method to use for the request. Overrides `subsetMethod` from ShapeStreamOptions.
89
+ * - `GET` (default): Sends subset params as query parameters. May fail with 414 errors
90
+ * for large queries.
91
+ * - `POST`: Sends subset params in request body as JSON. Recommended to avoid URL
92
+ * length limits with large WHERE clauses or many parameters.
93
+ *
94
+ * In Electric 2.0, GET will be deprecated and only POST will be supported.
95
+ */
96
+ method?: `GET` | `POST`;
87
97
  };
88
98
  type ControlMessage = {
89
99
  headers: (Header & {
@@ -629,6 +639,26 @@ interface ShapeStreamOptions<T = never> {
629
639
  * ```
630
640
  */
631
641
  onError?: ShapeStreamErrorHandler;
642
+ /**
643
+ * HTTP method to use for subset snapshot requests (`requestSnapshot`/`fetchSnapshot`).
644
+ *
645
+ * - `'GET'` (default): Sends subset params as URL query parameters. May fail with
646
+ * HTTP 414 errors for large queries with many parameters.
647
+ * - `'POST'`: Sends subset params in request body as JSON. Recommended for queries
648
+ * with large parameter lists (e.g., `WHERE id = ANY($1)` with hundreds of IDs).
649
+ *
650
+ * This can be overridden per-request by passing `method` in the subset params.
651
+ *
652
+ * @example
653
+ * ```typescript
654
+ * const stream = new ShapeStream({
655
+ * url: 'http://localhost:3000/v1/shape',
656
+ * params: { table: 'items' },
657
+ * subsetMethod: 'POST', // Use POST for all subset requests
658
+ * })
659
+ * ```
660
+ */
661
+ subsetMethod?: `GET` | `POST`;
632
662
  }
633
663
  interface ShapeStreamInterface<T extends Row<unknown> = Row> {
634
664
  subscribe(callback: (messages: Message<T>[]) => MaybePromise<void> | {
@@ -748,6 +778,10 @@ declare class ShapeStream<T extends Row<unknown> = Row> implements ShapeStreamIn
748
778
  * Fetch a snapshot for subset of data.
749
779
  * Returns the metadata and the data, but does not inject it into the subscribed data stream.
750
780
  *
781
+ * By default, uses GET to send subset parameters as query parameters. This may hit URL length
782
+ * limits (HTTP 414) with large WHERE clauses or many parameters. Set `method: 'POST'` or use
783
+ * `subsetMethod: 'POST'` on the stream to send parameters in the request body instead.
784
+ *
751
785
  * @param opts - The options for the snapshot request.
752
786
  * @returns The metadata and the data for the snapshot.
753
787
  */
@@ -1142,7 +1142,7 @@ function canonicalShapeKey(url) {
1142
1142
  cleanUrl.searchParams.sort();
1143
1143
  return cleanUrl.toString();
1144
1144
  }
1145
- 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, _staleCacheBuster, _staleCacheRetryCount, _maxStaleCacheRetries, _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;
1145
+ 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, _staleCacheBuster, _staleCacheRetryCount, _maxStaleCacheRetries, _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, buildSubsetBody_fn;
1146
1146
  var ShapeStream = class {
1147
1147
  constructor(options) {
1148
1148
  __privateAdd(this, _ShapeStream_instances);
@@ -1357,25 +1357,39 @@ var ShapeStream = class {
1357
1357
  * Fetch a snapshot for subset of data.
1358
1358
  * Returns the metadata and the data, but does not inject it into the subscribed data stream.
1359
1359
  *
1360
+ * By default, uses GET to send subset parameters as query parameters. This may hit URL length
1361
+ * limits (HTTP 414) with large WHERE clauses or many parameters. Set `method: 'POST'` or use
1362
+ * `subsetMethod: 'POST'` on the stream to send parameters in the request body instead.
1363
+ *
1360
1364
  * @param opts - The options for the snapshot request.
1361
1365
  * @returns The metadata and the data for the snapshot.
1362
1366
  */
1363
1367
  async fetchSnapshot(opts) {
1364
- var _a;
1365
- const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
1366
- const response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), {
1367
- headers: requestHeaders
1368
- });
1368
+ var _a, _b, _c;
1369
+ const method = (_b = (_a = opts.method) != null ? _a : this.options.subsetMethod) != null ? _b : `GET`;
1370
+ const usePost = method === `POST`;
1371
+ let fetchUrl;
1372
+ let fetchOptions;
1373
+ if (usePost) {
1374
+ const result = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true);
1375
+ fetchUrl = result.fetchUrl;
1376
+ fetchOptions = {
1377
+ method: `POST`,
1378
+ headers: __spreadProps(__spreadValues({}, result.requestHeaders), {
1379
+ "Content-Type": `application/json`
1380
+ }),
1381
+ body: JSON.stringify(__privateMethod(this, _ShapeStream_instances, buildSubsetBody_fn).call(this, opts))
1382
+ };
1383
+ } else {
1384
+ const result = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, this.options.url, true, opts);
1385
+ fetchUrl = result.fetchUrl;
1386
+ fetchOptions = { headers: result.requestHeaders };
1387
+ }
1388
+ const response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), fetchOptions);
1369
1389
  if (!response.ok) {
1370
- throw new FetchError(
1371
- response.status,
1372
- void 0,
1373
- void 0,
1374
- Object.fromEntries([...response.headers.entries()]),
1375
- fetchUrl.toString()
1376
- );
1390
+ throw await FetchError.fromResponse(response, fetchUrl.toString());
1377
1391
  }
1378
- const schema = (_a = __privateGet(this, _schema)) != null ? _a : getSchemaFromHeaders(response.headers, {
1392
+ const schema = (_c = __privateGet(this, _schema)) != null ? _c : getSchemaFromHeaders(response.headers, {
1379
1393
  required: true,
1380
1394
  url: fetchUrl.toString()
1381
1395
  });
@@ -1384,10 +1398,7 @@ var ShapeStream = class {
1384
1398
  rawData,
1385
1399
  schema
1386
1400
  );
1387
- return {
1388
- metadata,
1389
- data
1390
- };
1401
+ return { metadata, data };
1391
1402
  }
1392
1403
  };
1393
1404
  _error = new WeakMap();
@@ -1957,6 +1968,44 @@ reset_fn = function(handle) {
1957
1968
  __privateSet(this, _staleCacheBuster, void 0);
1958
1969
  __privateSet(this, _staleCacheRetryCount, 0);
1959
1970
  };
1971
+ buildSubsetBody_fn = function(opts) {
1972
+ var _a, _b, _c, _d;
1973
+ const body = {};
1974
+ if (opts.whereExpr) {
1975
+ body.where = compileExpression(
1976
+ opts.whereExpr,
1977
+ (_a = this.options.columnMapper) == null ? void 0 : _a.encode
1978
+ );
1979
+ body.where_expr = opts.whereExpr;
1980
+ } else if (opts.where && typeof opts.where === `string`) {
1981
+ body.where = encodeWhereClause(
1982
+ opts.where,
1983
+ (_b = this.options.columnMapper) == null ? void 0 : _b.encode
1984
+ );
1985
+ }
1986
+ if (opts.params) {
1987
+ body.params = opts.params;
1988
+ }
1989
+ if (opts.limit !== void 0) {
1990
+ body.limit = opts.limit;
1991
+ }
1992
+ if (opts.offset !== void 0) {
1993
+ body.offset = opts.offset;
1994
+ }
1995
+ if (opts.orderByExpr) {
1996
+ body.order_by = compileOrderBy(
1997
+ opts.orderByExpr,
1998
+ (_c = this.options.columnMapper) == null ? void 0 : _c.encode
1999
+ );
2000
+ body.order_by_expr = opts.orderByExpr;
2001
+ } else if (opts.orderBy && typeof opts.orderBy === `string`) {
2002
+ body.order_by = encodeWhereClause(
2003
+ opts.orderBy,
2004
+ (_d = this.options.columnMapper) == null ? void 0 : _d.encode
2005
+ );
2006
+ }
2007
+ return body;
2008
+ };
1960
2009
  ShapeStream.Replica = {
1961
2010
  FULL: `full`,
1962
2011
  DEFAULT: `default`