@ferricstore/ferricstore 0.3.0 → 0.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.
Files changed (95) hide show
  1. package/README.md +54 -2
  2. package/dist/index.cjs +2273 -600
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +193 -30
  5. package/dist/index.d.ts +193 -30
  6. package/dist/index.js +2275 -605
  7. package/dist/index.js.map +1 -1
  8. package/docs/api/assets/hierarchy.js +1 -1
  9. package/docs/api/assets/navigation.js +1 -1
  10. package/docs/api/assets/search.js +1 -1
  11. package/docs/api/classes/ClaimHydrationError.html +4 -4
  12. package/docs/api/classes/ConnectionClosedError.html +5 -5
  13. package/docs/api/classes/FerricStoreClient.html +6 -2
  14. package/docs/api/classes/FerricStoreError.html +5 -5
  15. package/docs/api/classes/FlowAlreadyExistsError.html +5 -5
  16. package/docs/api/classes/FlowBatchError.html +5 -5
  17. package/docs/api/classes/FlowNotFoundError.html +5 -5
  18. package/docs/api/classes/FlowQueryError.html +42 -0
  19. package/docs/api/classes/FlowWrongStateError.html +5 -5
  20. package/docs/api/classes/InvalidCommandError.html +5 -5
  21. package/docs/api/classes/LeaseRenewalError.html +5 -5
  22. package/docs/api/classes/LockHeldError.html +5 -5
  23. package/docs/api/classes/LockNotOwnedError.html +5 -5
  24. package/docs/api/classes/NativeAdapter.html +3 -3
  25. package/docs/api/classes/OverloadedError.html +5 -5
  26. package/docs/api/classes/QueueCompletionError.html +5 -5
  27. package/docs/api/classes/RequestTimeoutError.html +5 -5
  28. package/docs/api/classes/RerouteError.html +5 -5
  29. package/docs/api/classes/StaleLeaseError.html +5 -5
  30. package/docs/api/classes/StalePolicyGenerationError.html +5 -5
  31. package/docs/api/functions/projectFlowQuery.html +1 -0
  32. package/docs/api/hierarchy.html +1 -1
  33. package/docs/api/index.html +30 -3
  34. package/docs/api/interfaces/AdminListOptions.html +1 -1
  35. package/docs/api/interfaces/CancelOptions.html +1 -1
  36. package/docs/api/interfaces/CompleteOptions.html +1 -1
  37. package/docs/api/interfaces/CompleteOutcome.html +1 -1
  38. package/docs/api/interfaces/CreateManyOptions.html +1 -1
  39. package/docs/api/interfaces/EffectCompensateOptions.html +1 -1
  40. package/docs/api/interfaces/EffectConfirmOptions.html +1 -1
  41. package/docs/api/interfaces/EffectFailOptions.html +1 -1
  42. package/docs/api/interfaces/EffectStatusOptions.html +1 -1
  43. package/docs/api/interfaces/FailOptions.html +1 -1
  44. package/docs/api/interfaces/FailOutcome.html +1 -1
  45. package/docs/api/interfaces/FerricStoreClientFromUrlOptions.html +1 -1
  46. package/docs/api/interfaces/FerricStoreClientOptions.html +1 -1
  47. package/docs/api/interfaces/FlowEventProjectionField.html +4 -0
  48. package/docs/api/interfaces/FlowExplainResult.html +10 -0
  49. package/docs/api/interfaces/FlowPolicyOptions.html +1 -1
  50. package/docs/api/interfaces/FlowQueryCountResult.html +7 -0
  51. package/docs/api/interfaces/FlowQueryErrorPosition.html +4 -0
  52. package/docs/api/interfaces/FlowQueryIndex.html +9 -0
  53. package/docs/api/interfaces/FlowQueryIndexFormat.html +7 -0
  54. package/docs/api/interfaces/FlowQueryIndexRegistry.html +3 -0
  55. package/docs/api/interfaces/FlowQueryIndexStatus.html +8 -0
  56. package/docs/api/interfaces/FlowQueryPage.html +3 -0
  57. package/docs/api/interfaces/FlowQueryQuality.html +5 -0
  58. package/docs/api/interfaces/FlowQueryRecordsResult.html +8 -0
  59. package/docs/api/interfaces/FlowQueryUsage.html +12 -0
  60. package/docs/api/interfaces/FlowRunProjectionField.html +4 -0
  61. package/docs/api/interfaces/HistoryOptions.html +2 -2
  62. package/docs/api/interfaces/InvocationCreateOptions.html +1 -1
  63. package/docs/api/interfaces/LeaseMutationOptions.html +1 -1
  64. package/docs/api/interfaces/LimitListOptions.html +1 -1
  65. package/docs/api/interfaces/MutateOptions.html +1 -1
  66. package/docs/api/interfaces/NamedValueMutation.html +1 -1
  67. package/docs/api/interfaces/ProtocolCommand.html +2 -2
  68. package/docs/api/interfaces/ReadOptions.html +5 -3
  69. package/docs/api/interfaces/ReclaimOptions.html +1 -1
  70. package/docs/api/interfaces/RequestContextOptions.html +1 -1
  71. package/docs/api/interfaces/RetryOptions.html +1 -1
  72. package/docs/api/interfaces/RetryOutcome.html +1 -1
  73. package/docs/api/interfaces/SearchOptions.html +4 -3
  74. package/docs/api/interfaces/StepContinueOptions.html +1 -1
  75. package/docs/api/interfaces/TDigestCreateOptions.html +1 -1
  76. package/docs/api/interfaces/TDigestMergeOptions.html +1 -1
  77. package/docs/api/interfaces/TransitionOptions.html +1 -1
  78. package/docs/api/interfaces/TransitionOutcome.html +1 -1
  79. package/docs/api/modules.html +1 -1
  80. package/docs/api/types/ConnectionRequestDisposition.html +1 -1
  81. package/docs/api/types/FlowProjectionField.html +1 -0
  82. package/docs/api/types/FlowProjectionShape.html +1 -0
  83. package/docs/api/types/FlowQueryInteger.html +1 -0
  84. package/docs/api/types/FlowQueryParameter.html +1 -0
  85. package/docs/api/types/FlowQueryParameters.html +1 -0
  86. package/docs/api/types/FlowQueryRecord.html +1 -0
  87. package/docs/api/types/FlowQueryResult.html +1 -0
  88. package/docs/api/types/ManagementPairs.html +1 -1
  89. package/docs/api/types/SearchStateMeta.html +1 -1
  90. package/docs/api/variables/COMMAND_OPCODES.html +1 -1
  91. package/docs/api/variables/FERRICSTORE_MINIMUM_SERVER_VERSION.html +1 -1
  92. package/docs/api/variables/FERRICSTORE_NATIVE_PROTOCOL_VERSION.html +1 -1
  93. package/docs/api/variables/FERRICSTORE_SDK_VERSION.html +1 -1
  94. package/docs/api/variables/FlowProjection.html +1 -0
  95. package/package.json +4 -3
package/dist/index.cjs CHANGED
@@ -45,6 +45,8 @@ __export(index_exports, {
45
45
  FlowAlreadyExistsError: () => FlowAlreadyExistsError,
46
46
  FlowBatchError: () => FlowBatchError,
47
47
  FlowNotFoundError: () => FlowNotFoundError,
48
+ FlowProjection: () => FlowProjection,
49
+ FlowQueryError: () => FlowQueryError,
48
50
  FlowWrongStateError: () => FlowWrongStateError,
49
51
  GeoStore: () => GeoStore,
50
52
  HashStore: () => HashStore,
@@ -87,6 +89,7 @@ __export(index_exports, {
87
89
  isOutcome: () => isOutcome,
88
90
  isReconnectableClosedConnectionError: () => isReconnectableClosedConnectionError,
89
91
  mapException: () => mapException,
92
+ projectFlowQuery: () => projectFlowQuery,
90
93
  retry: () => retry,
91
94
  transition: () => transition
92
95
  });
@@ -104,7 +107,7 @@ function assertSafeVariadicDispatch(argumentCount, arrayCapability) {
104
107
  // src/native-adapter.ts
105
108
  var import_node_net3 = require("net");
106
109
  var import_node_tls3 = require("tls");
107
- var import_node_buffer26 = require("buffer");
110
+ var import_node_buffer31 = require("buffer");
108
111
 
109
112
  // src/errors.ts
110
113
  var FerricStoreError = class extends Error {
@@ -1276,10 +1279,151 @@ var NativeHeartbeat = class {
1276
1279
  };
1277
1280
 
1278
1281
  // src/protocol.ts
1279
- var import_node_buffer22 = require("buffer");
1282
+ var import_node_buffer27 = require("buffer");
1280
1283
 
1281
- // src/command-grammar.ts
1284
+ // src/flow-query-request.ts
1282
1285
  var import_node_buffer3 = require("buffer");
1286
+ var FLOW_QUERY_LANGUAGE_VERSION = "FQL1";
1287
+ var FLOW_QUERY_MAX_BYTES = 16 * 1024;
1288
+ var FLOW_QUERY_MAX_PARAMETERS = 64;
1289
+ var FLOW_QUERY_MAX_PARAMETER_NAME_BYTES = 128;
1290
+ var MIN_I64 = -(1n << 63n);
1291
+ var MAX_I64 = (1n << 63n) - 1n;
1292
+ var INDEX_ID = /^[A-Za-z0-9_.:-]{1,64}$/u;
1293
+ function flowQueryArgs(query, params = {}) {
1294
+ validateFlowQueryText(query);
1295
+ const entries = flowQueryParameterEntries(params);
1296
+ const args = ["FLOW.QUERY", FLOW_QUERY_LANGUAGE_VERSION, query];
1297
+ for (const [name, value] of entries) args.push(name, value);
1298
+ return args;
1299
+ }
1300
+ function flowQueryPayload(args) {
1301
+ if (args.length < 2) throw new TypeError("FLOW.QUERY requires version and query");
1302
+ if ((args.length - 2) % 2 !== 0) {
1303
+ throw new TypeError("FLOW.QUERY parameters must be name/value pairs");
1304
+ }
1305
+ const version = commandText(args[0], "FLOW.QUERY version");
1306
+ if (version !== FLOW_QUERY_LANGUAGE_VERSION) {
1307
+ throw new TypeError(`FLOW.QUERY requires version ${FLOW_QUERY_LANGUAGE_VERSION}`);
1308
+ }
1309
+ const query = commandText(args[1], "FLOW.QUERY query");
1310
+ validateFlowQueryText(query);
1311
+ const parameterCount = (args.length - 2) / 2;
1312
+ if (parameterCount > FLOW_QUERY_MAX_PARAMETERS) {
1313
+ throw new TypeError(`FLOW.QUERY accepts at most ${FLOW_QUERY_MAX_PARAMETERS} named parameters`);
1314
+ }
1315
+ const params = /* @__PURE__ */ Object.create(null);
1316
+ for (let index = 2; index < args.length; index += 2) {
1317
+ const name = commandText(args[index], "FLOW.QUERY parameter name");
1318
+ validateFlowQueryParameterName(name);
1319
+ if (Object.hasOwn(params, name)) {
1320
+ throw new TypeError(`FLOW.QUERY parameter ${JSON.stringify(name)} is duplicated`);
1321
+ }
1322
+ params[name] = normalizeFlowQueryParameter(args[index + 1], name);
1323
+ }
1324
+ return {
1325
+ version,
1326
+ query,
1327
+ ...parameterCount === 0 ? {} : { params }
1328
+ };
1329
+ }
1330
+ function validateFlowQueryText(query) {
1331
+ if (typeof query !== "string") throw new TypeError("FLOW.QUERY query must be text");
1332
+ if (query.trim().length === 0) throw new TypeError("FLOW.QUERY query must not be empty");
1333
+ validateUnicodeScalarText(query, "FLOW.QUERY query");
1334
+ if (import_node_buffer3.Buffer.byteLength(query, "utf8") > FLOW_QUERY_MAX_BYTES) {
1335
+ throw new TypeError(`FLOW.QUERY query exceeds ${FLOW_QUERY_MAX_BYTES} bytes`);
1336
+ }
1337
+ }
1338
+ function validateFlowQueryIndexId(indexId) {
1339
+ if (typeof indexId !== "string" || !INDEX_ID.test(indexId)) {
1340
+ throw new TypeError(
1341
+ "query index id must be 1..64 ASCII letters, digits, '_', '-', ':', or '.'"
1342
+ );
1343
+ }
1344
+ }
1345
+ function hasFlowExplainPrefix(query) {
1346
+ const source = query.trimStart();
1347
+ const prefix = source.slice(0, 7);
1348
+ return prefix.toUpperCase() === "EXPLAIN" && (source.length === 7 || /[\t\n\r ]/u.test(source[7] ?? ""));
1349
+ }
1350
+ function flowQueryParameterEntries(params) {
1351
+ if (typeof params !== "object" || params == null || Array.isArray(params)) {
1352
+ throw new TypeError("FLOW.QUERY params must be a plain object");
1353
+ }
1354
+ const prototype = Object.getPrototypeOf(params);
1355
+ if (prototype !== null && prototype !== Object.prototype) {
1356
+ throw new TypeError("FLOW.QUERY params must be a plain object");
1357
+ }
1358
+ const keys = Reflect.ownKeys(params);
1359
+ if (keys.some((key) => typeof key !== "string")) {
1360
+ throw new TypeError("FLOW.QUERY parameter names must be strings");
1361
+ }
1362
+ if (keys.length > FLOW_QUERY_MAX_PARAMETERS) {
1363
+ throw new TypeError(`FLOW.QUERY accepts at most ${FLOW_QUERY_MAX_PARAMETERS} named parameters`);
1364
+ }
1365
+ const names = keys.sort();
1366
+ return names.map((name) => {
1367
+ validateFlowQueryParameterName(name);
1368
+ return [name, normalizeFlowQueryParameter(params[name], name)];
1369
+ });
1370
+ }
1371
+ function validateFlowQueryParameterName(name) {
1372
+ validateUnicodeScalarText(name, "FLOW.QUERY parameter name");
1373
+ const size = import_node_buffer3.Buffer.byteLength(name, "utf8");
1374
+ if (size === 0 || size > FLOW_QUERY_MAX_PARAMETER_NAME_BYTES) {
1375
+ throw new TypeError(
1376
+ `FLOW.QUERY parameter names must be 1..${FLOW_QUERY_MAX_PARAMETER_NAME_BYTES} bytes`
1377
+ );
1378
+ }
1379
+ }
1380
+ function normalizeFlowQueryParameter(value, name) {
1381
+ if (typeof value === "string") {
1382
+ validateUnicodeScalarText(value, `FLOW.QUERY parameter ${JSON.stringify(name)}`);
1383
+ return value;
1384
+ }
1385
+ if (import_node_buffer3.Buffer.isBuffer(value)) return value;
1386
+ if (value instanceof Uint8Array) return import_node_buffer3.Buffer.from(value);
1387
+ if (typeof value === "boolean") return value;
1388
+ if (typeof value === "bigint" && value >= MIN_I64 && value <= MAX_I64) return value;
1389
+ if (typeof value === "number" && Number.isFinite(value)) {
1390
+ if (!Number.isInteger(value) || Number.isSafeInteger(value)) return value;
1391
+ }
1392
+ throw new TypeError(
1393
+ `FLOW.QUERY parameter ${JSON.stringify(name)} must be text, bytes, boolean, a finite float, or a signed 64-bit integer`
1394
+ );
1395
+ }
1396
+ function commandText(value, context) {
1397
+ if (typeof value === "string") {
1398
+ validateUnicodeScalarText(value, context);
1399
+ return value;
1400
+ }
1401
+ if (import_node_buffer3.Buffer.isBuffer(value) || value instanceof Uint8Array) {
1402
+ try {
1403
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
1404
+ } catch (error) {
1405
+ throw new TypeError(`${context} must be valid UTF-8`, { cause: error });
1406
+ }
1407
+ }
1408
+ throw new TypeError(`${context} must be text`);
1409
+ }
1410
+ function validateUnicodeScalarText(value, context) {
1411
+ for (let index = 0; index < value.length; index += 1) {
1412
+ const code = value.charCodeAt(index);
1413
+ if (code >= 55296 && code <= 56319) {
1414
+ const low = value.charCodeAt(index + 1);
1415
+ if (!(low >= 56320 && low <= 57343)) {
1416
+ throw new TypeError(`${context} must be valid UTF-8`);
1417
+ }
1418
+ index += 1;
1419
+ } else if (code >= 56320 && code <= 57343) {
1420
+ throw new TypeError(`${context} must be valid UTF-8`);
1421
+ }
1422
+ }
1423
+ }
1424
+
1425
+ // src/command-grammar.ts
1426
+ var import_node_buffer4 = require("buffer");
1283
1427
 
1284
1428
  // src/command-metadata-flow.ts
1285
1429
  var flowStateIdCommands = /* @__PURE__ */ new Set([
@@ -1670,20 +1814,15 @@ var typeScopedFlowCommands = /* @__PURE__ */ new Set([
1670
1814
  "FLOW.ATTRIBUTE_VALUES",
1671
1815
  "FLOW.ATTRIBUTES",
1672
1816
  "FLOW.BUDGET.LIST",
1673
- "FLOW.FAILURES",
1674
1817
  "FLOW.GOVERNANCE.OVERVIEW",
1675
1818
  "FLOW.INFO",
1676
1819
  "FLOW.LIMIT.LIST",
1677
- "FLOW.LIST",
1678
1820
  "FLOW.POLICY.GET",
1679
1821
  "FLOW.POLICY.SET",
1680
1822
  "FLOW.RETENTION_CLEANUP",
1681
1823
  "FLOW.SCHEDULE.FIRE_DUE",
1682
1824
  "FLOW.SCHEDULE.LIST",
1683
- "FLOW.SEARCH",
1684
- "FLOW.STATS",
1685
- "FLOW.STUCK",
1686
- "FLOW.TERMINALS"
1825
+ "FLOW.STATS"
1687
1826
  ]);
1688
1827
  var flowScheduleCommands = /* @__PURE__ */ new Set([
1689
1828
  "FLOW.SCHEDULE.CREATE",
@@ -1726,8 +1865,8 @@ var secondKeySubcommands = /* @__PURE__ */ new Map([
1726
1865
  ]);
1727
1866
  function commandToken(value) {
1728
1867
  if (typeof value === "string") return value.toUpperCase();
1729
- if (import_node_buffer3.Buffer.isBuffer(value) || value instanceof Uint8Array) {
1730
- return import_node_buffer3.Buffer.from(value).toString("utf8").toUpperCase();
1868
+ if (import_node_buffer4.Buffer.isBuffer(value) || value instanceof Uint8Array) {
1869
+ return import_node_buffer4.Buffer.from(value).toString("utf8").toUpperCase();
1731
1870
  }
1732
1871
  return void 0;
1733
1872
  }
@@ -1830,7 +1969,7 @@ function safeIntegerArgument(value) {
1830
1969
  if (typeof value === "bigint") {
1831
1970
  return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
1832
1971
  }
1833
- const source = typeof value === "string" ? value : import_node_buffer3.Buffer.isBuffer(value) || value instanceof Uint8Array ? import_node_buffer3.Buffer.from(value).toString("utf8") : void 0;
1972
+ const source = typeof value === "string" ? value : import_node_buffer4.Buffer.isBuffer(value) || value instanceof Uint8Array ? import_node_buffer4.Buffer.from(value).toString("utf8") : void 0;
1834
1973
  if (source == null || !/^[+-]?\d+$/u.test(source)) return void 0;
1835
1974
  const parsed = BigInt(source);
1836
1975
  return parsed >= BigInt(Number.MIN_SAFE_INTEGER) && parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : void 0;
@@ -1883,10 +2022,10 @@ function hasOwnCommandArgument(args, index, end, section) {
1883
2022
  }
1884
2023
 
1885
2024
  // src/protocol-core.ts
1886
- var import_node_buffer7 = require("buffer");
2025
+ var import_node_buffer8 = require("buffer");
1887
2026
 
1888
2027
  // src/protocol-constants.ts
1889
- var import_node_buffer4 = require("buffer");
2028
+ var import_node_buffer5 = require("buffer");
1890
2029
 
1891
2030
  // src/native-protocol-manifest.json
1892
2031
  var native_protocol_manifest_default = {
@@ -1981,7 +2120,6 @@ var COMMAND_OPCODES = {
1981
2120
  "FLOW.VALUE.PUT": 523,
1982
2121
  "FLOW.VALUE.MGET": 524,
1983
2122
  "FLOW.SIGNAL": 525,
1984
- "FLOW.LIST": 526,
1985
2123
  "FLOW.CREATE_MANY": 527,
1986
2124
  "FLOW.COMPLETE_MANY": 528,
1987
2125
  "FLOW.TRANSITION_MANY": 529,
@@ -1990,13 +2128,7 @@ var COMMAND_OPCODES = {
1990
2128
  "FLOW.CANCEL_MANY": 532,
1991
2129
  "FLOW.RECLAIM": 533,
1992
2130
  "FLOW.REWIND": 534,
1993
- "FLOW.TERMINALS": 535,
1994
- "FLOW.FAILURES": 536,
1995
- "FLOW.BY_PARENT": 537,
1996
- "FLOW.BY_ROOT": 538,
1997
- "FLOW.BY_CORRELATION": 539,
1998
2131
  "FLOW.INFO": 540,
1999
- "FLOW.STUCK": 541,
2000
2132
  "FLOW.POLICY.SET": 542,
2001
2133
  "FLOW.POLICY.GET": 543,
2002
2134
  "FLOW.SPAWN_CHILDREN": 544,
@@ -2015,7 +2147,7 @@ var COMMAND_OPCODES = {
2015
2147
  "FLOW.STATS": 557,
2016
2148
  "FLOW.ATTRIBUTES": 558,
2017
2149
  "FLOW.ATTRIBUTE_VALUES": 559,
2018
- "FLOW.SEARCH": 560,
2150
+ "FLOW.QUERY": 561,
2019
2151
  "FLOW.EFFECT.RESERVE": 576,
2020
2152
  "FLOW.EFFECT.CONFIRM": 577,
2021
2153
  "FLOW.EFFECT.FAIL": 578,
@@ -2104,7 +2236,7 @@ var OPCODES = {
2104
2236
  flowStepContinue: COMMAND_OPCODES["FLOW.STEP_CONTINUE"],
2105
2237
  flowStartAndClaim: COMMAND_OPCODES["FLOW.START_AND_CLAIM"],
2106
2238
  flowRunStepsMany: COMMAND_OPCODES["FLOW.RUN_STEPS_MANY"],
2107
- flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
2239
+ flowQuery: COMMAND_OPCODES["FLOW.QUERY"]
2108
2240
  };
2109
2241
  var COMPACT_FLOW_CLAIM_JOBS = 128;
2110
2242
  var COMPACT_OK_LIST = 129;
@@ -2131,11 +2263,12 @@ var COMPACT_FLOW_TRANSITION_MANY_REQUEST = 155;
2131
2263
  var COMPACT_FLOW_TRANSITION_MANY_OK_REQUEST = 156;
2132
2264
  var COMPACT_FLOW_VALUE_MGET_REQUEST = 157;
2133
2265
  var COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST = 158;
2134
- var COMPACT_FLOW_LIST_REQUEST = 159;
2266
+ var COMPACT_FLOW_QUERY_RESULT = 160;
2135
2267
  var COMPACT_PIPELINE_DECODED = /* @__PURE__ */ Symbol("ferricstore.compactPipelineDecoded");
2136
2268
  var NULL_U32 = 4294967295;
2137
- var MIN_I64 = -9223372036854775808n;
2138
- var MAX_I64 = 9223372036854775807n;
2269
+ var MIN_I642 = -9223372036854775808n;
2270
+ var MAX_I642 = 9223372036854775807n;
2271
+ var MAX_U64 = 18446744073709551615n;
2139
2272
  var MAX_SAFE_INTEGER_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
2140
2273
  var MIN_SAFE_INTEGER_BIGINT = BigInt(Number.MIN_SAFE_INTEGER);
2141
2274
  var FLOW_RECORD_FIELD_KEYS = [
@@ -2184,16 +2317,16 @@ var FLOW_RECORD_FIELD_KEYS = [
2184
2317
  ];
2185
2318
 
2186
2319
  // src/protocol-text.ts
2187
- var import_node_buffer5 = require("buffer");
2320
+ var import_node_buffer6 = require("buffer");
2188
2321
  function toBuffer(value) {
2189
- if (import_node_buffer5.Buffer.isBuffer(value)) return value;
2190
- if (value instanceof Uint8Array) return import_node_buffer5.Buffer.from(value);
2191
- if (typeof value === "string") return import_node_buffer5.Buffer.from(value);
2322
+ if (import_node_buffer6.Buffer.isBuffer(value)) return value;
2323
+ if (value instanceof Uint8Array) return import_node_buffer6.Buffer.from(value);
2324
+ if (typeof value === "string") return import_node_buffer6.Buffer.from(value);
2192
2325
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2193
- return import_node_buffer5.Buffer.from(String(value));
2326
+ return import_node_buffer6.Buffer.from(String(value));
2194
2327
  }
2195
- if (typeof value === "symbol") return import_node_buffer5.Buffer.from(value.description ?? value.toString());
2196
- if (value == null) return import_node_buffer5.Buffer.alloc(0);
2328
+ if (typeof value === "symbol") return import_node_buffer6.Buffer.from(value.description ?? value.toString());
2329
+ if (value == null) return import_node_buffer6.Buffer.alloc(0);
2197
2330
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2198
2331
  }
2199
2332
  function asText(value) {
@@ -2201,14 +2334,14 @@ function asText(value) {
2201
2334
  }
2202
2335
  function optionalText(value) {
2203
2336
  if (value == null || value === "") return void 0;
2204
- if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || import_node_buffer5.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2337
+ if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || import_node_buffer6.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2205
2338
  return asText(value);
2206
2339
  }
2207
2340
  return void 0;
2208
2341
  }
2209
2342
  function commandTokenIs(value, expected) {
2210
2343
  if (typeof value === "string") return value.toUpperCase() === expected;
2211
- if (import_node_buffer5.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2344
+ if (import_node_buffer6.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2212
2345
  return asText(value).toUpperCase() === expected;
2213
2346
  }
2214
2347
  return false;
@@ -2222,7 +2355,7 @@ function commandNameIs(value, expected) {
2222
2355
  }
2223
2356
 
2224
2357
  // src/request-context.ts
2225
- var import_node_buffer6 = require("buffer");
2358
+ var import_node_buffer7 = require("buffer");
2226
2359
  var requestContextCommands = /* @__PURE__ */ new Set([
2227
2360
  "INVOCATION.CREATE",
2228
2361
  "INVOCATION.DEFINITION.GET",
@@ -2277,9 +2410,9 @@ function requestContextCommandToken(value) {
2277
2410
  const upper = value.toUpperCase();
2278
2411
  return isRequestContextCommand(upper) ? upper : void 0;
2279
2412
  }
2280
- if (import_node_buffer6.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2413
+ if (import_node_buffer7.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2281
2414
  if (value[0] !== 73 && value[0] !== 105) return void 0;
2282
- const command = import_node_buffer6.Buffer.from(value).toString("utf8").toUpperCase();
2415
+ const command = import_node_buffer7.Buffer.from(value).toString("utf8").toUpperCase();
2283
2416
  return isRequestContextCommand(command) ? command : void 0;
2284
2417
  }
2285
2418
  return void 0;
@@ -2310,12 +2443,12 @@ function requestContextText(context, fieldName) {
2310
2443
  return value;
2311
2444
  }
2312
2445
  function isPlainObject(value) {
2313
- return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer6.Buffer.isBuffer(value) && !(value instanceof Uint8Array);
2446
+ return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer7.Buffer.isBuffer(value) && !(value instanceof Uint8Array);
2314
2447
  }
2315
2448
  function commandToken2(value) {
2316
2449
  if (typeof value === "string") return value.toUpperCase();
2317
- if (import_node_buffer6.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2318
- return import_node_buffer6.Buffer.from(value).toString("utf8").toUpperCase();
2450
+ if (import_node_buffer7.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2451
+ return import_node_buffer7.Buffer.from(value).toString("utf8").toUpperCase();
2319
2452
  }
2320
2453
  return "";
2321
2454
  }
@@ -2405,17 +2538,17 @@ function requestFrameTooLarge(maxBytes) {
2405
2538
  );
2406
2539
  }
2407
2540
  function binaryValueByteLength(value) {
2408
- if (import_node_buffer7.Buffer.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2409
- if (typeof value === "string") return import_node_buffer7.Buffer.byteLength(value);
2541
+ if (import_node_buffer8.Buffer.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2542
+ if (typeof value === "string") return import_node_buffer8.Buffer.byteLength(value);
2410
2543
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2411
- return import_node_buffer7.Buffer.byteLength(String(value));
2544
+ return import_node_buffer8.Buffer.byteLength(String(value));
2412
2545
  }
2413
- if (typeof value === "symbol") return import_node_buffer7.Buffer.byteLength(value.description ?? value.toString());
2546
+ if (typeof value === "symbol") return import_node_buffer8.Buffer.byteLength(value.description ?? value.toString());
2414
2547
  if (value == null) return 0;
2415
2548
  return toBuffer(value).byteLength;
2416
2549
  }
2417
2550
  function writeCustomPayload(output, offset, value, knownByteLength) {
2418
- if (import_node_buffer7.Buffer.isBuffer(value)) {
2551
+ if (import_node_buffer8.Buffer.isBuffer(value)) {
2419
2552
  value.copy(output, offset);
2420
2553
  return;
2421
2554
  }
@@ -2434,7 +2567,7 @@ function writeCustomPayload(output, offset, value, knownByteLength) {
2434
2567
  } else {
2435
2568
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2436
2569
  }
2437
- output.write(text3, offset, knownByteLength ?? import_node_buffer7.Buffer.byteLength(text3), "utf8");
2570
+ output.write(text3, offset, knownByteLength ?? import_node_buffer8.Buffer.byteLength(text3), "utf8");
2438
2571
  }
2439
2572
  function compactBinaryEncodedLength(value) {
2440
2573
  return 4 + compactBinaryByteLength(value);
@@ -2447,10 +2580,10 @@ function compactBinaryByteLength(value) {
2447
2580
  return byteLength;
2448
2581
  }
2449
2582
  function isCompactBinaryArgument(value) {
2450
- return typeof value === "string" || import_node_buffer7.Buffer.isBuffer(value) || value instanceof Uint8Array;
2583
+ return typeof value === "string" || import_node_buffer8.Buffer.isBuffer(value) || value instanceof Uint8Array;
2451
2584
  }
2452
2585
  function isCompactBinaryScalar(value) {
2453
- return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" || import_node_buffer7.Buffer.isBuffer(value) || value instanceof Uint8Array;
2586
+ return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" || import_node_buffer8.Buffer.isBuffer(value) || value instanceof Uint8Array;
2454
2587
  }
2455
2588
  function compactOptionalBinaryEncodedLength(value) {
2456
2589
  return value == null ? 4 : compactBinaryEncodedLength(value);
@@ -2516,7 +2649,7 @@ function integerArg(value) {
2516
2649
  throw new FerricStoreError("integer command argument must be an integer");
2517
2650
  }
2518
2651
  const integer2 = BigInt(source);
2519
- if (integer2 < MIN_I64 || integer2 > MAX_I64) {
2652
+ if (integer2 < MIN_I642 || integer2 > MAX_I642) {
2520
2653
  throw new FerricStoreError("integer command argument exceeds the signed 64-bit range");
2521
2654
  }
2522
2655
  return integer2 >= MIN_SAFE_INTEGER_BIGINT && integer2 <= MAX_SAFE_INTEGER_BIGINT ? Number(integer2) : integer2;
@@ -2547,7 +2680,7 @@ function independentMode(value) {
2547
2680
  return 0;
2548
2681
  }
2549
2682
  function optionalI64(value) {
2550
- return typeof value === "number" ? BigInt(value) : MIN_I64;
2683
+ return typeof value === "number" ? BigInt(value) : MIN_I642;
2551
2684
  }
2552
2685
  function compactClaimReturnMode(value) {
2553
2686
  const mode = value == null ? "" : asText(value).toUpperCase();
@@ -2581,18 +2714,18 @@ function setOwnValue2(target, key, value) {
2581
2714
  }
2582
2715
 
2583
2716
  // src/protocol-flow-options.ts
2584
- var import_node_buffer8 = require("buffer");
2717
+ var import_node_buffer9 = require("buffer");
2585
2718
 
2586
2719
  // src/protocol-flow-option-value.ts
2587
- function setFlowOptionValue(payload, field2, value, repeat) {
2588
- if (!repeat || !Object.hasOwn(payload, field2)) {
2589
- setOwnValue2(payload, field2, value);
2720
+ function setFlowOptionValue(payload, field3, value, repeat) {
2721
+ if (!repeat || !Object.hasOwn(payload, field3)) {
2722
+ setOwnValue2(payload, field3, value);
2590
2723
  return;
2591
2724
  }
2592
- const previous = payload[field2];
2725
+ const previous = payload[field3];
2593
2726
  setOwnValue2(
2594
2727
  payload,
2595
- field2,
2728
+ field3,
2596
2729
  Array.isArray(previous) ? [...previous, value] : [previous, value]
2597
2730
  );
2598
2731
  }
@@ -2635,44 +2768,30 @@ function optionMap(args) {
2635
2768
  index += 3;
2636
2769
  continue;
2637
2770
  }
2638
- const field2 = OPTION_FIELDS[token] ?? token.toLowerCase();
2771
+ const field3 = OPTION_FIELDS[token] ?? token.toLowerCase();
2639
2772
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow options")) {
2640
2773
  throw new FerricStoreError(`${token} requires a value`);
2641
2774
  }
2642
2775
  const value = args[index + 1];
2643
- if (BOOL_OPTION_FIELDS.has(field2) && !isBoolToken(value)) {
2776
+ if (BOOL_OPTION_FIELDS.has(field3) && !isBoolToken(value)) {
2644
2777
  return void 0;
2645
2778
  }
2646
- setOwnValue2(payload, field2, BOOL_OPTION_FIELDS.has(field2) ? boolArg(value) : value);
2779
+ setOwnValue2(payload, field3, BOOL_OPTION_FIELDS.has(field3) ? boolArg(value) : value);
2647
2780
  index += 2;
2648
2781
  }
2649
2782
  return payload;
2650
2783
  }
2651
- function ensureObjectField(payload, field2) {
2652
- const value = payload[field2];
2784
+ function ensureObjectField(payload, field3) {
2785
+ const value = payload[field3];
2653
2786
  if (isPlainObject2(value)) {
2654
2787
  return value;
2655
2788
  }
2656
2789
  const next = {};
2657
- setOwnValue2(payload, field2, next);
2790
+ setOwnValue2(payload, field3, next);
2658
2791
  return next;
2659
2792
  }
2660
- function normalizeFlowSearchStateMeta(payload) {
2661
- const stateMeta = payload.state_meta;
2662
- if (!isPlainObject2(stateMeta) || Object.keys(stateMeta).length === 0) {
2663
- return;
2664
- }
2665
- if (Object.values(stateMeta).every(isPlainObject2)) {
2666
- return;
2667
- }
2668
- const state = payload.state;
2669
- if (state == null) {
2670
- throw new FerricStoreError("FLOW.SEARCH STATE_META filters require STATE or nested state metadata");
2671
- }
2672
- payload.state_meta = { [asText(state)]: stateMeta };
2673
- }
2674
2793
  function isPlainObject2(value) {
2675
- return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer8.Buffer.isBuffer(value) && !(value instanceof Uint8Array);
2794
+ return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer9.Buffer.isBuffer(value) && !(value instanceof Uint8Array);
2676
2795
  }
2677
2796
  function parseFlowOptions(args, start, end, config) {
2678
2797
  const payload = {};
@@ -2766,9 +2885,9 @@ function parseFlowOptions(args, start, end, config) {
2766
2885
  case "TRANSITION_TO":
2767
2886
  case "TO_EVENT":
2768
2887
  case "EXPECT_STATE": {
2769
- const field2 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2888
+ const field3 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2770
2889
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2771
- setFlowOptionValue(payload, field2, args[index + 1], token === "IF_STATE");
2890
+ setFlowOptionValue(payload, field3, args[index + 1], token === "IF_STATE");
2772
2891
  index += 2;
2773
2892
  break;
2774
2893
  }
@@ -2776,8 +2895,8 @@ function parseFlowOptions(args, start, end, config) {
2776
2895
  case "RESULT":
2777
2896
  case "ERROR":
2778
2897
  case "REASON": {
2779
- const field2 = token === "LEASE_TOKEN" ? "lease_token" : token.toLowerCase();
2780
- if (!putScalar(payload, field2, args, index + 1, end)) return void 0;
2898
+ const field3 = token === "LEASE_TOKEN" ? "lease_token" : token.toLowerCase();
2899
+ if (!putScalar(payload, field3, args, index + 1, end)) return void 0;
2781
2900
  index += 2;
2782
2901
  break;
2783
2902
  }
@@ -2799,8 +2918,8 @@ function parseFlowOptions(args, start, end, config) {
2799
2918
  case "VALUE_REF":
2800
2919
  case "STATE_META": {
2801
2920
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options") || !hasOwnCommandArgument(args, index + 2, end, "Flow options")) return void 0;
2802
- const field2 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "VALUE_REF" ? "value_refs" : "state_meta";
2803
- const values = ensureObjectField(payload, field2);
2921
+ const field3 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "VALUE_REF" ? "value_refs" : "state_meta";
2922
+ const values = ensureObjectField(payload, field3);
2804
2923
  setOwnValue2(values, asText(args[index + 1]), args[index + 2]);
2805
2924
  index += 3;
2806
2925
  break;
@@ -2809,8 +2928,8 @@ function parseFlowOptions(args, start, end, config) {
2809
2928
  case "OVERRIDE_VALUE":
2810
2929
  case "ATTRIBUTE_DELETE": {
2811
2930
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2812
- const field2 = token === "DROP_VALUE" ? "drop_values" : token === "OVERRIDE_VALUE" ? "override_values" : "attributes_delete";
2813
- const values = ensureArrayField(payload, field2);
2931
+ const field3 = token === "DROP_VALUE" ? "drop_values" : token === "OVERRIDE_VALUE" ? "override_values" : "attributes_delete";
2932
+ const values = ensureArrayField(payload, field3);
2814
2933
  values.push(args[index + 1]);
2815
2934
  index += 2;
2816
2935
  break;
@@ -2927,13 +3046,13 @@ function putScalar(payload, key, args, index, end) {
2927
3046
  setOwnValue2(payload, key, args[index]);
2928
3047
  return true;
2929
3048
  }
2930
- function ensureArrayField(payload, field2) {
2931
- const value = payload[field2];
3049
+ function ensureArrayField(payload, field3) {
3050
+ const value = payload[field3];
2932
3051
  if (Array.isArray(value)) {
2933
3052
  return value;
2934
3053
  }
2935
3054
  const next = [];
2936
- setOwnValue2(payload, field2, next);
3055
+ setOwnValue2(payload, field3, next);
2937
3056
  return next;
2938
3057
  }
2939
3058
  function putNumber(payload, key, args, index, end) {
@@ -3154,8 +3273,8 @@ function flowHistoryPayload(args) {
3154
3273
  case "CONSISTENT_PROJECTION":
3155
3274
  case "VALUES": {
3156
3275
  if (!isBoolToken(value)) return void 0;
3157
- const field2 = token === "REV" ? "rev" : token === "INCLUDE_COLD" ? "include_cold" : token === "CONSISTENT_PROJECTION" ? "consistent_projection" : "values";
3158
- payload[field2] = boolArg(value);
3276
+ const field3 = token === "REV" ? "rev" : token === "INCLUDE_COLD" ? "include_cold" : token === "CONSISTENT_PROJECTION" ? "consistent_projection" : "values";
3277
+ payload[field3] = boolArg(value);
3159
3278
  break;
3160
3279
  }
3161
3280
  default:
@@ -3167,9 +3286,9 @@ function flowHistoryPayload(args) {
3167
3286
  function flowAdminPayload(opcode, args, leadingFields = []) {
3168
3287
  if (args.length < leadingFields.length) return void 0;
3169
3288
  const payload = {};
3170
- for (const [index, field2] of leadingFields.entries()) {
3289
+ for (const [index, field3] of leadingFields.entries()) {
3171
3290
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
3172
- setOwnValue2(payload, field2, args[index]);
3291
+ setOwnValue2(payload, field3, args[index]);
3173
3292
  }
3174
3293
  for (let index = leadingFields.length; index < args.length; ) {
3175
3294
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
@@ -3177,15 +3296,15 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3177
3296
  if (token == null) return void 0;
3178
3297
  if (["ATTRIBUTE", "ATTRIBUTE_MERGE", "STATE_META", "VALUE", "VALUE_REF"].includes(token)) {
3179
3298
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments") || !hasOwnCommandArgument(args, index + 2, args.length, "Flow admin arguments")) return void 0;
3180
- const field3 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "STATE_META" ? "state_meta" : token === "VALUE" ? "values" : "value_refs";
3181
- setOwnValue2(ensureObjectField(payload, field3), asText(args[index + 1]), args[index + 2]);
3299
+ const field4 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "STATE_META" ? "state_meta" : token === "VALUE" ? "values" : "value_refs";
3300
+ setOwnValue2(ensureObjectField(payload, field4), asText(args[index + 1]), args[index + 2]);
3182
3301
  index += 3;
3183
3302
  continue;
3184
3303
  }
3185
3304
  if (token === "ATTRIBUTE_DELETE" || token === "DROP_VALUE" || token === "OVERRIDE_VALUE") {
3186
3305
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) return void 0;
3187
- const field3 = token === "ATTRIBUTE_DELETE" ? "attributes_delete" : token === "DROP_VALUE" ? "drop_values" : "override_values";
3188
- ensureArrayField(payload, field3).push(args[index + 1]);
3306
+ const field4 = token === "ATTRIBUTE_DELETE" ? "attributes_delete" : token === "DROP_VALUE" ? "drop_values" : "override_values";
3307
+ ensureArrayField(payload, field4).push(args[index + 1]);
3189
3308
  index += 2;
3190
3309
  continue;
3191
3310
  }
@@ -3204,13 +3323,13 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3204
3323
  index += 2 + count;
3205
3324
  continue;
3206
3325
  }
3207
- const field2 = FLOW_ADMIN_FIELDS[token];
3208
- if (field2 == null || !hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) {
3326
+ const field3 = FLOW_ADMIN_FIELDS[token];
3327
+ if (field3 == null || !hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) {
3209
3328
  return void 0;
3210
3329
  }
3211
3330
  const rawValue = args[index + 1];
3212
- if (FLOW_ADMIN_BOOLEAN_FIELDS.has(field2) && !isBoolToken(rawValue)) return void 0;
3213
- setOwnValue2(payload, field2, FLOW_ADMIN_BOOLEAN_FIELDS.has(field2) ? boolArg(rawValue) : rawValue);
3331
+ if (FLOW_ADMIN_BOOLEAN_FIELDS.has(field3) && !isBoolToken(rawValue)) return void 0;
3332
+ setOwnValue2(payload, field3, FLOW_ADMIN_BOOLEAN_FIELDS.has(field3) ? boolArg(rawValue) : rawValue);
3214
3333
  index += 2;
3215
3334
  }
3216
3335
  const serverBlockMs = opcode === COMMAND_OPCODES["FLOW.SCHEDULE.FIRE_DUE"] && payload.block_ms != null ? blockDurationMs(payload.block_ms, 1) : void 0;
@@ -3218,7 +3337,7 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3218
3337
  }
3219
3338
 
3220
3339
  // src/protocol-flow-compact.ts
3221
- var import_node_buffer10 = require("buffer");
3340
+ var import_node_buffer11 = require("buffer");
3222
3341
 
3223
3342
  // src/protocol-flow-compact-common.ts
3224
3343
  function compactManyRequestTag(value, regularTag, okOnSuccessTag) {
@@ -3327,7 +3446,7 @@ function parseNamedCountMap(values, start) {
3327
3446
  }
3328
3447
 
3329
3448
  // src/protocol-flow-compact-transition.ts
3330
- var import_node_buffer9 = require("buffer");
3449
+ var import_node_buffer10 = require("buffer");
3331
3450
  function compactFlowTransitionManyPayload(partition, fromState, toState, rawItems, mixed, options, maxBodyBytes) {
3332
3451
  if ("payload" in options || "priority" in options || "state_meta" in options || "values" in options || "value_refs" in options || "drop_values" in options || "override_values" in options || "attributes_merge" in options || "attributes_delete" in options || typeof options.now_ms !== "number" || !Number.isSafeInteger(options.now_ms) || options.now_ms < 0) {
3333
3452
  return void 0;
@@ -3379,7 +3498,7 @@ function compactFlowTransitionManyPayload(partition, fromState, toState, rawItem
3379
3498
  total += 4 + idLength + 4 + itemPartitionLength + 8 + 4 + leaseLength;
3380
3499
  }
3381
3500
  assertCompactPayloadFits(total, maxBodyBytes);
3382
- const out = import_node_buffer9.Buffer.allocUnsafe(total);
3501
+ const out = import_node_buffer10.Buffer.allocUnsafe(total);
3383
3502
  let offset = 0;
3384
3503
  out.writeUInt8(tag, offset);
3385
3504
  offset += 1;
@@ -3437,7 +3556,7 @@ function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options,
3437
3556
  }
3438
3557
  assertCompactPayloadFits(total, maxBodyBytes);
3439
3558
  const tag = mixed ? COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST : auto ? COMPACT_FLOW_CREATE_MANY_REQUEST : COMPACT_FLOW_CREATE_MANY_PARTITION_REQUEST;
3440
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3559
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3441
3560
  let offset = 0;
3442
3561
  out.writeUInt8(tag, offset++);
3443
3562
  offset = writeBinary(out, offset, toBuffer(options.type));
@@ -3482,7 +3601,7 @@ function compactFlowClaimDuePayload(type, options, maxBodyBytes) {
3482
3601
  total += 1;
3483
3602
  }
3484
3603
  assertCompactPayloadFits(total, maxBodyBytes);
3485
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3604
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3486
3605
  let offset = 0;
3487
3606
  out.writeUInt8(COMPACT_FLOW_CLAIM_DUE_REQUEST, offset++);
3488
3607
  offset = writeBinary(out, offset, toBuffer(type));
@@ -3536,7 +3655,7 @@ function compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto
3536
3655
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3537
3656
  }
3538
3657
  assertCompactPayloadFits(total, maxBodyBytes);
3539
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3658
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3540
3659
  let offset = 0;
3541
3660
  out.writeUInt8(
3542
3661
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_COMPLETE_MANY_OK_REQUEST : COMPACT_FLOW_COMPLETE_MANY_REQUEST,
@@ -3583,7 +3702,7 @@ function compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options,
3583
3702
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3584
3703
  }
3585
3704
  assertCompactPayloadFits(total, maxBodyBytes);
3586
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3705
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3587
3706
  let offset = 0;
3588
3707
  out.writeUInt8(
3589
3708
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_RETRY_MANY_OK_REQUEST : COMPACT_FLOW_RETRY_MANY_REQUEST,
@@ -3671,7 +3790,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3671
3790
  total += 4 + idLength + 4 + itemPartitionLength + 8;
3672
3791
  }
3673
3792
  assertCompactPayloadFits(total, maxBodyBytes);
3674
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3793
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3675
3794
  let offset = 0;
3676
3795
  out.writeUInt8(tag, offset);
3677
3796
  offset += 1;
@@ -3694,6 +3813,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3694
3813
  offset += 8;
3695
3814
  }
3696
3815
  return {
3816
+ compactResponseItems: count,
3697
3817
  flags: FLAG_CUSTOM_PAYLOAD,
3698
3818
  opcode: COMMAND_OPCODES["FLOW.CANCEL_MANY"],
3699
3819
  payload: out
@@ -3707,7 +3827,7 @@ function isOptionalSafeIntegerNumber(value) {
3707
3827
  }
3708
3828
 
3709
3829
  // src/protocol-flow-compact-single.ts
3710
- var import_node_buffer11 = require("buffer");
3830
+ var import_node_buffer12 = require("buffer");
3711
3831
  function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3712
3832
  if (refs.length > 4294967295 || maxBytes != null && (typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 0)) return void 0;
3713
3833
  const minimum = 13 + refs.length * 4;
@@ -3724,7 +3844,7 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3724
3844
  total += 4 + byteLength;
3725
3845
  }
3726
3846
  assertCompactPayloadFits(total, maxBodyBytes);
3727
- const out = import_node_buffer11.Buffer.allocUnsafe(total);
3847
+ const out = import_node_buffer12.Buffer.allocUnsafe(total);
3728
3848
  let offset = 0;
3729
3849
  out.writeUInt8(COMPACT_FLOW_VALUE_MGET_REQUEST, offset);
3730
3850
  offset += 1;
@@ -3737,47 +3857,6 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3737
3857
  }
3738
3858
  return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.flowValueMGet, payload: out };
3739
3859
  }
3740
- function compactFlowListPayload(args, maxBodyBytes) {
3741
- const type = args[0];
3742
- if (!isCompactBinaryArgument(type)) return void 0;
3743
- let state;
3744
- let count = 100;
3745
- let returnMode = 0;
3746
- const seen = /* @__PURE__ */ new Set();
3747
- for (let index = 1; index < args.length; index += 2) {
3748
- if (index + 1 >= args.length) return void 0;
3749
- const token = asText(args[index]).toUpperCase();
3750
- if (seen.has(token)) return void 0;
3751
- seen.add(token);
3752
- if (token === "STATE") {
3753
- if (!isCompactBinaryArgument(args[index + 1])) return void 0;
3754
- state = args[index + 1];
3755
- } else if (token === "COUNT") {
3756
- const value = safeIntegerNumberArg(args[index + 1]);
3757
- if (value <= 0) return void 0;
3758
- count = value;
3759
- } else if (token === "RETURN") {
3760
- if (!commandTokenIs(args[index + 1], "META")) return void 0;
3761
- returnMode = 1;
3762
- } else {
3763
- return void 0;
3764
- }
3765
- }
3766
- const typeLength = compactBinaryByteLength(type);
3767
- const stateLength = state == null ? 0 : compactBinaryByteLength(state);
3768
- const total = 1 + 4 + typeLength + 4 + stateLength + 8 + 1;
3769
- assertCompactPayloadFits(total, maxBodyBytes);
3770
- const out = import_node_buffer11.Buffer.allocUnsafe(total);
3771
- let offset = 0;
3772
- out.writeUInt8(COMPACT_FLOW_LIST_REQUEST, offset);
3773
- offset += 1;
3774
- offset = writeBinaryValue(out, offset, type, typeLength);
3775
- offset = writeOptionalBinaryValue(out, offset, state, stateLength);
3776
- out.writeBigInt64BE(BigInt(count), offset);
3777
- offset += 8;
3778
- out.writeUInt8(returnMode, offset);
3779
- return { flags: FLAG_CUSTOM_PAYLOAD, opcode: COMMAND_OPCODES["FLOW.LIST"], payload: out };
3780
- }
3781
3860
 
3782
3861
  // src/protocol-flow-routing.ts
3783
3862
  function withFlowPartitionRouting(command, payload) {
@@ -3826,15 +3905,6 @@ function expandFlowClaimStates(args) {
3826
3905
  }
3827
3906
 
3828
3907
  // src/protocol-flow.ts
3829
- function hasFlowCommandOnlyOption(command, args) {
3830
- if (command !== "FLOW.SEARCH") return false;
3831
- for (let index = 1; index < args.length; ) {
3832
- const token = asText(args[index]).toUpperCase();
3833
- if (token === "INDEXED_STATE_META") return true;
3834
- index += token === "ATTRIBUTE" || token === "STATE_META" ? 3 : 2;
3835
- }
3836
- return false;
3837
- }
3838
3908
  function flowCreatePayload(args) {
3839
3909
  if (args.length < 7) return void 0;
3840
3910
  const id = args[0];
@@ -3891,9 +3961,9 @@ function flowValueMGetPayload(args, maxBodyBytes, allowCompact) {
3891
3961
  }
3892
3962
  if (allowCompact) {
3893
3963
  const compact = compactFlowValueMGetPayload(refs, payload.max_bytes, maxBodyBytes);
3894
- if (compact != null) return compact;
3964
+ if (compact != null) return { ...compact, compactResponseItems: refs.length };
3895
3965
  }
3896
- return { opcode: OPCODES.flowValueMGet, payload };
3966
+ return { compactResponseItems: refs.length, opcode: OPCODES.flowValueMGet, payload };
3897
3967
  }
3898
3968
  function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3899
3969
  if (args.length < 2) return void 0;
@@ -3929,7 +3999,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3929
3999
  if (items2 == null) return void 0;
3930
4000
  const payload2 = { ...options, items: items2 };
3931
4001
  if (!auto && !mixed) payload2.partition_key = partition;
3932
- return { opcode: OPCODES.flowCreateMany, payload: payload2 };
4002
+ return { compactResponseItems: items2.length, opcode: OPCODES.flowCreateMany, payload: payload2 };
3933
4003
  }
3934
4004
  const rawItems = denseCommandArgumentTail(args, itemsIndex + 1, "ITEMS");
3935
4005
  const width = mixed ? 3 : 2;
@@ -3943,7 +4013,9 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3943
4013
  options,
3944
4014
  maxBodyBytes
3945
4015
  );
3946
- if (compact != null) return compact;
4016
+ if (compact != null) {
4017
+ return { ...compact, compactResponseItems: rawItems.length / width };
4018
+ }
3947
4019
  }
3948
4020
  const items = [];
3949
4021
  for (let index = 0; index < rawItems.length; index += width) {
@@ -3955,7 +4027,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3955
4027
  }
3956
4028
  const payload = { ...options, items };
3957
4029
  if (!auto && !mixed) payload.partition_key = partition;
3958
- return { opcode: OPCODES.flowCreateMany, payload };
4030
+ return { compactResponseItems: items.length, opcode: OPCODES.flowCreateMany, payload };
3959
4031
  }
3960
4032
  function flowClaimDuePayload(args, maxBodyBytes, allowCompact) {
3961
4033
  if (args.length < 1) return void 0;
@@ -4118,7 +4190,9 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4118
4190
  if (rawItems.length === 0 || rawItems.length % width !== 0) return void 0;
4119
4191
  if (allowCompact) {
4120
4192
  const compact = command === "FLOW.RETRY_MANY" ? compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options, maxBodyBytes) : compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto, options, maxBodyBytes);
4121
- if (compact != null) return compact;
4193
+ if (compact != null) {
4194
+ return { ...compact, compactResponseItems: rawItems.length / width };
4195
+ }
4122
4196
  }
4123
4197
  const items = [];
4124
4198
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4130,7 +4204,7 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4130
4204
  }
4131
4205
  const payload = { ...options, items };
4132
4206
  if (!auto && !mixed) payload.partition_key = partition;
4133
- return { opcode, payload };
4207
+ return { compactResponseItems: items.length, opcode, payload };
4134
4208
  }
4135
4209
  function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4136
4210
  if (args.length < 4) return void 0;
@@ -4170,7 +4244,9 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4170
4244
  options,
4171
4245
  maxBodyBytes
4172
4246
  ) : void 0;
4173
- if (compact != null) return compact;
4247
+ if (compact != null) {
4248
+ return { ...compact, compactResponseItems: rawItems.length / width };
4249
+ }
4174
4250
  }
4175
4251
  const items = [];
4176
4252
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4190,7 +4266,11 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4190
4266
  items
4191
4267
  };
4192
4268
  if (!mixed) payload.partition_key = args[0];
4193
- return { opcode: OPCODES.flowTransitionMany, payload };
4269
+ return {
4270
+ compactResponseItems: items.length,
4271
+ opcode: OPCODES.flowTransitionMany,
4272
+ payload
4273
+ };
4194
4274
  }
4195
4275
  function flowSpawnChildrenPayload(args) {
4196
4276
  if (args.length < 2) return void 0;
@@ -4233,13 +4313,6 @@ function flowSpawnChildrenPayload(args) {
4233
4313
  payload: { id: args[0], ...options, children }
4234
4314
  };
4235
4315
  }
4236
- function flowSearchPayload(args) {
4237
- if (args.length < 1) return void 0;
4238
- const payload = optionMap(args.slice(1));
4239
- if (payload == null) return void 0;
4240
- normalizeFlowSearchStateMeta(payload);
4241
- return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
4242
- }
4243
4316
 
4244
4317
  // src/protocol-flow-signal.ts
4245
4318
  function flowSignalPayload(args) {
@@ -4265,7 +4338,7 @@ function flowSignalPayload(args) {
4265
4338
  }
4266
4339
 
4267
4340
  // src/protocol-flow-policy.ts
4268
- var import_node_buffer12 = require("buffer");
4341
+ var import_node_buffer13 = require("buffer");
4269
4342
  var BACKOFF_FIELDS = {
4270
4343
  BASE_MS: "base_ms",
4271
4344
  MAX_MS: "max_ms",
@@ -4395,7 +4468,7 @@ function maxActiveOption(value) {
4395
4468
  return integerOption(value);
4396
4469
  }
4397
4470
  function isBinaryArgument(value) {
4398
- return typeof value === "string" || import_node_buffer12.Buffer.isBuffer(value) || value instanceof Uint8Array;
4471
+ return typeof value === "string" || import_node_buffer13.Buffer.isBuffer(value) || value instanceof Uint8Array;
4399
4472
  }
4400
4473
  function objectField(target, name) {
4401
4474
  const existing = Object.hasOwn(target, name) ? target[name] : void 0;
@@ -4467,7 +4540,7 @@ function commandRequiresOrderedPipelineExecution(args) {
4467
4540
  }
4468
4541
 
4469
4542
  // src/protocol-compact-request.ts
4470
- var import_node_buffer13 = require("buffer");
4543
+ var import_node_buffer14 = require("buffer");
4471
4544
  function compactMsetPayload(args, maxBodyBytes) {
4472
4545
  if (args.length % 2 !== 0) throw new FerricStoreError("MSET requires key/value pairs");
4473
4546
  const minimum = 6 + args.length * 4;
@@ -4486,7 +4559,7 @@ function compactMsetPayload(args, maxBodyBytes) {
4486
4559
  total += 4 + byteLength;
4487
4560
  }
4488
4561
  assertCompactPayloadFits(total, maxBodyBytes);
4489
- const out = import_node_buffer13.Buffer.allocUnsafe(total);
4562
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4490
4563
  let offset = writeCompactPipelineHeader(out, 1, args.length / 2);
4491
4564
  for (let index = 0; index < args.length; index += 1) {
4492
4565
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4510,7 +4583,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4510
4583
  total += 4 + byteLength;
4511
4584
  }
4512
4585
  assertCompactPayloadFits(total, maxBodyBytes);
4513
- const out = import_node_buffer13.Buffer.allocUnsafe(total);
4586
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4514
4587
  let offset = writeCompactPipelineHeader(out, mode, args.length);
4515
4588
  for (let index = 0; index < args.length; index += 1) {
4516
4589
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4520,7 +4593,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4520
4593
  function compactPipelinePayload(commands, maxBodyBytes) {
4521
4594
  if (commands.length === 0) {
4522
4595
  assertCompactPayloadFits(6, maxBodyBytes);
4523
- const out = import_node_buffer13.Buffer.allocUnsafe(6);
4596
+ const out = import_node_buffer14.Buffer.allocUnsafe(6);
4524
4597
  writeCompactPipelineHeader(out, 128 | 2, 0);
4525
4598
  return out;
4526
4599
  }
@@ -4562,7 +4635,7 @@ function compactSetPipelinePayload(commands, maxBodyBytes) {
4562
4635
  total += 8 + keyByteLength + valueByteLength;
4563
4636
  }
4564
4637
  assertCompactPayloadFits(total, maxBodyBytes);
4565
- const out = import_node_buffer13.Buffer.allocUnsafe(total);
4638
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4566
4639
  let offset = writeCompactPipelineHeader(out, 128 | 1, commands.length);
4567
4640
  for (let index = 0; index < commands.length; index += 1) {
4568
4641
  offset = writeBinaryValue(out, offset, argumentValues[index * 2], argumentByteLengths[index * 2] ?? 0);
@@ -4597,7 +4670,7 @@ function compactGetPipelinePayload(commands, maxBodyBytes) {
4597
4670
  total += 4 + keyByteLength;
4598
4671
  }
4599
4672
  assertCompactPayloadFits(total, maxBodyBytes);
4600
- const out = import_node_buffer13.Buffer.allocUnsafe(total);
4673
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4601
4674
  let offset = writeCompactPipelineHeader(out, 128 | 2, commands.length);
4602
4675
  for (let index = 0; index < commands.length; index += 1) {
4603
4676
  offset = writeBinaryValue(out, offset, keys[index], keyByteLengths[index] ?? 0);
@@ -4638,7 +4711,7 @@ function writeCompactPipelineHeader(out, mode, count) {
4638
4711
  }
4639
4712
 
4640
4713
  // src/protocol-kv.ts
4641
- var import_node_buffer14 = require("buffer");
4714
+ var import_node_buffer15 = require("buffer");
4642
4715
  function collectionProtocolCommand(command, args) {
4643
4716
  switch (command) {
4644
4717
  case "CAS":
@@ -4709,8 +4782,8 @@ function stringSetPayload(args) {
4709
4782
  if (value == null || token === "EX" && value > Math.floor(Number.MAX_SAFE_INTEGER / 1e3)) {
4710
4783
  return void 0;
4711
4784
  }
4712
- const field2 = token === "EX" || token === "PX" ? "ttl" : token.toLowerCase();
4713
- setOwnValue2(payload, field2, token === "EX" ? value * 1e3 : value);
4785
+ const field3 = token === "EX" || token === "PX" ? "ttl" : token.toLowerCase();
4786
+ setOwnValue2(payload, field3, token === "EX" ? value * 1e3 : value);
4714
4787
  expirySeen = true;
4715
4788
  index += 2;
4716
4789
  } else if (token === "NX") {
@@ -4809,25 +4882,25 @@ function hashSetCommand(args) {
4809
4882
  if (!isBinaryCommandArgument(args[0]) || args.length < 3 || args.length % 2 !== 1) return void 0;
4810
4883
  const fields = /* @__PURE__ */ Object.create(null);
4811
4884
  for (let index = 1; index < args.length; index += 2) {
4812
- const field2 = args[index];
4885
+ const field3 = args[index];
4813
4886
  const value = args[index + 1];
4814
- if (typeof field2 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4815
- setOwnValue2(fields, field2, value);
4887
+ if (typeof field3 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4888
+ setOwnValue2(fields, field3, value);
4816
4889
  }
4817
4890
  return { opcode: COMMAND_OPCODES.HSET, payload: { fields, key: args[0] } };
4818
4891
  }
4819
4892
  function keyOnlyCommand(opcode, args) {
4820
4893
  return args.length === 1 && isBinaryCommandArgument(args[0]) ? { opcode, payload: { key: args[0] } } : void 0;
4821
4894
  }
4822
- function binaryFieldsCommand(opcode, args, field2, length) {
4895
+ function binaryFieldsCommand(opcode, args, field3, length) {
4823
4896
  if (args.length !== length || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1])) return void 0;
4824
- return { opcode, payload: { [field2]: args[1], key: args[0] } };
4897
+ return { opcode, payload: { [field3]: args[1], key: args[0] } };
4825
4898
  }
4826
- function binaryListCommand(opcode, args, field2) {
4899
+ function binaryListCommand(opcode, args, field3) {
4827
4900
  if (!isBinaryCommandArgument(args[0]) || args.length < 2) return void 0;
4828
4901
  const values = args.slice(1);
4829
4902
  if (!values.every(isBinaryCommandArgument)) return void 0;
4830
- return { opcode, payload: { [field2]: values, key: args[0] } };
4903
+ return { opcode, payload: { [field3]: values, key: args[0] } };
4831
4904
  }
4832
4905
  function listPopCommand(opcode, args) {
4833
4906
  if (!isBinaryCommandArgument(args[0]) || args.length !== 1 && args.length !== 2) return void 0;
@@ -4885,17 +4958,35 @@ function parsedNumber(value) {
4885
4958
  }
4886
4959
  }
4887
4960
  function isBinaryCommandArgument(value) {
4888
- return typeof value === "string" || import_node_buffer14.Buffer.isBuffer(value);
4961
+ return typeof value === "string" || import_node_buffer15.Buffer.isBuffer(value);
4889
4962
  }
4890
4963
  function isDirectKvValueArgument(value) {
4891
4964
  return isBinaryCommandArgument(value) || typeof value === "object" && value != null;
4892
4965
  }
4893
4966
  function binaryToken(value) {
4894
- return typeof value === "string" ? value.toUpperCase() : import_node_buffer14.Buffer.isBuffer(value) ? value.toString("utf8").toUpperCase() : void 0;
4967
+ return typeof value === "string" ? value.toUpperCase() : import_node_buffer15.Buffer.isBuffer(value) ? value.toString("utf8").toUpperCase() : void 0;
4968
+ }
4969
+
4970
+ // src/protocol-value.ts
4971
+ var import_node_buffer17 = require("buffer");
4972
+
4973
+ // src/protocol-map-key.ts
4974
+ var import_node_buffer16 = require("buffer");
4975
+ function setProtocolMapEntry(target, encodedKey, value) {
4976
+ if (typeof encodedKey === "string" && !encodedKey.isWellFormed()) {
4977
+ throw new FerricStoreError("native protocol map key must be valid UTF-8");
4978
+ }
4979
+ if (typeof encodedKey !== "string" && !(0, import_node_buffer16.isUtf8)(encodedKey)) {
4980
+ throw new FerricStoreError("native protocol map key must be valid UTF-8");
4981
+ }
4982
+ const key = typeof encodedKey === "string" ? encodedKey : encodedKey.toString("utf8");
4983
+ if (Object.hasOwn(target, key)) {
4984
+ throw new FerricStoreError(`native protocol response contains duplicate map key ${JSON.stringify(key)}`);
4985
+ }
4986
+ setOwnValue2(target, key, value);
4895
4987
  }
4896
4988
 
4897
4989
  // src/protocol-value.ts
4898
- var import_node_buffer15 = require("buffer");
4899
4990
  function planValueWithLimit(value, maxBytes) {
4900
4991
  const budget = {
4901
4992
  maxBytes,
@@ -4950,7 +5041,7 @@ function planContainerValue(value, budget, ancestors, depth) {
4950
5041
  let byteLength = 5;
4951
5042
  let index = 0;
4952
5043
  for (const [key, item] of entries) {
4953
- const keyByteLength = import_node_buffer15.Buffer.byteLength(key);
5044
+ const keyByteLength = import_node_buffer17.Buffer.byteLength(key);
4954
5045
  consumeEncodeBytes(budget, 4 + keyByteLength);
4955
5046
  const valuePlan = planValueAt(item, budget, ancestors, depth + 1);
4956
5047
  entryPlans[index] = { key, keyByteLength, value: valuePlan };
@@ -4989,17 +5080,21 @@ function planScalarValue(value, budget) {
4989
5080
  return { byteLength: 9, tag: 3, value: BigInt(value) };
4990
5081
  }
4991
5082
  if (typeof value === "bigint") {
4992
- if (value < MIN_I64 || value > MAX_I64) {
4993
- throw new FerricStoreError("integer exceeds the signed 64-bit native range");
5083
+ if (value >= MIN_I642 && value <= MAX_I642) {
5084
+ consumeEncodeBytes(budget, 9);
5085
+ return { byteLength: 9, tag: 3, value };
4994
5086
  }
4995
- consumeEncodeBytes(budget, 9);
4996
- return { byteLength: 9, tag: 3, value };
5087
+ if (value > MAX_I642 && value <= MAX_U64) {
5088
+ consumeEncodeBytes(budget, 9);
5089
+ return { byteLength: 9, tag: 8, value };
5090
+ }
5091
+ throw new FerricStoreError("integer exceeds the signed or unsigned 64-bit native range");
4997
5092
  }
4998
5093
  if (typeof value === "number") {
4999
5094
  consumeEncodeBytes(budget, 9);
5000
5095
  return { byteLength: 9, tag: 7, value };
5001
5096
  }
5002
- if (typeof value === "string" || import_node_buffer15.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5097
+ if (typeof value === "string" || import_node_buffer17.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5003
5098
  const valueByteLength = binaryValueByteLength(value);
5004
5099
  const byteLength = 5 + valueByteLength;
5005
5100
  consumeEncodeBytes(budget, byteLength);
@@ -5023,7 +5118,7 @@ function writeValuePlan(output, start, plan) {
5023
5118
  offset += 4;
5024
5119
  if (typeof plan.value === "string") {
5025
5120
  output.write(plan.value, offset, plan.valueByteLength, "utf8");
5026
- } else if (import_node_buffer15.Buffer.isBuffer(plan.value)) {
5121
+ } else if (import_node_buffer17.Buffer.isBuffer(plan.value)) {
5027
5122
  plan.value.copy(output, offset);
5028
5123
  } else {
5029
5124
  output.set(plan.value, offset);
@@ -5048,6 +5143,9 @@ function writeValuePlan(output, start, plan) {
5048
5143
  case 7:
5049
5144
  output.writeDoubleBE(plan.value, offset);
5050
5145
  return offset + 8;
5146
+ case 8:
5147
+ output.writeBigUInt64BE(plan.value, offset);
5148
+ return offset + 8;
5051
5149
  }
5052
5150
  }
5053
5151
  function consumeEncodeBytes(budget, bytes2) {
@@ -5105,7 +5203,7 @@ function decodeValueAt(data, offset, limits, budget, depth) {
5105
5203
  const key = readBinary(data, offset);
5106
5204
  offset = key.offset;
5107
5205
  const item = decodeValueAt(data, offset, limits, budget, depth + 1);
5108
- setOwnValue2(value, key.value.toString("utf8"), item.value);
5206
+ setProtocolMapEntry(value, key.value, item.value);
5109
5207
  offset = item.offset;
5110
5208
  }
5111
5209
  return { value, offset };
@@ -5114,6 +5212,14 @@ function decodeValueAt(data, offset, limits, budget, depth) {
5114
5212
  requireAvailable(data, offset, 8);
5115
5213
  return { value: data.readDoubleBE(offset), offset: offset + 8 };
5116
5214
  }
5215
+ if (tag === 8) {
5216
+ requireAvailable(data, offset, 8);
5217
+ const integer2 = data.readBigUInt64BE(offset);
5218
+ return {
5219
+ value: integer2 <= MAX_SAFE_INTEGER_BIGINT ? Number(integer2) : integer2,
5220
+ offset: offset + 8
5221
+ };
5222
+ }
5117
5223
  throw new FerricStoreError(`unknown protocol value tag ${tag}`);
5118
5224
  }
5119
5225
  function decodeValueWithBudget(data, offset, budget) {
@@ -5157,20 +5263,20 @@ function requireAvailable(data, offset, size) {
5157
5263
  }
5158
5264
 
5159
5265
  // src/key-slot-validation.ts
5160
- var import_node_buffer17 = require("buffer");
5266
+ var import_node_buffer19 = require("buffer");
5161
5267
 
5162
5268
  // src/topology-utilities.ts
5163
- var import_node_buffer16 = require("buffer");
5269
+ var import_node_buffer18 = require("buffer");
5164
5270
  function isPlainObject3(value) {
5165
- return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer16.Buffer.isBuffer(value);
5271
+ return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer18.Buffer.isBuffer(value);
5166
5272
  }
5167
5273
  function getField(source, ...keys) {
5168
5274
  if (source instanceof Map) {
5169
5275
  for (const key of keys) {
5170
5276
  if (source.has(key)) return source.get(key);
5171
- const bufferKey = import_node_buffer16.Buffer.from(key);
5277
+ const bufferKey = import_node_buffer18.Buffer.from(key);
5172
5278
  for (const [itemKey, value] of source.entries()) {
5173
- if (import_node_buffer16.Buffer.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
5279
+ if (import_node_buffer18.Buffer.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
5174
5280
  }
5175
5281
  }
5176
5282
  return void 0;
@@ -5184,14 +5290,14 @@ function getField(source, ...keys) {
5184
5290
  }
5185
5291
  function textOrUndefined(value) {
5186
5292
  if (typeof value === "string") return value;
5187
- if (import_node_buffer16.Buffer.isBuffer(value)) return value.toString("utf8");
5293
+ if (import_node_buffer18.Buffer.isBuffer(value)) return value.toString("utf8");
5188
5294
  return void 0;
5189
5295
  }
5190
5296
  function numberOrUndefined(value) {
5191
5297
  return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
5192
5298
  }
5193
- function nativeEventName(event) {
5194
- return textOrUndefined(getField(event.value, "event"))?.toUpperCase();
5299
+ function nativeEventName(event2) {
5300
+ return textOrUndefined(getField(event2.value, "event"))?.toUpperCase();
5195
5301
  }
5196
5302
  function endpointFromRange(item) {
5197
5303
  const endpointValue = getField(item, "endpoint");
@@ -5359,7 +5465,7 @@ function stringHashRange(key) {
5359
5465
  var validatedCommands = /* @__PURE__ */ new WeakSet();
5360
5466
  function assertAtomicKeyValueCommandSharesSlot(args) {
5361
5467
  const value = args[0];
5362
- const command = (typeof value === "string" ? value : import_node_buffer17.Buffer.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5468
+ const command = (typeof value === "string" ? value : import_node_buffer19.Buffer.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5363
5469
  if (command === "MSET" || command === "MSETNX") {
5364
5470
  assertKeyValueCommandSharesSlot(args, command);
5365
5471
  }
@@ -5369,7 +5475,7 @@ function assertKeyValueCommandSharesSlot(args, command) {
5369
5475
  let expectedSlot;
5370
5476
  for (let index = 1; index < args.length; index += 2) {
5371
5477
  const key = args[index];
5372
- if (typeof key !== "string" && !import_node_buffer17.Buffer.isBuffer(key)) return;
5478
+ if (typeof key !== "string" && !import_node_buffer19.Buffer.isBuffer(key)) return;
5373
5479
  const slot = routingSlotForKey(key);
5374
5480
  expectedSlot ??= slot;
5375
5481
  if (slot !== expectedSlot) {
@@ -5380,62 +5486,202 @@ function assertKeyValueCommandSharesSlot(args, command) {
5380
5486
  }
5381
5487
 
5382
5488
  // src/protocol-response.ts
5383
- var import_node_buffer21 = require("buffer");
5489
+ var import_node_buffer26 = require("buffer");
5384
5490
 
5385
5491
  // src/protocol-compact-response.ts
5386
- var import_node_buffer20 = require("buffer");
5492
+ var import_node_buffer25 = require("buffer");
5387
5493
 
5388
5494
  // src/native-negotiation.ts
5389
- var import_node_buffer18 = require("buffer");
5495
+ var import_node_buffer20 = require("buffer");
5390
5496
  var EMPTY_COMPACT_RESPONSE_OPCODES = /* @__PURE__ */ new Map();
5391
5497
  function nativeNegotiation(value) {
5392
5498
  const capabilities = field(value, "capabilities") ?? value;
5393
5499
  const limits = field(capabilities, "limits");
5394
- const responseCodecs = field(capabilities, "response_codecs");
5500
+ const rawResponseCodecs = field(capabilities, "response_codecs");
5501
+ const responseCodecs = rawResponseCodecs == null ? void 0 : requiredMap(rawResponseCodecs, "HELLO response_codecs");
5502
+ const schemas = requiredMap(field(capabilities, "schemas"), "HELLO schemas");
5395
5503
  const maxResponseBytes = positiveSafeInteger3(field(limits, "max_response_bytes"));
5396
5504
  return {
5397
5505
  compactResponseOpcodes: parseCompactResponseOpcodes(
5398
5506
  field(responseCodecs, "compact_response_opcodes")
5399
5507
  ),
5508
+ flowQuery: parseFlowQueryNegotiation(capabilities, schemas),
5400
5509
  ...maxResponseBytes == null ? {} : { maxResponseBytes }
5401
5510
  };
5402
5511
  }
5512
+ var REQUIRED_FLOW_QUERY_CAPABILITIES = /* @__PURE__ */ new Set([
5513
+ "flow_query_v1",
5514
+ "flow_query_result_projection_v1",
5515
+ "flow_explain_v1",
5516
+ "flow_explain_analyze_v1",
5517
+ "flow_composite_index_v1",
5518
+ "flow_query_index_status_v1"
5519
+ ]);
5520
+ var REQUIRED_FLOW_QUERY_SHAPES = /* @__PURE__ */ new Set([
5521
+ "runs_by_run_id_record",
5522
+ "runs_by_partition_and_run_id_record",
5523
+ "runs_by_partition_predicates_ordered_records",
5524
+ "runs_by_partition_type_state_ordered_records",
5525
+ "runs_by_partition_type_terminals_ordered_records",
5526
+ "runs_by_partition_metadata_ordered_records",
5527
+ "runs_by_partition_type_running_lease_deadline_ordered_records",
5528
+ "runs_by_partition_parent_ordered_records",
5529
+ "runs_by_partition_root_ordered_records",
5530
+ "runs_by_partition_correlation_ordered_records",
5531
+ "runs_by_partition_predicates_count",
5532
+ "events_by_run_id_ordered_records"
5533
+ ]);
5534
+ function parseFlowQueryNegotiation(capabilities, schemas) {
5535
+ const manifest = requiredMap(field(capabilities, "flow_query"), "HELLO flow_query");
5536
+ const requestContract = requiredBoundedText(manifest, "request_contract");
5537
+ const resultContract = requiredBoundedText(manifest, "result_contract");
5538
+ const explainContract = requiredBoundedText(manifest, "explain_contract");
5539
+ const indexStatusContract = requiredBoundedText(manifest, "index_status_contract");
5540
+ requireEqual(requestContract, "ferric.flow.query.request/v1", "flow_query request_contract");
5541
+ requireEqual(resultContract, "ferric.flow.query.result/v1", "flow_query result_contract");
5542
+ requireEqual(explainContract, "ferric.flow.explain/v1", "flow_query explain_contract");
5543
+ requireEqual(
5544
+ indexStatusContract,
5545
+ "ferric.flow.query.indexes/v1",
5546
+ "flow_query index_status_contract"
5547
+ );
5548
+ const queryCapabilities = boundedTextSet(manifest, "capabilities", 64);
5549
+ const languageVersions = boundedTextSet(manifest, "language_versions", 16);
5550
+ const shapes = boundedTextSet(manifest, "shapes", 128);
5551
+ requireMembers(queryCapabilities, REQUIRED_FLOW_QUERY_CAPABILITIES, "flow_query capability");
5552
+ requireMembers(languageVersions, /* @__PURE__ */ new Set(["FQL1"]), "flow_query language");
5553
+ requireMembers(shapes, REQUIRED_FLOW_QUERY_SHAPES, "flow_query shape");
5554
+ const schema = requiredMap(field(schemas, "FLOW.QUERY"), "HELLO FLOW.QUERY schema");
5555
+ const fields = boundedTextSet(schema, "fields", 64);
5556
+ requireMembers(
5557
+ fields,
5558
+ /* @__PURE__ */ new Set(["version", "query", "params", "deadline_ms"]),
5559
+ "FLOW.QUERY schema field"
5560
+ );
5561
+ const required = boundedTextSet(schema, "required", 16);
5562
+ if (required.size !== 2 || !required.has("version") || !required.has("query")) {
5563
+ throw incompatibleServer("FLOW.QUERY schema must require exactly version and query");
5564
+ }
5565
+ return {
5566
+ requestContract: "ferric.flow.query.request/v1",
5567
+ resultContract: "ferric.flow.query.result/v1",
5568
+ explainContract: "ferric.flow.explain/v1",
5569
+ indexStatusContract: "ferric.flow.query.indexes/v1",
5570
+ capabilities: queryCapabilities,
5571
+ languageVersions,
5572
+ shapes
5573
+ };
5574
+ }
5575
+ function requiredMap(value, context) {
5576
+ if (value instanceof Map) return value;
5577
+ if (typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer20.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
5578
+ return value;
5579
+ }
5580
+ throw incompatibleServer(`${context} is missing or invalid`);
5581
+ }
5582
+ function requiredBoundedText(mapping, name) {
5583
+ const value = strictText(field(mapping, name));
5584
+ if (value == null || value.length === 0 || import_node_buffer20.Buffer.byteLength(value) > 256) {
5585
+ throw incompatibleServer(`HELLO flow_query ${name} must be bounded non-empty text`);
5586
+ }
5587
+ return value;
5588
+ }
5589
+ function boundedTextSet(mapping, name, maximum) {
5590
+ const raw = field(mapping, name);
5591
+ if (!Array.isArray(raw) || raw.length < 1 || raw.length > maximum) {
5592
+ throw incompatibleServer(`HELLO ${name} must contain 1..${maximum} entries`);
5593
+ }
5594
+ const result = /* @__PURE__ */ new Set();
5595
+ for (let index = 0; index < raw.length; index += 1) {
5596
+ if (!Object.hasOwn(raw, index)) throw incompatibleServer(`HELLO ${name} must be dense`);
5597
+ const item = strictText(raw[index]);
5598
+ if (item == null || item.length === 0 || import_node_buffer20.Buffer.byteLength(item) > 256) {
5599
+ throw incompatibleServer(`HELLO ${name} contains invalid text`);
5600
+ }
5601
+ if (result.has(item)) throw incompatibleServer(`HELLO ${name} contains duplicate ${item}`);
5602
+ result.add(item);
5603
+ }
5604
+ return result;
5605
+ }
5606
+ function requireMembers(actual, required, context) {
5607
+ for (const item of required) {
5608
+ if (!actual.has(item)) throw incompatibleServer(`missing ${context} ${JSON.stringify(item)}`);
5609
+ }
5610
+ }
5611
+ function requireEqual(actual, expected, context) {
5612
+ if (actual !== expected) throw incompatibleServer(`${context} must be ${JSON.stringify(expected)}`);
5613
+ }
5614
+ function strictText(value) {
5615
+ if (typeof value === "string") return value;
5616
+ if (import_node_buffer20.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5617
+ try {
5618
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
5619
+ } catch {
5620
+ return void 0;
5621
+ }
5622
+ }
5623
+ return void 0;
5624
+ }
5625
+ function incompatibleServer(message) {
5626
+ return new FerricStoreError(`incompatible FerricStore server: ${message}`);
5627
+ }
5403
5628
  function compactResponseOpcodeSupports(capabilities, codec, opcode) {
5404
5629
  return capabilities?.get(codec)?.has(opcode) === true;
5405
5630
  }
5406
5631
  function parseCompactResponseOpcodes(value) {
5632
+ if (value == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
5407
5633
  const entries = mapEntries(value);
5408
- if (entries == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
5634
+ if (entries == null) {
5635
+ throw incompatibleServer("HELLO compact_response_opcodes must be a map");
5636
+ }
5637
+ if (entries.length > 32) {
5638
+ throw incompatibleServer("HELLO compact_response_opcodes supports at most 32 codecs");
5639
+ }
5409
5640
  const result = /* @__PURE__ */ new Map();
5641
+ let totalOpcodes = 0;
5410
5642
  for (const [rawName, rawOpcodes] of entries) {
5411
- const name = text2(rawName);
5412
- if (name == null || name.length === 0 || !Array.isArray(rawOpcodes)) continue;
5643
+ const name = strictText(rawName);
5644
+ if (name == null || name.length === 0 || import_node_buffer20.Buffer.byteLength(name) > 128) {
5645
+ throw incompatibleServer("HELLO compact_response_opcodes contains an invalid codec name");
5646
+ }
5647
+ if (result.has(name)) {
5648
+ throw incompatibleServer(`HELLO compact_response_opcodes contains duplicate codec ${name}`);
5649
+ }
5650
+ if (!Array.isArray(rawOpcodes)) {
5651
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} must be an array`);
5652
+ }
5653
+ totalOpcodes += rawOpcodes.length;
5654
+ if (totalOpcodes > 1024) {
5655
+ throw incompatibleServer("HELLO compact_response_opcodes supports at most 1024 opcodes");
5656
+ }
5413
5657
  const opcodes = /* @__PURE__ */ new Set();
5414
- let valid = true;
5415
5658
  for (let index = 0; index < rawOpcodes.length; index += 1) {
5416
5659
  if (!Object.hasOwn(rawOpcodes, index)) {
5417
- valid = false;
5418
- break;
5660
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} must be dense`);
5419
5661
  }
5420
- const opcode = unsigned16(rawOpcodes[index]);
5662
+ const opcode = strictUnsigned16(rawOpcodes[index]);
5421
5663
  if (opcode == null) {
5422
- valid = false;
5423
- break;
5664
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} has invalid opcode`);
5665
+ }
5666
+ if (opcodes.has(opcode)) {
5667
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} has duplicate opcode`);
5424
5668
  }
5425
5669
  opcodes.add(opcode);
5426
5670
  }
5427
- if (valid) result.set(name, opcodes);
5671
+ result.set(name, opcodes);
5428
5672
  }
5429
5673
  return result;
5430
5674
  }
5431
5675
  function mapEntries(value) {
5432
5676
  if (value instanceof Map) return [...value.entries()];
5433
- if (typeof value !== "object" || value == null || Array.isArray(value)) return void 0;
5677
+ if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer20.Buffer.isBuffer(value) || value instanceof Uint8Array) return void 0;
5434
5678
  return Object.entries(value);
5435
5679
  }
5436
- function unsigned16(value) {
5437
- const parsed = nonNegativeSafeInteger2(value);
5438
- return parsed != null && parsed <= 65535 ? parsed : void 0;
5680
+ function strictUnsigned16(value) {
5681
+ if (typeof value === "bigint") {
5682
+ return value >= 0n && value <= 0xffffn ? Number(value) : void 0;
5683
+ }
5684
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 65535 ? value : void 0;
5439
5685
  }
5440
5686
  function positiveSafeInteger3(value) {
5441
5687
  const parsed = nonNegativeSafeInteger2(value);
@@ -5454,14 +5700,14 @@ function nonNegativeSafeInteger2(value) {
5454
5700
  }
5455
5701
  function text2(value) {
5456
5702
  if (typeof value === "string") return value;
5457
- if (import_node_buffer18.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5458
- return import_node_buffer18.Buffer.from(value).toString("utf8");
5703
+ if (import_node_buffer20.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5704
+ return import_node_buffer20.Buffer.from(value).toString("utf8");
5459
5705
  }
5460
5706
  return void 0;
5461
5707
  }
5462
5708
 
5463
5709
  // src/protocol-compact-collections.ts
5464
- var import_node_buffer19 = require("buffer");
5710
+ var import_node_buffer21 = require("buffer");
5465
5711
  function decodeCompactIntegerList(data, budget) {
5466
5712
  requireAvailable(data, 0, 5);
5467
5713
  const count = data.readUInt32BE(1);
@@ -5526,7 +5772,7 @@ function readCompactBinaryMap(data, offset, budget) {
5526
5772
  for (let index = 0; index < count; index += 1) {
5527
5773
  const key = readBinary(data, offset);
5528
5774
  const value = readBinary(data, key.offset);
5529
- setOwnValue2(values, key.value.toString("utf8"), value.value);
5775
+ setProtocolMapEntry(values, key.value, value.value);
5530
5776
  offset = value.offset;
5531
5777
  }
5532
5778
  return { value: values, offset };
@@ -5542,39 +5788,274 @@ function requireCompactContainer(count, budget) {
5542
5788
  consumeDecodeItems(count, budget);
5543
5789
  }
5544
5790
 
5545
- // src/protocol-compact-response.ts
5546
- function tryDecodeCompactResponse(opcode, body, hints) {
5547
- if (body.byteLength === 0) return { found: false, value: void 0 };
5548
- const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
5549
- const tag = body.readUInt8(0);
5550
- const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
5551
- if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
5552
- const values = decodeCompactOkList(body, budget);
5553
- return {
5554
- found: true,
5555
- value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values.length === 1 ? "OK" : values
5556
- };
5557
- }
5558
- if (tag === COMPACT_KV_GET && supports(hints, "kv_get_v1", opcode)) {
5559
- return { found: true, value: decodeCompactKvGet(body) };
5791
+ // src/protocol-error-message.ts
5792
+ var import_node_buffer22 = require("buffer");
5793
+ var MAX_ERROR_MESSAGE_CHARS = 4096;
5794
+ var MAX_ERROR_TEXT_BYTES = MAX_ERROR_MESSAGE_CHARS * 4;
5795
+ function protocolErrorMessage(status, value) {
5796
+ const direct = errorText(value);
5797
+ if (direct != null) return truncate(direct);
5798
+ return truncate(`ERR native request failed status=${status}: ${errorDescription(value)}`);
5799
+ }
5800
+ function errorText(value) {
5801
+ if (typeof value === "string") return value;
5802
+ if (import_node_buffer22.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5803
+ return boundedBinaryText(value);
5560
5804
  }
5561
- if ((tag === COMPACT_KV_MGET || tag === COMPACT_KV_MGET_FIXED) && (supports(hints, "kv_mget_v1", opcode) || pipelineValues)) {
5562
- const values = tag === COMPACT_KV_MGET ? decodeCompactMget(body, budget) : decodeCompactMgetFixed(body, budget);
5563
- return {
5564
- found: true,
5565
- value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
5566
- };
5805
+ if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5806
+ const message = value.message;
5807
+ if (typeof message === "string") return message;
5808
+ if (import_node_buffer22.Buffer.isBuffer(message) || message instanceof Uint8Array) {
5809
+ return boundedBinaryText(message);
5810
+ }
5811
+ if (message == null || typeof message !== "object") return String(message);
5567
5812
  }
5568
- if (tag === COMPACT_INTEGER_LIST && pipelineValues) {
5569
- return { found: true, value: markCompactPipelineDecoded(decodeCompactIntegerList(body, budget)) };
5813
+ return void 0;
5814
+ }
5815
+ function boundedBinaryText(value) {
5816
+ const bytes2 = import_node_buffer22.Buffer.isBuffer(value) ? value : import_node_buffer22.Buffer.from(value.buffer, value.byteOffset, value.byteLength);
5817
+ return bytes2.subarray(0, MAX_ERROR_TEXT_BYTES).toString("utf8");
5818
+ }
5819
+ function errorDescription(value) {
5820
+ if (Array.isArray(value)) return `[array length=${value.length}]`;
5821
+ if (value instanceof Map) return `[map size=${value.size}]`;
5822
+ if (typeof value === "object" && value != null) return "[object]";
5823
+ return String(value);
5824
+ }
5825
+ function truncate(value) {
5826
+ return value.length <= MAX_ERROR_MESSAGE_CHARS ? value : `${value.slice(0, MAX_ERROR_MESSAGE_CHARS - 1)}\u2026`;
5827
+ }
5828
+
5829
+ // src/protocol-flow-query-result.ts
5830
+ var import_node_buffer24 = require("buffer");
5831
+
5832
+ // src/protocol-binary-detacher.ts
5833
+ var import_node_buffer23 = require("buffer");
5834
+ var MIN_PINNED_BACKING_BYTES = 64;
5835
+ function detachDecodedBinary(value, backingBytes) {
5836
+ if (import_node_buffer23.Buffer.isBuffer(value)) return detachBuffer(value, backingBytes);
5837
+ if (Array.isArray(value)) {
5838
+ for (let index = 0; index < value.length; index += 1) {
5839
+ value[index] = detachDecodedBinary(value[index], backingBytes);
5840
+ }
5841
+ return value;
5570
5842
  }
5571
- if (tag === COMPACT_BINARY_LIST_LIST && pipelineValues) {
5572
- return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryListList(body, budget)) };
5843
+ if (!isDecodedRecord(value)) return value;
5844
+ for (const key of Object.keys(value)) {
5845
+ setOwnValue2(value, key, detachDecodedBinary(value[key], backingBytes));
5573
5846
  }
5574
- if (tag === COMPACT_BINARY_MAP_LIST && pipelineValues) {
5575
- return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryMapList(body, budget)) };
5847
+ return value;
5848
+ }
5849
+ function detachBuffer(value, backingBytes) {
5850
+ if (backingBytes <= Math.max(MIN_PINNED_BACKING_BYTES, value.byteLength * 2)) {
5851
+ return value;
5576
5852
  }
5577
- if (tag === COMPACT_PIPELINE_RESPONSE && pipelineValues) {
5853
+ if (value.byteLength === 0) return import_node_buffer23.Buffer.alloc(0);
5854
+ const detached = import_node_buffer23.Buffer.allocUnsafeSlow(value.byteLength);
5855
+ value.copy(detached);
5856
+ return detached;
5857
+ }
5858
+ function isDecodedRecord(value) {
5859
+ if (typeof value !== "object" || value == null) return false;
5860
+ const prototype = Object.getPrototypeOf(value);
5861
+ return prototype === Object.prototype || prototype === null;
5862
+ }
5863
+
5864
+ // src/protocol-flow-query-result.ts
5865
+ var CONTRACT = "ferric.flow.query.result/v1";
5866
+ var MAX_RECORDS = 100;
5867
+ var MAX_CURSOR_BYTES = 4096;
5868
+ var RECORD_FIELDS = [
5869
+ "id",
5870
+ "type",
5871
+ "state",
5872
+ "version",
5873
+ "priority",
5874
+ "partition_key",
5875
+ "created_at_ms",
5876
+ "updated_at_ms",
5877
+ "next_run_at_ms",
5878
+ "lease_deadline_ms",
5879
+ "attempts",
5880
+ "run_state",
5881
+ "max_active_ms",
5882
+ "parent_flow_id",
5883
+ "root_flow_id",
5884
+ "correlation_id",
5885
+ "attributes",
5886
+ "state_meta",
5887
+ "event_id",
5888
+ "fields"
5889
+ ];
5890
+ var RECORD_FIELD_MASK = (1 << RECORD_FIELDS.length) - 1;
5891
+ var QUALITY_VALUES = [
5892
+ ["authoritative", "projected_exact", "exact", "not_applicable"],
5893
+ ["current", "projection_watermark", "not_applicable"],
5894
+ ["complete", "unavailable"],
5895
+ ["none", "complete", "authenticated_seek", "live_seek"]
5896
+ ];
5897
+ var QUALITY_FIELDS = ["exactness", "freshness", "coverage", "pagination"];
5898
+ var USAGE_FIELDS = [
5899
+ "range_seeks",
5900
+ "range_pages",
5901
+ "scanned_entries",
5902
+ "scanned_bytes",
5903
+ "hydrated_records",
5904
+ "residual_checks",
5905
+ "duplicate_entries",
5906
+ "result_records",
5907
+ "response_bytes",
5908
+ "memory_high_water_bytes",
5909
+ "wall_time_us"
5910
+ ];
5911
+ function decodeCompactFlowQueryResult(data, budget) {
5912
+ requireAvailable(data, 0, 2 + QUALITY_FIELDS.length + USAGE_FIELDS.length * 8);
5913
+ if (data.readUInt8(0) !== COMPACT_FLOW_QUERY_RESULT) {
5914
+ throw new FerricStoreError("expected compact FLOW.QUERY result");
5915
+ }
5916
+ const kind = data.readUInt8(1);
5917
+ let offset = 2;
5918
+ const quality = {};
5919
+ for (let index = 0; index < QUALITY_FIELDS.length; index += 1) {
5920
+ const field3 = QUALITY_FIELDS[index];
5921
+ const values = QUALITY_VALUES[index];
5922
+ if (field3 == null || values == null) throw new FerricStoreError("invalid compact FLOW.QUERY quality schema");
5923
+ const value = values[data.readUInt8(offset)];
5924
+ if (value == null) throw new FerricStoreError("invalid compact FLOW.QUERY quality code");
5925
+ quality[field3] = import_node_buffer24.Buffer.from(value);
5926
+ offset += 1;
5927
+ }
5928
+ const usage = {};
5929
+ for (const field3 of USAGE_FIELDS) {
5930
+ const read = readU64(data, offset);
5931
+ usage[field3] = read.value;
5932
+ offset = read.offset;
5933
+ }
5934
+ let result;
5935
+ if (kind === 0) {
5936
+ const page = readPage(data, offset);
5937
+ offset = page.offset;
5938
+ requireAvailable(data, offset, 4);
5939
+ const count = data.readUInt32BE(offset);
5940
+ offset += 4;
5941
+ if (count > MAX_RECORDS) throw new FerricStoreError("compact FLOW.QUERY page exceeds 100 records");
5942
+ consumeDecodeItems(count, budget);
5943
+ const records = new Array(count);
5944
+ for (let index = 0; index < count; index += 1) {
5945
+ const read = readRecord(data, offset, budget);
5946
+ records[index] = read.value;
5947
+ offset = read.offset;
5948
+ }
5949
+ result = { version: import_node_buffer24.Buffer.from(CONTRACT), records, page: page.value, quality, usage };
5950
+ } else if (kind === 1) {
5951
+ const count = readU64(data, offset);
5952
+ offset = count.offset;
5953
+ result = {
5954
+ version: import_node_buffer24.Buffer.from(CONTRACT),
5955
+ result: { kind: import_node_buffer24.Buffer.from("count"), value: count.value },
5956
+ quality,
5957
+ usage
5958
+ };
5959
+ } else {
5960
+ throw new FerricStoreError(`unsupported compact FLOW.QUERY result kind ${kind}`);
5961
+ }
5962
+ if (offset !== data.byteLength) throw new FerricStoreError("trailing compact FLOW.QUERY result bytes");
5963
+ if (BigInt(usage.response_bytes) !== BigInt(data.byteLength)) {
5964
+ throw new FerricStoreError("compact FLOW.QUERY response_bytes does not match its payload");
5965
+ }
5966
+ return result;
5967
+ }
5968
+ function readPage(data, offset) {
5969
+ requireAvailable(data, offset, 5);
5970
+ const hasMoreCode = data.readUInt8(offset);
5971
+ const size = data.readUInt32BE(offset + 1);
5972
+ offset += 5;
5973
+ if (hasMoreCode === 0 && size === NULL_U32) {
5974
+ return { value: { has_more: false, cursor: null }, offset };
5975
+ }
5976
+ if (hasMoreCode !== 1 || size === 0 || size === NULL_U32 || size > MAX_CURSOR_BYTES) {
5977
+ throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
5978
+ }
5979
+ requireAvailable(data, offset, size);
5980
+ return {
5981
+ value: {
5982
+ has_more: true,
5983
+ cursor: detachDecodedBinary(data.subarray(offset, offset + size), data.byteLength)
5984
+ },
5985
+ offset: offset + size
5986
+ };
5987
+ }
5988
+ function readRecord(data, offset, budget) {
5989
+ requireAvailable(data, offset, 4);
5990
+ const bitmap = data.readUInt32BE(offset);
5991
+ offset += 4;
5992
+ if ((bitmap & ~RECORD_FIELD_MASK) !== 0) {
5993
+ throw new FerricStoreError("compact FLOW.QUERY record contains reserved fields");
5994
+ }
5995
+ consumeDecodeItems(populationCount(bitmap), budget);
5996
+ const record = {};
5997
+ for (let index = 0; index < RECORD_FIELDS.length; index += 1) {
5998
+ if ((bitmap & 1 << index) === 0) continue;
5999
+ const field3 = RECORD_FIELDS[index];
6000
+ if (field3 == null) throw new FerricStoreError("invalid compact FLOW.QUERY record schema");
6001
+ const read = decodeValueWithBudget(data, offset, budget);
6002
+ setOwnValue2(record, field3, detachDecodedBinary(read.value, data.byteLength));
6003
+ offset = read.offset;
6004
+ }
6005
+ return { value: record, offset };
6006
+ }
6007
+ function readU64(data, offset) {
6008
+ requireAvailable(data, offset, 8);
6009
+ const value = data.readBigUInt64BE(offset);
6010
+ return {
6011
+ value: value <= MAX_SAFE_INTEGER_BIGINT ? Number(value) : value,
6012
+ offset: offset + 8
6013
+ };
6014
+ }
6015
+ function populationCount(value) {
6016
+ let remaining = value >>> 0;
6017
+ let count = 0;
6018
+ while (remaining !== 0) {
6019
+ remaining &= remaining - 1;
6020
+ count += 1;
6021
+ }
6022
+ return count;
6023
+ }
6024
+
6025
+ // src/protocol-compact-response.ts
6026
+ function tryDecodeCompactResponse(opcode, body, hints) {
6027
+ if (body.byteLength === 0) return { found: false, value: void 0 };
6028
+ const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
6029
+ const tag = body.readUInt8(0);
6030
+ validateCompactResponseItems(tag, opcode, body, hints);
6031
+ const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
6032
+ if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
6033
+ const values = decodeCompactOkList(body, budget);
6034
+ return {
6035
+ found: true,
6036
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values.length === 1 ? "OK" : values
6037
+ };
6038
+ }
6039
+ if (tag === COMPACT_KV_GET && supports(hints, "kv_get_v1", opcode)) {
6040
+ return { found: true, value: decodeCompactKvGet(body) };
6041
+ }
6042
+ if ((tag === COMPACT_KV_MGET || tag === COMPACT_KV_MGET_FIXED) && (supports(hints, "kv_mget_v1", opcode) || pipelineValues)) {
6043
+ const values = tag === COMPACT_KV_MGET ? decodeCompactMget(body, budget) : decodeCompactMgetFixed(body, budget);
6044
+ return {
6045
+ found: true,
6046
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
6047
+ };
6048
+ }
6049
+ if (tag === COMPACT_INTEGER_LIST && pipelineValues) {
6050
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactIntegerList(body, budget)) };
6051
+ }
6052
+ if (tag === COMPACT_BINARY_LIST_LIST && pipelineValues) {
6053
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryListList(body, budget)) };
6054
+ }
6055
+ if (tag === COMPACT_BINARY_MAP_LIST && pipelineValues) {
6056
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryMapList(body, budget)) };
6057
+ }
6058
+ if (tag === COMPACT_PIPELINE_RESPONSE && pipelineValues) {
5578
6059
  return { found: true, value: decodeCompactPipeline(body, budget, hints.pipelineClaimModes) };
5579
6060
  }
5580
6061
  if (tag === COMPACT_FLOW_CLAIM_JOBS && (supports(hints, "flow_claim_jobs_v1", opcode) || pipelineValues)) {
@@ -5597,6 +6078,9 @@ function tryDecodeCompactResponse(opcode, body, hints) {
5597
6078
  value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(read.value) : read.value
5598
6079
  };
5599
6080
  }
6081
+ if (tag === COMPACT_FLOW_QUERY_RESULT && supports(hints, "flow_query_result_v1", opcode)) {
6082
+ return { found: true, value: decodeCompactFlowQueryResult(body, budget) };
6083
+ }
5600
6084
  return { found: false, value: void 0 };
5601
6085
  }
5602
6086
  function supports(hints, codec, opcode) {
@@ -5607,7 +6091,7 @@ function decodeCompactOkList(data, budget) {
5607
6091
  const count = data.readUInt32BE(1);
5608
6092
  requireCompactContainer2(count, budget);
5609
6093
  if (data.byteLength !== 5) throw new FerricStoreError("invalid compact OK list response");
5610
- return Array.from({ length: count }, () => import_node_buffer20.Buffer.from("OK"));
6094
+ return Array.from({ length: count }, () => import_node_buffer25.Buffer.from("OK"));
5611
6095
  }
5612
6096
  function decodeCompactKvGet(data) {
5613
6097
  requireAvailable(data, 0, 2);
@@ -5653,7 +6137,7 @@ function decodeCompactMgetFixed(data, budget) {
5653
6137
  if (size === NULL_U32 || data.byteLength !== expected) {
5654
6138
  throw new FerricStoreError("invalid compact fixed MGET response");
5655
6139
  }
5656
- if (size === 0) return new Array(count).fill(import_node_buffer20.Buffer.alloc(0));
6140
+ if (size === 0) return new Array(count).fill(import_node_buffer25.Buffer.alloc(0));
5657
6141
  const values = new Array(count);
5658
6142
  for (let index = 0, offset = 9; index < count; index += 1, offset += size) {
5659
6143
  values[index] = data.subarray(offset, offset + size);
@@ -5714,7 +6198,7 @@ function decodeCompactPipeline(data, budget, claimModes) {
5714
6198
  const read = readBinary(data, offset);
5715
6199
  const errorStatus = status === 1 ? "busy" : "error";
5716
6200
  values[index] = classifyServerError(
5717
- errorMessage(status === 1 ? 4 : 1, read.value),
6201
+ protocolErrorMessage(status === 1 ? 4 : 1, read.value),
5718
6202
  read.value,
5719
6203
  void 0,
5720
6204
  errorStatus
@@ -5824,13 +6308,13 @@ function readCompactFlowRecord(data, offset, budget = { remainingItems: DEFAULT_
5824
6308
  let key;
5825
6309
  if (keyId === 0) {
5826
6310
  const read2 = readBinary(data, offset);
5827
- key = read2.value.toString("utf8");
6311
+ key = read2.value;
5828
6312
  offset = read2.offset;
5829
6313
  } else {
5830
6314
  key = FLOW_RECORD_FIELD_KEYS[keyId] ?? `field_${keyId}`;
5831
6315
  }
5832
6316
  const read = decodeValueWithBudget(data, offset, budget);
5833
- setOwnValue2(record, key, read.value);
6317
+ setProtocolMapEntry(record, key, read.value);
5834
6318
  offset = read.offset;
5835
6319
  }
5836
6320
  return { value: record, offset };
@@ -5866,15 +6350,29 @@ function requireCompactContainer2(count, budget) {
5866
6350
  }
5867
6351
  consumeDecodeItems(count, budget);
5868
6352
  }
5869
- function errorMessage(status, value) {
5870
- if (typeof value === "string") return value;
5871
- if (import_node_buffer20.Buffer.isBuffer(value)) return value.toString("utf8");
5872
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5873
- const message = value.message;
5874
- return typeof message === "string" ? message : String(message);
6353
+ function validateCompactResponseItems(tag, opcode, data, hints) {
6354
+ const scalarItems = opcode === OPCODES.set || opcode === OPCODES.mset ? 1 : void 0;
6355
+ const expected = scalarItems ?? hints.compactResponseItems;
6356
+ if (expected == null || !COUNTED_COMPACT_TAGS.has(tag)) return;
6357
+ requireAvailable(data, 0, 5);
6358
+ const actual = data.readUInt32BE(1);
6359
+ if (actual !== expected) {
6360
+ throw new FerricStoreError(
6361
+ `compact response returned ${actual} items; expected ${expected} items`
6362
+ );
5875
6363
  }
5876
- return `ERR native request failed status=${status}: ${String(value)}`;
5877
6364
  }
6365
+ var COUNTED_COMPACT_TAGS = /* @__PURE__ */ new Set([
6366
+ COMPACT_FLOW_CLAIM_JOBS,
6367
+ COMPACT_OK_LIST,
6368
+ COMPACT_KV_MGET,
6369
+ COMPACT_FLOW_RECORD_LIST,
6370
+ COMPACT_BINARY_LIST_LIST,
6371
+ COMPACT_BINARY_MAP_LIST,
6372
+ COMPACT_INTEGER_LIST,
6373
+ COMPACT_KV_MGET_FIXED,
6374
+ COMPACT_PIPELINE_RESPONSE
6375
+ ]);
5878
6376
 
5879
6377
  // src/protocol-response.ts
5880
6378
  function decodeResponse(frame, expectedOpcode, hints = {}) {
@@ -5892,9 +6390,16 @@ function decodeResponse(frame, expectedOpcode, hints = {}) {
5892
6390
  }
5893
6391
  const status = frame.body.readUInt16BE(0);
5894
6392
  const body = frame.body.subarray(2);
5895
- const value = decodeResponseValue(frame.opcode, body, hints);
6393
+ const customPayload = (frame.flags & FLAG_CUSTOM_PAYLOAD) !== 0;
6394
+ const value = decodeResponseValue(
6395
+ frame.opcode,
6396
+ body,
6397
+ hints,
6398
+ status === STATUS_OK,
6399
+ customPayload
6400
+ );
5896
6401
  if (status === STATUS_OK) return value;
5897
- const message = errorMessage2(status, value);
6402
+ const message = protocolErrorMessage(status, value);
5898
6403
  throw classifyServerError(message, value, void 0, status);
5899
6404
  }
5900
6405
  function unwrapPipelineResponse(value, options = {}, expectedItems) {
@@ -5933,7 +6438,7 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5933
6438
  continue;
5934
6439
  }
5935
6440
  const error = classifyServerError(
5936
- errorMessage2(status === "busy" ? 4 : 1, payload),
6441
+ protocolErrorMessage(status === "busy" ? 4 : 1, payload),
5937
6442
  payload,
5938
6443
  void 0,
5939
6444
  status
@@ -5948,28 +6453,24 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5948
6453
  return out;
5949
6454
  }
5950
6455
  function pipelineStatus(value) {
5951
- if (typeof value !== "string" && !import_node_buffer21.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return null;
6456
+ if (typeof value !== "string" && !import_node_buffer26.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return null;
5952
6457
  const status = asText(value).toLowerCase();
5953
6458
  return status === "ok" || status === "busy" || status === "error" ? status : null;
5954
6459
  }
5955
- function decodeResponseValue(opcode, body, hints) {
5956
- const compact = tryDecodeCompactResponse(opcode, body, hints);
5957
- if (compact.found) return compact.value;
6460
+ function decodeResponseValue(opcode, body, hints, allowCompact, customPayload) {
6461
+ if (customPayload && allowCompact) {
6462
+ const compact = tryDecodeCompactResponse(opcode, body, hints);
6463
+ if (compact.found) return compact.value;
6464
+ }
6465
+ if (customPayload) {
6466
+ throw new FerricStoreError("unsupported or malformed custom protocol response", { raw: body });
6467
+ }
5958
6468
  const decoded = decodeValue(body);
5959
6469
  if (decoded.offset !== body.byteLength) {
5960
6470
  throw new FerricStoreError("native protocol response has trailing bytes", { raw: body });
5961
6471
  }
5962
6472
  return decoded.value;
5963
6473
  }
5964
- function errorMessage2(status, value) {
5965
- if (typeof value === "string") return value;
5966
- if (import_node_buffer21.Buffer.isBuffer(value)) return value.toString("utf8");
5967
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5968
- const message = value.message;
5969
- return typeof message === "string" ? message : String(message);
5970
- }
5971
- return `ERR native request failed status=${status}: ${String(value)}`;
5972
- }
5973
6474
 
5974
6475
  // src/protocol.ts
5975
6476
  function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
@@ -5979,7 +6480,7 @@ function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGE
5979
6480
  const bodyLength = customPayload ? binaryValueByteLength(command.payload) : plan?.byteLength ?? 0;
5980
6481
  if (bodyLength > bodyLimit) throw requestFrameTooLarge(bodyLimit);
5981
6482
  const flags = command.flags ?? 0;
5982
- const frame = import_node_buffer22.Buffer.allocUnsafe(HEADER_SIZE + bodyLength);
6483
+ const frame = import_node_buffer27.Buffer.allocUnsafe(HEADER_SIZE + bodyLength);
5983
6484
  frame.write(MAGIC, 0, "ascii");
5984
6485
  frame.writeUInt8(REQUEST_VERSION, 4);
5985
6486
  frame.writeUInt8(flags, 5);
@@ -6080,18 +6581,18 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
6080
6581
  }
6081
6582
  if (command === "SET" && commandArgs2.length >= 2) {
6082
6583
  const payload = stringSetPayload(commandArgs2);
6083
- return payload == null ? commandExec(args) : { opcode: OPCODES.set, payload };
6584
+ return payload == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.set, payload };
6084
6585
  }
6085
6586
  if (command === "MGET" && commandArgs2.length > 0) {
6086
6587
  const compact = allowCustomPayload ? compactKeyPipelinePayload(OPCODES.mget, commandArgs2, 2, maxBodyBytes) : void 0;
6087
- if (compact != null) return compact;
6088
- return commandArgs2.every(isBinaryCommandArgument) ? { opcode: OPCODES.mget, payload: { keys: commandArgs2 } } : commandExec(args);
6588
+ if (compact != null) return { ...compact, compactResponseItems: commandArgs2.length };
6589
+ return commandArgs2.every(isBinaryCommandArgument) ? { compactResponseItems: commandArgs2.length, opcode: OPCODES.mget, payload: { keys: commandArgs2 } } : commandExec(args);
6089
6590
  }
6090
6591
  if (command === "MSET" && commandArgs2.length >= 2 && commandArgs2.length % 2 === 0) {
6091
6592
  const compact = allowCustomPayload ? compactMsetPayload(commandArgs2, maxBodyBytes) : void 0;
6092
- if (compact != null) return compact;
6593
+ if (compact != null) return { ...compact, compactResponseItems: 1 };
6093
6594
  const pairs = typedKeyValuePairs(commandArgs2);
6094
- return pairs == null ? commandExec(args) : { opcode: OPCODES.mset, payload: { pairs } };
6595
+ return pairs == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.mset, payload: { pairs } };
6095
6596
  }
6096
6597
  if (command === "DEL" && commandArgs2.length > 0) {
6097
6598
  return commandArgs2.every(isBinaryCommandArgument) ? { opcode: OPCODES.del, payload: { keys: commandArgs2 } } : commandExec(args);
@@ -6101,8 +6602,8 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
6101
6602
  if (command === "FLOW.HISTORY") {
6102
6603
  return flowHistoryPayload(commandArgs2) ?? commandExec(args);
6103
6604
  }
6104
- if (command === "FLOW.LIST") {
6105
- return (allowCustomPayload ? compactFlowListPayload(commandArgs2, maxBodyBytes) : void 0) ?? commandExec(args);
6605
+ if (command === "FLOW.QUERY") {
6606
+ return { opcode: OPCODES.flowQuery, payload: flowQueryPayload(commandArgs2) };
6106
6607
  }
6107
6608
  if (command === "FLOW.POLICY.SET") {
6108
6609
  return flowPolicySetPayload(commandArgs2) ?? commandExec(args);
@@ -6261,24 +6762,17 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
6261
6762
  if (command === "FLOW.RUN_STEPS_MANY") {
6262
6763
  return flowAdminPayload(OPCODES.flowRunStepsMany, commandArgs2) ?? commandExec(args);
6263
6764
  }
6264
- if (command === "FLOW.SEARCH") {
6265
- if (hasFlowCommandOnlyOption(command, commandArgs2)) {
6266
- const fallback = commandExec(args);
6267
- try {
6268
- const parsed = flowSearchPayload(commandArgs2);
6269
- return parsed == null ? fallback : withFlowPartitionRouting(fallback, parsed.payload);
6270
- } catch {
6271
- return fallback;
6272
- }
6273
- }
6274
- return flowSearchPayload(commandArgs2) ?? commandExec(args);
6275
- }
6276
6765
  return commandExec(args);
6277
6766
  }
6278
6767
  function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6279
6768
  const compact = compactPipelinePayload(commands, maxBodyBytes);
6280
6769
  if (compact != null) {
6281
- return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.pipeline, payload: compact };
6770
+ return {
6771
+ compactResponseItems: commands.length,
6772
+ flags: FLAG_CUSTOM_PAYLOAD,
6773
+ opcode: OPCODES.pipeline,
6774
+ payload: compact
6775
+ };
6282
6776
  }
6283
6777
  const protocols = new Array(commands.length);
6284
6778
  for (let index = 0; index < commands.length; index += 1) {
@@ -6317,6 +6811,7 @@ function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6317
6811
  const pipelineClaimModes = pipelineProtocols.map((protocol) => protocol.compactClaimMode);
6318
6812
  const hasPipelineClaimMode = pipelineClaimModes.some((mode) => mode != null);
6319
6813
  return {
6814
+ compactResponseItems: commands.length,
6320
6815
  opcode: OPCODES.pipeline,
6321
6816
  payload: {
6322
6817
  atomicity: "none",
@@ -6365,7 +6860,7 @@ var import_node_net2 = require("net");
6365
6860
  var import_node_tls2 = require("tls");
6366
6861
 
6367
6862
  // src/client-native-options.ts
6368
- var import_node_buffer23 = require("buffer");
6863
+ var import_node_buffer28 = require("buffer");
6369
6864
 
6370
6865
  // src/string-array-snapshot.ts
6371
6866
  function snapshotOwnStringArray(values, name) {
@@ -6448,7 +6943,7 @@ function snapshotTlsOptions(options) {
6448
6943
  return Object.freeze(snapshot);
6449
6944
  }
6450
6945
  function snapshotTlsValue(value, name) {
6451
- if (import_node_buffer23.Buffer.isBuffer(value)) return import_node_buffer23.Buffer.from(value);
6946
+ if (import_node_buffer28.Buffer.isBuffer(value)) return import_node_buffer28.Buffer.from(value);
6452
6947
  if (value instanceof Uint8Array) return value.slice();
6453
6948
  if (Array.isArray(value)) {
6454
6949
  const snapshot = new Array(value.length);
@@ -7003,7 +7498,7 @@ var NativeChunkAssembler = class {
7003
7498
  };
7004
7499
 
7005
7500
  // src/native-response-handler.ts
7006
- var import_node_buffer24 = require("buffer");
7501
+ var import_node_buffer29 = require("buffer");
7007
7502
 
7008
7503
  // src/native-receive-buffer.ts
7009
7504
  var FRAME_ASSEMBLY_PAGE_BYTES = 64 * 1024;
@@ -7303,7 +7798,7 @@ var NativeResponseHandler = class {
7303
7798
  compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
7304
7799
  });
7305
7800
  if (frame.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
7306
- const event = {
7801
+ const event2 = {
7307
7802
  flags: frame.flags,
7308
7803
  laneId: frame.laneId,
7309
7804
  opcode: frame.opcode,
@@ -7311,7 +7806,7 @@ var NativeResponseHandler = class {
7311
7806
  };
7312
7807
  if (frame.opcode === OPCODES.goaway) this.options.beginDraining();
7313
7808
  try {
7314
- const callback = this.options.onEvent?.(event);
7809
+ const callback = this.options.onEvent?.(event2);
7315
7810
  if (callback != null) void Promise.resolve(callback).catch(() => void 0);
7316
7811
  } catch {
7317
7812
  }
@@ -7338,7 +7833,7 @@ var NativeRequestScheduler = class {
7338
7833
  };
7339
7834
 
7340
7835
  // src/native-write-queue.ts
7341
- var import_node_buffer25 = require("buffer");
7836
+ var import_node_buffer30 = require("buffer");
7342
7837
  var NativeWriteQueue = class {
7343
7838
  constructor(socket, maxQueuedWriteBytes, isClosed, hasPending, rejectPending) {
7344
7839
  this.socket = socket;
@@ -7475,12 +7970,14 @@ var NativeConnectionCapabilities = class {
7475
7970
  }
7476
7971
  configuredRequestFrameBytes;
7477
7972
  compactResponseOpcodes = EMPTY_COMPACT_RESPONSE_OPCODES;
7973
+ flowQuery;
7478
7974
  requestFrameBytes;
7479
7975
  negotiatedRequestFrameBytes;
7480
7976
  apply(value) {
7481
7977
  const limits = startupLimits(value);
7482
7978
  const negotiation = nativeNegotiation(value);
7483
7979
  this.compactResponseOpcodes = negotiation.compactResponseOpcodes;
7980
+ this.flowQuery = negotiation.flowQuery;
7484
7981
  if (limits.frameBytes != null) {
7485
7982
  this.negotiatedRequestFrameBytes = Math.min(
7486
7983
  this.configuredRequestFrameBytes,
@@ -7500,6 +7997,19 @@ var NativeConnectionCapabilities = class {
7500
7997
  }
7501
7998
  };
7502
7999
 
8000
+ // src/native-startup-payload.ts
8001
+ function nativeStartupPayload(clientName, events) {
8002
+ const name = clientName ?? "ferricstore-typescript";
8003
+ return {
8004
+ client_name: name,
8005
+ compact_flow_responses: true,
8006
+ compact_response_codecs: ["flow_query_result_v1"],
8007
+ compression: "none",
8008
+ driver_name: name,
8009
+ ...events == null || events.length === 0 ? {} : { events: [...events] }
8010
+ };
8011
+ }
8012
+
7503
8013
  // src/native-adapter.ts
7504
8014
  var NativeAdapter = class _NativeAdapter {
7505
8015
  socket;
@@ -7658,13 +8168,7 @@ var NativeAdapter = class _NativeAdapter {
7658
8168
  const response = await this.request({
7659
8169
  laneId: 0,
7660
8170
  opcode: OPCODES.startup,
7661
- payload: {
7662
- client_name: clientName ?? "ferricstore-typescript",
7663
- compact_flow_responses: true,
7664
- compression: "none",
7665
- driver_name: clientName ?? "ferricstore-typescript",
7666
- ...events == null || events.length === 0 ? {} : { events: [...events] }
7667
- }
8171
+ payload: nativeStartupPayload(clientName, events)
7668
8172
  });
7669
8173
  this.applyStartupLimits(response);
7670
8174
  const authRequired = field(response, "auth_required");
@@ -7724,6 +8228,7 @@ var NativeAdapter = class _NativeAdapter {
7724
8228
  if (!hasFlowControlCredit) this.pendingControlRequests += 1;
7725
8229
  this.pending.set(requestId, {
7726
8230
  ...command.compactClaimMode == null ? {} : { compactClaimMode: command.compactClaimMode },
8231
+ ...command.compactResponseItems == null ? {} : { compactResponseItems: command.compactResponseItems },
7727
8232
  hasFlowControlCredit,
7728
8233
  indefinite: timeoutMs == null,
7729
8234
  laneId,
@@ -7855,10 +8360,10 @@ function executeCommandArgs(executor, args) {
7855
8360
  }
7856
8361
 
7857
8362
  // src/reconnecting-executor.ts
7858
- var import_node_buffer28 = require("buffer");
8363
+ var import_node_buffer33 = require("buffer");
7859
8364
 
7860
8365
  // src/command-retry-policy.ts
7861
- var import_node_buffer27 = require("buffer");
8366
+ var import_node_buffer32 = require("buffer");
7862
8367
  function isCasMutation(args) {
7863
8368
  const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
7864
8369
  const name = commandName2(args[offset]);
@@ -7872,8 +8377,8 @@ function isCasMutation(args) {
7872
8377
  }
7873
8378
  function commandName2(value) {
7874
8379
  if (typeof value === "string") return value.toUpperCase();
7875
- if (import_node_buffer27.Buffer.isBuffer(value) || value instanceof Uint8Array) {
7876
- return import_node_buffer27.Buffer.from(value).toString("utf8").toUpperCase();
8380
+ if (import_node_buffer32.Buffer.isBuffer(value) || value instanceof Uint8Array) {
8381
+ return import_node_buffer32.Buffer.from(value).toString("utf8").toUpperCase();
7877
8382
  }
7878
8383
  return void 0;
7879
8384
  }
@@ -8085,19 +8590,91 @@ function normalizeNonNegativeInteger2(value, fallback) {
8085
8590
  }
8086
8591
 
8087
8592
  // src/topology.ts
8088
- var import_node_buffer30 = require("buffer");
8593
+ var import_node_buffer36 = require("buffer");
8089
8594
 
8090
8595
  // src/topology-routing.ts
8091
- var import_node_buffer29 = require("buffer");
8596
+ var import_node_buffer35 = require("buffer");
8597
+
8598
+ // src/flow-partition-route-cache.ts
8599
+ var import_node_buffer34 = require("buffer");
8092
8600
  var import_node_crypto = require("crypto");
8093
- var FLOW_PARTITION_ROUTE_CACHE_MAX = 1024;
8094
- var flowPartitionRouteCache = /* @__PURE__ */ new Map();
8601
+ var AUTO_PREFIX = import_node_buffer34.Buffer.from("__flow_auto__:", "ascii");
8602
+ var MAX_CACHEABLE_PARTITION_BYTES = 4 * 1024;
8603
+ var MAX_CACHE_BYTES = 1 * 1024 * 1024;
8604
+ var MAX_CACHE_ENTRIES = 1024;
8605
+ var CACHE_ENTRY_OVERHEAD_BYTES = 96;
8606
+ var routeCache = /* @__PURE__ */ new Map();
8607
+ var cacheBytes = 0;
8608
+ var cacheHits = 0;
8609
+ var cacheMisses = 0;
8610
+ function flowLogicalPartitionRoutingKey(value) {
8611
+ if (typeof value !== "string" && !import_node_buffer34.Buffer.isBuffer(value)) return void 0;
8612
+ const autoBucket = flowAutoBucket(value);
8613
+ if (autoBucket != null) return `{fa:${autoBucket}}`;
8614
+ const bytes2 = import_node_buffer34.Buffer.isBuffer(value) ? value : import_node_buffer34.Buffer.from(value);
8615
+ if (bytes2.byteLength > MAX_CACHEABLE_PARTITION_BYTES) return hashRoute(bytes2);
8616
+ const cacheKey = bytes2.toString("base64");
8617
+ const cached = routeCache.get(cacheKey);
8618
+ if (cached != null) {
8619
+ cacheHits += 1;
8620
+ routeCache.delete(cacheKey);
8621
+ routeCache.set(cacheKey, cached);
8622
+ return cached.routeKey;
8623
+ }
8624
+ cacheMisses += 1;
8625
+ const routeKey = hashRoute(bytes2);
8626
+ const entryBytes = estimatedEntryBytes(cacheKey, routeKey);
8627
+ while (routeCache.size >= MAX_CACHE_ENTRIES || routeCache.size > 0 && cacheBytes + entryBytes > MAX_CACHE_BYTES) {
8628
+ evictOldest();
8629
+ }
8630
+ if (entryBytes <= MAX_CACHE_BYTES) {
8631
+ routeCache.set(cacheKey, { bytes: entryBytes, routeKey });
8632
+ cacheBytes += entryBytes;
8633
+ }
8634
+ return routeKey;
8635
+ }
8636
+ function flowAutoBucket(value) {
8637
+ if (typeof value === "string") {
8638
+ const match = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(value);
8639
+ if (match?.[1] == null) return void 0;
8640
+ const bucket2 = Number(match[1]);
8641
+ return bucket2 < 256 ? bucket2 : void 0;
8642
+ }
8643
+ const digitCount = value.byteLength - AUTO_PREFIX.byteLength;
8644
+ if (digitCount < 1 || digitCount > 3) return void 0;
8645
+ for (let index = 0; index < AUTO_PREFIX.byteLength; index += 1) {
8646
+ if (value[index] !== AUTO_PREFIX[index]) return void 0;
8647
+ }
8648
+ if (digitCount > 1 && value[AUTO_PREFIX.byteLength] === 48) return void 0;
8649
+ let bucket = 0;
8650
+ for (let index = AUTO_PREFIX.byteLength; index < value.byteLength; index += 1) {
8651
+ const digit = value[index];
8652
+ if (digit == null || digit < 48 || digit > 57) return void 0;
8653
+ bucket = bucket * 10 + digit - 48;
8654
+ }
8655
+ return bucket < 256 ? bucket : void 0;
8656
+ }
8657
+ function hashRoute(value) {
8658
+ const digest = (0, import_node_crypto.createHash)("sha256").update(value).digest("base64url");
8659
+ return `{f:${digest}}`;
8660
+ }
8661
+ function estimatedEntryBytes(cacheKey, routeKey) {
8662
+ return CACHE_ENTRY_OVERHEAD_BYTES + 2 * (cacheKey.length + routeKey.length);
8663
+ }
8664
+ function evictOldest() {
8665
+ const oldest = routeCache.entries().next().value;
8666
+ if (oldest == null) return;
8667
+ routeCache.delete(oldest[0]);
8668
+ cacheBytes -= oldest[1].bytes;
8669
+ }
8670
+
8671
+ // src/topology-routing.ts
8095
8672
  function routingKeyFromProtocolPayload(name, command) {
8096
8673
  if (command.opcode < 256 || name === "CLUSTER.KEYSLOT" || name === "SHARDS" || name === "ROUTE") {
8097
8674
  return void 0;
8098
8675
  }
8099
8676
  if (isPlainObject3(command.payload)) {
8100
- for (const field2 of [
8677
+ for (const field3 of [
8101
8678
  "key",
8102
8679
  "partition_key",
8103
8680
  "id",
@@ -8107,8 +8684,8 @@ function routingKeyFromProtocolPayload(name, command) {
8107
8684
  "correlation_id",
8108
8685
  "scope"
8109
8686
  ]) {
8110
- const value = getField(command.payload, field2);
8111
- if (typeof value === "string" || import_node_buffer29.Buffer.isBuffer(value)) {
8687
+ const value = getField(command.payload, field3);
8688
+ if (typeof value === "string" || import_node_buffer35.Buffer.isBuffer(value)) {
8112
8689
  return value;
8113
8690
  }
8114
8691
  }
@@ -8142,6 +8719,7 @@ function flowRoutingData(name, args) {
8142
8719
  if (flowScheduleCommands.has(name)) {
8143
8720
  return void 0;
8144
8721
  }
8722
+ if (name === "FLOW.QUERY") return void 0;
8145
8723
  if (flowApprovalIdCommands.has(name)) {
8146
8724
  const id = flowArgs[0];
8147
8725
  return flowRoutingResult(flowLogicalPartitionRoutingKey(id));
@@ -8155,7 +8733,7 @@ function flowRoutingData(name, args) {
8155
8733
  if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
8156
8734
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
8157
8735
  }
8158
- if (import_node_buffer29.Buffer.isBuffer(partition)) {
8736
+ if (import_node_buffer35.Buffer.isBuffer(partition)) {
8159
8737
  const text3 = partition.toString("utf8").toUpperCase();
8160
8738
  if (text3 !== "AUTO" && text3 !== "MIXED") {
8161
8739
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
@@ -8246,46 +8824,17 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
8246
8824
  return { handled: false };
8247
8825
  }
8248
8826
  function isRoutingKey(value) {
8249
- return typeof value === "string" || import_node_buffer29.Buffer.isBuffer(value);
8250
- }
8251
- function flowLogicalPartitionRoutingKey(value) {
8252
- if (typeof value !== "string" && !import_node_buffer29.Buffer.isBuffer(value)) {
8253
- return void 0;
8254
- }
8255
- const bytes2 = import_node_buffer29.Buffer.isBuffer(value) ? value : import_node_buffer29.Buffer.from(value);
8256
- const text3 = bytes2.toString("utf8");
8257
- const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(text3);
8258
- if (autoMatch != null) {
8259
- const bucket = Number(autoMatch[1]);
8260
- if (bucket < 256) {
8261
- return `{fa:${bucket}}`;
8262
- }
8263
- }
8264
- const cacheKey = `${import_node_buffer29.Buffer.isBuffer(value) ? "b" : "s"}:${bytes2.toString("base64")}`;
8265
- const cached = flowPartitionRouteCache.get(cacheKey);
8266
- if (cached != null) {
8267
- flowPartitionRouteCache.delete(cacheKey);
8268
- flowPartitionRouteCache.set(cacheKey, cached);
8269
- return cached;
8270
- }
8271
- const digest = (0, import_node_crypto.createHash)("sha256").update(bytes2).digest("base64url");
8272
- const routeKey = `{f:${digest}}`;
8273
- if (flowPartitionRouteCache.size >= FLOW_PARTITION_ROUTE_CACHE_MAX) {
8274
- const oldest = flowPartitionRouteCache.keys().next().value;
8275
- if (oldest != null) flowPartitionRouteCache.delete(oldest);
8276
- }
8277
- flowPartitionRouteCache.set(cacheKey, routeKey);
8278
- return routeKey;
8827
+ return typeof value === "string" || import_node_buffer35.Buffer.isBuffer(value);
8279
8828
  }
8280
8829
  function flowAutoIdRoutingKey(value) {
8281
- if (typeof value !== "string" && !import_node_buffer29.Buffer.isBuffer(value)) {
8830
+ if (typeof value !== "string" && !import_node_buffer35.Buffer.isBuffer(value)) {
8282
8831
  return void 0;
8283
8832
  }
8284
- const bucket = (import_node_buffer29.Buffer.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
8833
+ const bucket = (import_node_buffer35.Buffer.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
8285
8834
  return `{fa:${bucket}}`;
8286
8835
  }
8287
8836
  function flowClaimLogicalPartitionRoutingKey(value) {
8288
- if (typeof value !== "string" && !import_node_buffer29.Buffer.isBuffer(value)) return void 0;
8837
+ if (typeof value !== "string" && !import_node_buffer35.Buffer.isBuffer(value)) return void 0;
8289
8838
  const selector = commandPart(value);
8290
8839
  if (selector === "AUTO" || selector === "ANY") return void 0;
8291
8840
  if (selector === "GLOBAL") return "{f}";
@@ -8300,7 +8849,7 @@ function singleShardFlowClaimPartitionKey(values) {
8300
8849
  return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
8301
8850
  }
8302
8851
  function singleShardKey(keys) {
8303
- if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !import_node_buffer29.Buffer.isBuffer(key))) {
8852
+ if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !import_node_buffer35.Buffer.isBuffer(key))) {
8304
8853
  return void 0;
8305
8854
  }
8306
8855
  const usable = keys;
@@ -8333,7 +8882,7 @@ function routedKeyGroups(keys, routeKey) {
8333
8882
  const groups = /* @__PURE__ */ new Map();
8334
8883
  for (let index = 0; index < keys.length; index += 1) {
8335
8884
  const key = keys[index];
8336
- if (typeof key !== "string" && !import_node_buffer29.Buffer.isBuffer(key)) return void 0;
8885
+ if (typeof key !== "string" && !import_node_buffer35.Buffer.isBuffer(key)) return void 0;
8337
8886
  const route = routeKey(key);
8338
8887
  const groupKey = `${route.endpointKey}\0${route.laneId}`;
8339
8888
  const group = groups.get(groupKey);
@@ -9105,15 +9654,15 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9105
9654
  this.adapterOptions = {
9106
9655
  ...adapterOptions,
9107
9656
  events: [.../* @__PURE__ */ new Set([...adapterOptions.events ?? [], "TOPOLOGY_CHANGED"])],
9108
- onEvent: (event) => {
9657
+ onEvent: (event2) => {
9109
9658
  try {
9110
- const callback = userOnEvent?.(event);
9659
+ const callback = userOnEvent?.(event2);
9111
9660
  if (callback != null) {
9112
9661
  void Promise.resolve(callback).catch(() => void 0);
9113
9662
  }
9114
9663
  } catch {
9115
9664
  }
9116
- if (!this.closed && nativeEventName(event) === "TOPOLOGY_CHANGED") {
9665
+ if (!this.closed && nativeEventName(event2) === "TOPOLOGY_CHANGED") {
9117
9666
  this.requestTopologyRefresh();
9118
9667
  }
9119
9668
  }
@@ -9422,7 +9971,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9422
9971
  };
9423
9972
 
9424
9973
  // src/response-map-preservation.ts
9425
- var import_node_buffer31 = require("buffer");
9974
+ var import_node_buffer37 = require("buffer");
9426
9975
  function toStringKeyMapPreservingValues(value) {
9427
9976
  if (value == null) return void 0;
9428
9977
  const result = {};
@@ -9432,7 +9981,7 @@ function toStringKeyMapPreservingValues(value) {
9432
9981
  }
9433
9982
  return result;
9434
9983
  }
9435
- if (typeof value === "object" && !Array.isArray(value) && !import_node_buffer31.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9984
+ if (typeof value === "object" && !Array.isArray(value) && !import_node_buffer37.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9436
9985
  for (const [key, item] of Object.entries(value)) {
9437
9986
  setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
9438
9987
  }
@@ -9441,7 +9990,7 @@ function toStringKeyMapPreservingValues(value) {
9441
9990
  return void 0;
9442
9991
  }
9443
9992
  function normalizeMapStructurePreservingBytes(value) {
9444
- if (import_node_buffer31.Buffer.isBuffer(value) || value instanceof Uint8Array) return value;
9993
+ if (import_node_buffer37.Buffer.isBuffer(value) || value instanceof Uint8Array) return value;
9445
9994
  if (value instanceof Map) {
9446
9995
  const result = {};
9447
9996
  for (const [key, item] of value.entries()) {
@@ -9463,7 +10012,7 @@ function normalizeMapStructurePreservingBytes(value) {
9463
10012
  }
9464
10013
 
9465
10014
  // src/native-kv-responses.ts
9466
- var import_node_buffer32 = require("buffer");
10015
+ var import_node_buffer38 = require("buffer");
9467
10016
  function rateLimitResultFromResp(value) {
9468
10017
  if (!Array.isArray(value) || value.length !== 4) {
9469
10018
  throw new TypeError("RATELIMIT.ADD returned an unexpected response");
@@ -9520,13 +10069,13 @@ function fetchOrComputeResultFromResp(value, codec) {
9520
10069
  }
9521
10070
  function decodePayload(codec, value) {
9522
10071
  if (value == null) return null;
9523
- if (import_node_buffer32.Buffer.isBuffer(value)) return codec.decode(value);
9524
- if (value instanceof Uint8Array) return codec.decode(import_node_buffer32.Buffer.from(value));
9525
- if (typeof value === "string") return codec.decode(import_node_buffer32.Buffer.from(value));
10072
+ if (import_node_buffer38.Buffer.isBuffer(value)) return codec.decode(value);
10073
+ if (value instanceof Uint8Array) return codec.decode(import_node_buffer38.Buffer.from(value));
10074
+ if (typeof value === "string") return codec.decode(import_node_buffer38.Buffer.from(value));
9526
10075
  return normalizeRefMeta(value);
9527
10076
  }
9528
10077
  function requiredResponseString(value, context) {
9529
- if (typeof value !== "string" && !import_node_buffer32.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
10078
+ if (typeof value !== "string" && !import_node_buffer38.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9530
10079
  throw new TypeError(`${context} returned an unexpected response`);
9531
10080
  }
9532
10081
  const result = text(value);
@@ -9543,7 +10092,7 @@ function requiredNonNegativeInteger(value, context) {
9543
10092
  return result;
9544
10093
  }
9545
10094
  function responseBytes(value, context) {
9546
- if (typeof value !== "string" && !import_node_buffer32.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
10095
+ if (typeof value !== "string" && !import_node_buffer38.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9547
10096
  throw new TypeError(`${context} returned an unexpected response`);
9548
10097
  }
9549
10098
  return bytes(value);
@@ -9866,17 +10415,6 @@ function finiteNonNegativeInteger(value, fallback) {
9866
10415
  function finiteNonNegativeNumber(value, fallback) {
9867
10416
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, value);
9868
10417
  }
9869
- function appendReadOptions(args, options) {
9870
- append(args, "COUNT", options.count);
9871
- append(args, "PARTITION", options.partitionKey);
9872
- append(args, "FROM_MS", options.fromMs);
9873
- append(args, "TO_MS", options.toMs);
9874
- appendBool(args, "REV", options.rev);
9875
- append(args, "STATE", options.state);
9876
- appendBool(args, "TERMINAL_ONLY", options.terminalOnly);
9877
- appendBool(args, "INCLUDE_COLD", options.includeCold);
9878
- appendBool(args, "CONSISTENT_PROJECTION", options.consistentProjection);
9879
- }
9880
10418
  function appendAttributeQueryOptions(args, options) {
9881
10419
  append(args, "STATE", options.state);
9882
10420
  append(args, "PARTITION", options.partitionKey);
@@ -9930,22 +10468,6 @@ function appendAttributes(args, attributes) {
9930
10468
  args.push("ATTRIBUTE", name, value);
9931
10469
  }
9932
10470
  }
9933
- function appendSearchStateMeta(args, state, stateMeta) {
9934
- const entries = Object.entries(stateMeta ?? {});
9935
- if (entries.length === 0) {
9936
- return;
9937
- }
9938
- if (entries.every(([, value]) => isPlainObject5(value))) {
9939
- for (const [metaState, values] of entries) {
9940
- args.push("STATE_META", metaState, values);
9941
- }
9942
- return;
9943
- }
9944
- if (state == null) {
9945
- throw new Error("search stateMeta filters require state or nested state metadata");
9946
- }
9947
- args.push("STATE_META", state, stateMeta);
9948
- }
9949
10471
  function normalizeAdminResponse(value) {
9950
10472
  return normalizeRefMeta(value);
9951
10473
  }
@@ -10253,7 +10775,7 @@ function groupAutoPartitionItems(items) {
10253
10775
  }
10254
10776
 
10255
10777
  // src/client-values.ts
10256
- var import_node_buffer33 = require("buffer");
10778
+ var import_node_buffer39 = require("buffer");
10257
10779
  async function valueMGetEntries(client, refs, options = {}) {
10258
10780
  const refCount = refs.length;
10259
10781
  if (refCount === 0) {
@@ -10288,12 +10810,12 @@ async function valueMGetEntries(client, refs, options = {}) {
10288
10810
  const item = response[index];
10289
10811
  if (item == null) {
10290
10812
  entries[index] = { found: false };
10291
- } else if (import_node_buffer33.Buffer.isBuffer(item)) {
10813
+ } else if (import_node_buffer39.Buffer.isBuffer(item)) {
10292
10814
  entries[index] = { found: true, value: client.codec.decode(item) };
10293
10815
  } else if (item instanceof Uint8Array) {
10294
- entries[index] = { found: true, value: client.codec.decode(import_node_buffer33.Buffer.from(item)) };
10816
+ entries[index] = { found: true, value: client.codec.decode(import_node_buffer39.Buffer.from(item)) };
10295
10817
  } else if (typeof item === "string") {
10296
- entries[index] = { found: true, value: client.codec.decode(import_node_buffer33.Buffer.from(item)) };
10818
+ entries[index] = { found: true, value: client.codec.decode(import_node_buffer39.Buffer.from(item)) };
10297
10819
  } else {
10298
10820
  entries[index] = { found: true, value: item };
10299
10821
  }
@@ -10302,10 +10824,10 @@ async function valueMGetEntries(client, refs, options = {}) {
10302
10824
  }
10303
10825
 
10304
10826
  // src/auto-batch.ts
10305
- var import_node_buffer35 = require("buffer");
10827
+ var import_node_buffer41 = require("buffer");
10306
10828
 
10307
10829
  // src/auto-batch-ordering.ts
10308
- var import_node_buffer34 = require("buffer");
10830
+ var import_node_buffer40 = require("buffer");
10309
10831
  function autoBatchOrderingPlan(batch) {
10310
10832
  const accesses = /* @__PURE__ */ new Map();
10311
10833
  const fallbackDependencies = [];
@@ -10420,13 +10942,13 @@ function flowManyAutoBatchIds(command, name) {
10420
10942
  return fixedFlowItemIds(
10421
10943
  command,
10422
10944
  mixed ? 4 : 3,
10423
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && import_node_buffer34.Buffer.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
10945
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && import_node_buffer40.Buffer.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
10424
10946
  );
10425
10947
  }
10426
10948
  return fixedFlowItemIds(
10427
10949
  command,
10428
10950
  mixed ? 4 : 3,
10429
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer34.Buffer.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
10951
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer40.Buffer.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
10430
10952
  );
10431
10953
  }
10432
10954
  function createManyAutoBatchIds(command) {
@@ -10439,7 +10961,7 @@ function createManyAutoBatchIds(command) {
10439
10961
  const ids = fixedFlowItemIds(
10440
10962
  command,
10441
10963
  width,
10442
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer34.Buffer.isBuffer(command[itemIndex + width - 1]),
10964
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer40.Buffer.isBuffer(command[itemIndex + width - 1]),
10443
10965
  markerIndex
10444
10966
  );
10445
10967
  if (ids != null) return ids;
@@ -10457,7 +10979,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
10457
10979
  let cursor = markerIndex + 2;
10458
10980
  for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
10459
10981
  const id = command[cursor];
10460
- if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !import_node_buffer34.Buffer.isBuffer(command[cursor + 2])) return void 0;
10982
+ if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !import_node_buffer40.Buffer.isBuffer(command[cursor + 2])) return void 0;
10461
10983
  ids.push(id);
10462
10984
  cursor += 3;
10463
10985
  const afterValues = skipExtendedNamedItems(command, cursor, true);
@@ -10476,7 +10998,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
10476
10998
  for (let index = 0; index < count; index += 1) {
10477
10999
  const name = command[firstItem + index * 2];
10478
11000
  const value = command[firstItem + index * 2 + 1];
10479
- if (!isAutoBatchResourceValue(name) || (encodedValues ? !import_node_buffer34.Buffer.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
11001
+ if (!isAutoBatchResourceValue(name) || (encodedValues ? !import_node_buffer40.Buffer.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
10480
11002
  }
10481
11003
  return firstItem + count * 2;
10482
11004
  }
@@ -10491,7 +11013,7 @@ function runStepsManyAutoBatchIds(command) {
10491
11013
  ids.push(item);
10492
11014
  continue;
10493
11015
  }
10494
- if (typeof item !== "object" || item == null || Array.isArray(item) || import_node_buffer34.Buffer.isBuffer(item)) return void 0;
11016
+ if (typeof item !== "object" || item == null || Array.isArray(item) || import_node_buffer40.Buffer.isBuffer(item)) return void 0;
10495
11017
  const id = item.id;
10496
11018
  if (!isAutoBatchResourceValue(id)) return void 0;
10497
11019
  ids.push(id);
@@ -10532,7 +11054,7 @@ function flowValuePutOwner(command, start) {
10532
11054
  }
10533
11055
  var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
10534
11056
  function isAutoBatchResourceValue(value) {
10535
- return typeof value === "string" || import_node_buffer34.Buffer.isBuffer(value);
11057
+ return typeof value === "string" || import_node_buffer40.Buffer.isBuffer(value);
10536
11058
  }
10537
11059
  function isFencingToken(value) {
10538
11060
  return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
@@ -10541,7 +11063,7 @@ function nonNegativeItemCount(value) {
10541
11063
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
10542
11064
  }
10543
11065
  function autoBatchResourceKey(namespace, value) {
10544
- return `${namespace}:${import_node_buffer34.Buffer.from(value).toString("base64")}`;
11066
+ return `${namespace}:${import_node_buffer40.Buffer.from(value).toString("base64")}`;
10545
11067
  }
10546
11068
  function autoBatchCommandName(command) {
10547
11069
  return commandView(command).name ?? null;
@@ -10917,7 +11439,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10917
11439
  const results = new Array(claimed.length);
10918
11440
  let cursor = 0;
10919
11441
  let failure;
10920
- const run = async () => {
11442
+ const run2 = async () => {
10921
11443
  while (failure == null) {
10922
11444
  const index = cursor;
10923
11445
  cursor += 1;
@@ -10930,7 +11452,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10930
11452
  }
10931
11453
  }
10932
11454
  };
10933
- await Promise.all(Array.from({ length: Math.min(concurrency, claimed.length) }, run));
11455
+ await Promise.all(Array.from({ length: Math.min(concurrency, claimed.length) }, run2));
10934
11456
  if (failure != null) {
10935
11457
  const hydratedItems = [];
10936
11458
  for (let index = 0; index < results.length; index += 1) {
@@ -10950,71 +11472,1039 @@ function claimFailure(error) {
10950
11472
  }
10951
11473
 
10952
11474
  // src/client-flow-support.ts
10953
- var import_node_buffer42 = require("buffer");
11475
+ var import_node_buffer52 = require("buffer");
10954
11476
 
10955
- // src/client-core.ts
10956
- var import_node_buffer40 = require("buffer");
11477
+ // src/flow-query-builder.ts
11478
+ var import_node_buffer43 = require("buffer");
10957
11479
 
10958
- // src/client-core-helpers.ts
10959
- var import_node_buffer36 = require("buffer");
10960
- function bgsaveResponse(response) {
10961
- if ((typeof response === "string" || import_node_buffer36.Buffer.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
10962
- return true;
11480
+ // src/flow-query-metadata.ts
11481
+ var import_node_buffer42 = require("buffer");
11482
+ var MAX_FLOW_QUERY_METADATA_KEY_BYTES = 64;
11483
+ function normalizeStateMeta(value, state) {
11484
+ if (value == null) return {};
11485
+ const entries = objectEntries(value, "stateMeta");
11486
+ if (entries.length === 0) return {};
11487
+ const nested = entries.map(([, item]) => isPlainRecord(item));
11488
+ if (nested.every(Boolean)) {
11489
+ return value;
10963
11490
  }
10964
- return okResponse(response);
10965
- }
10966
- function clientNameResponse(response) {
10967
- return response == null ? null : textResponse(response, "CLIENT GETNAME");
10968
- }
10969
- function fetchOrComputeCompletionToken(options) {
10970
- if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
11491
+ if (nested.some(Boolean)) {
10971
11492
  throw new TypeError(
10972
- "fetch-or-compute completion requires computeToken"
11493
+ "stateMeta must be entirely flat or entirely nested by state"
10973
11494
  );
10974
11495
  }
10975
- if (!import_node_buffer36.Buffer.isBuffer(options.computeToken)) {
10976
- throw new TypeError("fetch-or-compute computeToken must be a Buffer");
11496
+ if (state == null || state === "" || state === "any") {
11497
+ throw new TypeError(
11498
+ "FLOW.QUERY stateMeta filters require state; a concrete state is required"
11499
+ );
10977
11500
  }
10978
- return options.computeToken;
11501
+ return { [state]: value };
10979
11502
  }
10980
- function concatCommandArgs(prefix, suffix) {
10981
- const args = new Array(prefix.length + suffix.length);
10982
- for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
10983
- for (let index = 0; index < suffix.length; index += 1) {
10984
- args[prefix.length + index] = suffix[index];
11503
+ function metadataEntries(value, context) {
11504
+ const entries = objectEntries(value ?? {}, context).map(([rawName, item]) => {
11505
+ const name = rawName.trim();
11506
+ const size = import_node_buffer42.Buffer.byteLength(name, "utf8");
11507
+ if (size === 0 || size > MAX_FLOW_QUERY_METADATA_KEY_BYTES || name.startsWith("__")) {
11508
+ throw new TypeError(`${context} key is invalid or reserved`);
11509
+ }
11510
+ return [name, item];
11511
+ });
11512
+ entries.sort(([left], [right]) => compareUnicodeScalars(left, right));
11513
+ for (let index = 1; index < entries.length; index += 1) {
11514
+ if (entries[index - 1]?.[0] === entries[index]?.[0]) {
11515
+ throw new TypeError(`${context} key is duplicated after normalization`);
11516
+ }
10985
11517
  }
10986
- return args;
11518
+ return entries;
10987
11519
  }
10988
- function unsupportedClientTracking() {
10989
- throw new InvalidCommandError(
10990
- "CLIENT TRACKING is not supported by the FerricStore native protocol; use native event subscriptions"
10991
- );
11520
+ function objectEntries(value, context) {
11521
+ if (!isPlainRecord(value))
11522
+ throw new TypeError(`${context} must be a plain object`);
11523
+ const keys = Reflect.ownKeys(value);
11524
+ if (keys.some((key) => typeof key !== "string")) {
11525
+ throw new TypeError(`${context} keys must be strings`);
11526
+ }
11527
+ return keys.map((key) => [key, value[key]]);
10992
11528
  }
10993
- function unsupportedClientCaching() {
10994
- throw new InvalidCommandError("CLIENT CACHING is not supported by the FerricStore native protocol");
11529
+ function isPlainRecord(value) {
11530
+ if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer42.Buffer.isBuffer(value)) {
11531
+ return false;
11532
+ }
11533
+ const prototype = Object.getPrototypeOf(value);
11534
+ return prototype === null || prototype === Object.prototype;
10995
11535
  }
10996
-
10997
- // src/client-base.ts
10998
- var import_node_buffer38 = require("buffer");
10999
-
11000
- // src/client-executor.ts
11001
- var import_node_buffer37 = require("buffer");
11002
- var ErrorMappingExecutor = class {
11003
- constructor(executor) {
11004
- this.executor = executor;
11536
+ function metadataSelector(root, ...names) {
11537
+ return root + names.map((name) => `['${name.replaceAll("'", "''")}']`).join("");
11538
+ }
11539
+ function compareUnicodeScalars(left, right) {
11540
+ let leftOffset = 0;
11541
+ let rightOffset = 0;
11542
+ while (leftOffset < left.length && rightOffset < right.length) {
11543
+ const leftCodePoint = left.codePointAt(leftOffset);
11544
+ const rightCodePoint = right.codePointAt(rightOffset);
11545
+ if (leftCodePoint == null || rightCodePoint == null) break;
11546
+ if (leftCodePoint !== rightCodePoint)
11547
+ return leftCodePoint < rightCodePoint ? -1 : 1;
11548
+ leftOffset += leftCodePoint > 65535 ? 2 : 1;
11549
+ rightOffset += rightCodePoint > 65535 ? 2 : 1;
11005
11550
  }
11006
- executor;
11007
- async executeCommand(...args) {
11008
- return await this.executeCommandArgs(args);
11551
+ return left.length === right.length ? 0 : leftOffset === left.length ? -1 : 1;
11552
+ }
11553
+
11554
+ // src/flow-query-builder.ts
11555
+ var MAX_FLOW_QUERY_RESULTS = 100;
11556
+ var MAX_FLOW_QUERY_PARTITION_BYTES = 65535;
11557
+ var MAX_FLOW_QUERY_TIME = Number.MAX_SAFE_INTEGER;
11558
+ var MAX_FLOW_QUERY_STATE_BYTES = 64;
11559
+ var FlowCollectionQuery = class {
11560
+ constructor(partitionKey, limit, reverse) {
11561
+ this.limit = limit;
11562
+ this.reverse = reverse;
11563
+ this.params.partition_key = partitionKey;
11009
11564
  }
11010
- async executeCommandArgs(args) {
11011
- try {
11012
- return await executeCommandArgs(this.executor, args);
11013
- } catch (error) {
11014
- throwMapped(error);
11565
+ limit;
11566
+ reverse;
11567
+ params = /* @__PURE__ */ Object.create(null);
11568
+ predicates = ["partition_key = @partition_key"];
11569
+ orderField = "updated_at_ms";
11570
+ equality(selector, parameter, value) {
11571
+ this.params[parameter] = queryParameter(value, parameter);
11572
+ this.predicates.push(`${selector} = @${parameter}`);
11573
+ }
11574
+ window(fromMs, toMs) {
11575
+ if (fromMs == null && toMs == null) return;
11576
+ const lower = fromMs == null ? 0 : boundedTime(fromMs, "fromMs");
11577
+ const upper = toMs == null ? MAX_FLOW_QUERY_TIME : boundedTime(toMs, "toMs");
11578
+ if (lower > upper) throw new TypeError("fromMs must not exceed toMs");
11579
+ this.predicates.push("updated_at_ms BETWEEN @from_ms AND @to_ms");
11580
+ this.params.from_ms = lower;
11581
+ this.params.to_ms = upper;
11582
+ }
11583
+ metadata(root, values) {
11584
+ const entries = metadataEntries(values, root);
11585
+ for (let index = 0; index < entries.length; index += 1) {
11586
+ const entry = entries[index];
11587
+ if (entry == null) throw new TypeError("metadata entries must be dense");
11588
+ this.equality(
11589
+ metadataSelector(root, entry[0]),
11590
+ `${root}_${index}`,
11591
+ entry[1]
11592
+ );
11015
11593
  }
11016
11594
  }
11017
- async executePipeline(commands, options) {
11595
+ stateMetadata(values) {
11596
+ const entries = [];
11597
+ const states = /* @__PURE__ */ new Set();
11598
+ for (const [rawState, metadata] of objectEntries(values, "stateMeta")) {
11599
+ const state = requiredText(rawState, "stateMeta state").trim();
11600
+ const stateBytes = import_node_buffer43.Buffer.byteLength(state, "utf8");
11601
+ if (stateBytes === 0 || stateBytes > MAX_FLOW_QUERY_STATE_BYTES) {
11602
+ throw new TypeError(
11603
+ `stateMeta state names must be 1..${MAX_FLOW_QUERY_STATE_BYTES} bytes`
11604
+ );
11605
+ }
11606
+ if (states.has(state)) {
11607
+ throw new TypeError(
11608
+ "stateMeta state is duplicated after normalization"
11609
+ );
11610
+ }
11611
+ states.add(state);
11612
+ if (!isPlainRecord(metadata))
11613
+ throw new TypeError("stateMeta values must be metadata maps");
11614
+ for (const [name, value] of metadataEntries(metadata, "stateMeta")) {
11615
+ entries.push([state, name, value]);
11616
+ }
11617
+ }
11618
+ entries.sort(
11619
+ ([leftState, leftName], [rightState, rightName]) => compareUnicodeScalars(leftState, rightState) || compareUnicodeScalars(leftName, rightName)
11620
+ );
11621
+ for (let index = 0; index < entries.length; index += 1) {
11622
+ const entry = entries[index];
11623
+ if (entry == null) throw new TypeError("stateMeta entries must be dense");
11624
+ this.equality(
11625
+ metadataSelector("state_meta", entry[0], entry[1]),
11626
+ `state_meta_${index}`,
11627
+ entry[2]
11628
+ );
11629
+ }
11630
+ }
11631
+ build() {
11632
+ if (this.predicates.length > 12) {
11633
+ throw new TypeError("FLOW.QUERY accepts at most 12 predicates");
11634
+ }
11635
+ const direction = this.reverse ? "DESC" : "ASC";
11636
+ const query = `FROM runs WHERE ${this.predicates.join(" AND ")} ORDER BY ${this.orderField} ${direction} LIMIT ${this.limit} RETURN RECORDS`;
11637
+ validateFlowQueryText(query);
11638
+ return { query, params: this.params };
11639
+ }
11640
+ };
11641
+ function buildFlowListQuery(type, options) {
11642
+ const attributeCount = Object.keys(options.attributes ?? {}).length;
11643
+ if (type === "any" && attributeCount === 0) {
11644
+ throw new TypeError(
11645
+ "FLOW.QUERY list requires a concrete flow type or an attribute predicate"
11646
+ );
11647
+ }
11648
+ if (options.terminalOnly !== true && options.state === "any" && attributeCount === 0) {
11649
+ throw new TypeError(
11650
+ "FLOW.QUERY list state any requires an attribute predicate"
11651
+ );
11652
+ }
11653
+ const builder = queryBuilder(options);
11654
+ addType(builder, type);
11655
+ if (options.terminalOnly === true) {
11656
+ addTerminalState(builder, options.state);
11657
+ } else if (options.state == null || options.state === "") {
11658
+ builder.equality("state", "state", "queued");
11659
+ } else if (options.state !== "any") {
11660
+ builder.equality("state", "state", requiredText(options.state, "state"));
11661
+ }
11662
+ builder.metadata("attribute", options.attributes);
11663
+ builder.window(options.fromMs, options.toMs);
11664
+ return builder.build();
11665
+ }
11666
+ function buildFlowSearchQuery(type, options) {
11667
+ const stateMeta = normalizeStateMeta(options.stateMeta, options.state);
11668
+ if (Object.keys(options.attributes ?? {}).length === 0 && Object.keys(stateMeta).length === 0) {
11669
+ throw new TypeError(
11670
+ "FLOW.QUERY search requires an attribute or stateMeta predicate"
11671
+ );
11672
+ }
11673
+ if ((type === "" || type === "any") && Object.keys(stateMeta).length > 0) {
11674
+ throw new TypeError(
11675
+ "FLOW.QUERY stateMeta predicates require a concrete flow type"
11676
+ );
11677
+ }
11678
+ const builder = queryBuilder(options);
11679
+ if (type !== "" && type !== "any")
11680
+ builder.equality("type", "type", requiredText(type, "type"));
11681
+ if (options.terminalOnly === true) {
11682
+ addTerminalState(builder, options.state);
11683
+ } else if (options.state != null && options.state !== "" && options.state !== "any") {
11684
+ builder.equality("state", "state", requiredText(options.state, "state"));
11685
+ }
11686
+ builder.metadata("attribute", options.attributes);
11687
+ builder.stateMetadata(stateMeta);
11688
+ builder.window(options.fromMs, options.toMs);
11689
+ return builder.build();
11690
+ }
11691
+ function buildFlowTerminalQuery(type, options) {
11692
+ if (requiredText(type, "type") === "any") {
11693
+ throw new TypeError("FLOW.QUERY terminals require a concrete flow type");
11694
+ }
11695
+ if (metadataEntries(options.attributes, "attribute").length > 0) {
11696
+ throw new TypeError(
11697
+ "FLOW.QUERY terminals do not support attribute predicates"
11698
+ );
11699
+ }
11700
+ const builder = queryBuilder(options);
11701
+ addType(builder, type);
11702
+ addTerminalState(builder, options.state);
11703
+ builder.window(options.fromMs, options.toMs);
11704
+ return builder.build();
11705
+ }
11706
+ function buildFlowFailureQuery(type, options) {
11707
+ if (options.state != null && options.state !== "" && options.state !== "any" && options.state !== "failed") {
11708
+ throw new TypeError("FLOW failures state must be failed or any");
11709
+ }
11710
+ return buildFlowListQuery(type, {
11711
+ ...options,
11712
+ state: "failed",
11713
+ terminalOnly: false
11714
+ });
11715
+ }
11716
+ function buildFlowLineageQuery(selector, id, options) {
11717
+ if (options.terminalOnly === true) {
11718
+ throw new TypeError("terminalOnly cannot be combined with a lineage query");
11719
+ }
11720
+ if (metadataEntries(options.attributes, "attribute").length > 0) {
11721
+ throw new TypeError(
11722
+ "FLOW.QUERY lineage does not support attribute predicates"
11723
+ );
11724
+ }
11725
+ const builder = queryBuilder(options);
11726
+ builder.equality(selector, "lineage_id", requiredText(id, "lineage id"));
11727
+ if (options.state != null && options.state !== "" && options.state !== "any") {
11728
+ builder.equality("state", "state", requiredText(options.state, "state"));
11729
+ }
11730
+ builder.metadata("attribute", options.attributes);
11731
+ builder.window(options.fromMs, options.toMs);
11732
+ return builder.build();
11733
+ }
11734
+ function buildFlowStuckQuery(type, options) {
11735
+ const concreteType = requiredText(type, "type");
11736
+ if (concreteType === "any") {
11737
+ throw new TypeError("FLOW.QUERY stuck requires a concrete flow type");
11738
+ }
11739
+ const now = options.nowMs == null ? Date.now() : boundedTime(options.nowMs, "nowMs");
11740
+ const older = options.olderThanMs == null ? 0 : boundedTime(options.olderThanMs, "olderThanMs");
11741
+ const cutoff = now - older;
11742
+ if (cutoff < 0) throw new TypeError("olderThanMs must not exceed nowMs");
11743
+ const builder = new FlowCollectionQuery(
11744
+ requiredPartition(options.partitionKey),
11745
+ boundedCount(options.count),
11746
+ false
11747
+ );
11748
+ builder.orderField = "lease_deadline_ms";
11749
+ builder.equality("type", "type", concreteType);
11750
+ builder.equality("state", "state", "running");
11751
+ builder.predicates.push(
11752
+ "lease_deadline_ms BETWEEN @lease_from_ms AND @lease_to_ms"
11753
+ );
11754
+ builder.params.lease_from_ms = 0;
11755
+ builder.params.lease_to_ms = cutoff;
11756
+ return builder.build();
11757
+ }
11758
+ function queryBuilder(options) {
11759
+ if (options.includeCold === true)
11760
+ throw new TypeError("FLOW.QUERY does not expose includeCold");
11761
+ if (options.consistentProjection === true) {
11762
+ throw new TypeError("FLOW.QUERY does not expose consistentProjection");
11763
+ }
11764
+ if (options.rev != null && typeof options.rev !== "boolean") {
11765
+ throw new TypeError("rev must be boolean");
11766
+ }
11767
+ return new FlowCollectionQuery(
11768
+ requiredPartition(options.partitionKey),
11769
+ boundedCount(options.count),
11770
+ options.rev !== false
11771
+ );
11772
+ }
11773
+ function requiredPartition(value) {
11774
+ if (typeof value !== "string") {
11775
+ throw new TypeError(
11776
+ "FLOW.QUERY convenience methods require a partition key"
11777
+ );
11778
+ }
11779
+ const size = import_node_buffer43.Buffer.byteLength(value, "utf8");
11780
+ if (size === 0 || size > MAX_FLOW_QUERY_PARTITION_BYTES) {
11781
+ throw new TypeError(
11782
+ `FLOW.QUERY partition key must be 1..${MAX_FLOW_QUERY_PARTITION_BYTES} bytes`
11783
+ );
11784
+ }
11785
+ return value;
11786
+ }
11787
+ function boundedCount(value) {
11788
+ if (value == null) return MAX_FLOW_QUERY_RESULTS;
11789
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_FLOW_QUERY_RESULTS) {
11790
+ throw new TypeError(
11791
+ `FLOW.QUERY limit must be between 1 and ${MAX_FLOW_QUERY_RESULTS}`
11792
+ );
11793
+ }
11794
+ return value;
11795
+ }
11796
+ function boundedTime(value, name) {
11797
+ if (!Number.isSafeInteger(value) || value < 0 || value > MAX_FLOW_QUERY_TIME) {
11798
+ throw new TypeError(`${name} must be a non-negative safe integer`);
11799
+ }
11800
+ return value;
11801
+ }
11802
+ function addType(builder, type) {
11803
+ const normalized = requiredText(type, "type");
11804
+ if (normalized !== "any") builder.equality("type", "type", normalized);
11805
+ }
11806
+ function addTerminalState(builder, state) {
11807
+ if (state == null || state === "" || state === "any") {
11808
+ builder.predicates.push("state IN (@terminal_0, @terminal_1, @terminal_2)");
11809
+ builder.params.terminal_0 = "completed";
11810
+ builder.params.terminal_1 = "failed";
11811
+ builder.params.terminal_2 = "cancelled";
11812
+ } else if (state === "completed" || state === "failed" || state === "cancelled") {
11813
+ builder.equality("state", "state", state);
11814
+ } else {
11815
+ throw new TypeError(
11816
+ "terminal state must be completed, failed, cancelled, or any"
11817
+ );
11818
+ }
11819
+ }
11820
+ function requiredText(value, context) {
11821
+ if (typeof value !== "string" || value.length === 0) {
11822
+ throw new TypeError(`${context} must be non-empty text`);
11823
+ }
11824
+ return value;
11825
+ }
11826
+ function queryParameter(value, context) {
11827
+ if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" || import_node_buffer43.Buffer.isBuffer(value)) {
11828
+ return value;
11829
+ }
11830
+ throw new TypeError(`${context} must be a scalar FLOW.QUERY parameter`);
11831
+ }
11832
+
11833
+ // src/flow-query-response.ts
11834
+ var import_node_buffer45 = require("buffer");
11835
+
11836
+ // src/flow-query-response-validation.ts
11837
+ var import_node_buffer44 = require("buffer");
11838
+ function requiredMap2(value, context) {
11839
+ if (value instanceof Map) return value;
11840
+ if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer44.Buffer.isBuffer(value) || value instanceof Uint8Array) {
11841
+ throw decodeError(`${context} must be a map`, value);
11842
+ }
11843
+ return value;
11844
+ }
11845
+ function freezeMap(value) {
11846
+ const output = /* @__PURE__ */ Object.create(null);
11847
+ const entries = value instanceof Map ? value.entries() : Object.entries(value);
11848
+ for (const [rawKey, item] of entries) {
11849
+ const key = strictText2(rawKey);
11850
+ if (key == null || Object.hasOwn(output, key)) {
11851
+ throw decodeError(
11852
+ "server response map contains an invalid or duplicate key",
11853
+ value
11854
+ );
11855
+ }
11856
+ output[key] = item;
11857
+ }
11858
+ return Object.freeze(output);
11859
+ }
11860
+ function freezeMetadataMap(value, context) {
11861
+ return normalizeMetadataMap(
11862
+ value,
11863
+ context,
11864
+ { remaining: DEFAULT_MAX_VALUE_ITEMS },
11865
+ /* @__PURE__ */ new Set(),
11866
+ 0
11867
+ );
11868
+ }
11869
+ function normalizeMetadataMap(value, context, budget, ancestors, depth) {
11870
+ enterMetadataContainer(value, context, budget, ancestors, depth);
11871
+ try {
11872
+ const output = /* @__PURE__ */ Object.create(null);
11873
+ const entries = value instanceof Map ? value.entries() : Object.entries(value);
11874
+ for (const [rawKey, item] of entries) {
11875
+ const key = strictText2(rawKey);
11876
+ if (key == null || Object.hasOwn(output, key)) {
11877
+ throw decodeError(`${context} contains an invalid or duplicate key`, value);
11878
+ }
11879
+ output[key] = normalizeMetadataValue(
11880
+ item,
11881
+ `${context}.${key}`,
11882
+ budget,
11883
+ ancestors,
11884
+ depth + 1
11885
+ );
11886
+ }
11887
+ return Object.freeze(output);
11888
+ } finally {
11889
+ ancestors.delete(value);
11890
+ }
11891
+ }
11892
+ function normalizeMetadataValue(value, context, budget, ancestors, depth) {
11893
+ if (typeof value === "string") {
11894
+ if (!value.isWellFormed()) throw decodeError(`${context} contains invalid text`, value);
11895
+ return value;
11896
+ }
11897
+ if (import_node_buffer44.Buffer.isBuffer(value) || value instanceof Uint8Array) {
11898
+ const decoded = strictText2(value);
11899
+ if (decoded == null) throw decodeError(`${context} contains invalid UTF-8`, value);
11900
+ return decoded;
11901
+ }
11902
+ if (value == null || typeof value === "boolean" || typeof value === "number" || typeof value === "bigint") {
11903
+ return value;
11904
+ }
11905
+ if (Array.isArray(value)) {
11906
+ enterMetadataContainer(value, context, budget, ancestors, depth);
11907
+ try {
11908
+ const output = new Array(value.length);
11909
+ for (let index = 0; index < value.length; index += 1) {
11910
+ if (!Object.hasOwn(value, index)) {
11911
+ throw decodeError(`${context} must be a dense array`, value);
11912
+ }
11913
+ output[index] = normalizeMetadataValue(
11914
+ value[index],
11915
+ `${context}[${index}]`,
11916
+ budget,
11917
+ ancestors,
11918
+ depth + 1
11919
+ );
11920
+ }
11921
+ return Object.freeze(output);
11922
+ } finally {
11923
+ ancestors.delete(value);
11924
+ }
11925
+ }
11926
+ if (value instanceof Map) {
11927
+ return normalizeMetadataMap(value, context, budget, ancestors, depth);
11928
+ }
11929
+ if (isPlainObject6(value)) {
11930
+ return normalizeMetadataMap(value, context, budget, ancestors, depth);
11931
+ }
11932
+ throw decodeError(`${context} contains an unsupported value`, value);
11933
+ }
11934
+ function enterMetadataContainer(value, context, budget, ancestors, depth) {
11935
+ if (depth >= DEFAULT_MAX_VALUE_DEPTH) {
11936
+ throw decodeError(`${context} exceeds the maximum metadata depth`, value);
11937
+ }
11938
+ if (ancestors.has(value)) throw decodeError(`${context} contains a cycle`, value);
11939
+ const size = Array.isArray(value) ? value.length : value instanceof Map ? value.size : Object.keys(value).length;
11940
+ if (size > budget.remaining) {
11941
+ throw decodeError(`${context} exceeds the maximum metadata items`, value);
11942
+ }
11943
+ budget.remaining -= size;
11944
+ ancestors.add(value);
11945
+ }
11946
+ function isPlainObject6(value) {
11947
+ const prototype = Object.getPrototypeOf(value);
11948
+ return prototype === Object.prototype || prototype === null;
11949
+ }
11950
+ function requireContract(mapping, name, expected, context) {
11951
+ const actual = requiredText2(mapping, name, context);
11952
+ if (actual !== expected) {
11953
+ throw decodeError(
11954
+ `${context} has unsupported contract ${JSON.stringify(actual)}`,
11955
+ mapping
11956
+ );
11957
+ }
11958
+ }
11959
+ function requiredText2(mapping, name, context) {
11960
+ const value = strictText2(field(mapping, name));
11961
+ if (value == null || value.length === 0) {
11962
+ throw decodeError(`${context} ${name} must be non-empty text`, mapping);
11963
+ }
11964
+ return value;
11965
+ }
11966
+ function optionalText2(mapping, name, context) {
11967
+ const raw = field(mapping, name);
11968
+ if (raw == null) return void 0;
11969
+ const value = strictText2(raw);
11970
+ if (value == null)
11971
+ throw decodeError(`${context} ${name} must be text`, mapping);
11972
+ return value;
11973
+ }
11974
+ function requiredBoundedText2(mapping, name, context, maximumBytes) {
11975
+ const value = requiredText2(mapping, name, context);
11976
+ if (import_node_buffer44.Buffer.byteLength(value, "utf8") > maximumBytes) {
11977
+ throw decodeError(
11978
+ `${context} ${name} exceeds ${maximumBytes} bytes`,
11979
+ mapping
11980
+ );
11981
+ }
11982
+ return value;
11983
+ }
11984
+ function boundedText(value, context, maximumBytes) {
11985
+ const decoded = strictText2(value);
11986
+ if (decoded == null || decoded.length === 0) {
11987
+ throw decodeError(`${context} must be non-empty text`, value);
11988
+ }
11989
+ if (import_node_buffer44.Buffer.byteLength(decoded, "utf8") > maximumBytes) {
11990
+ throw decodeError(`${context} exceeds ${maximumBytes} bytes`, value);
11991
+ }
11992
+ return decoded;
11993
+ }
11994
+ function requiredBoolean(mapping, name, context) {
11995
+ const value = field(mapping, name);
11996
+ if (typeof value !== "boolean") {
11997
+ throw decodeError(`${context} ${name} must be boolean`, mapping);
11998
+ }
11999
+ return value;
12000
+ }
12001
+ function nonNegativeInteger(value, context) {
12002
+ if (typeof value === "bigint") {
12003
+ if (value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER))
12004
+ return Number(value);
12005
+ } else if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
12006
+ return value;
12007
+ }
12008
+ throw decodeError(`${context} must be a non-negative safe integer`, value);
12009
+ }
12010
+ function positiveInteger(value, context) {
12011
+ const parsed = nonNegativeInteger(value, context);
12012
+ if (parsed === 0) throw decodeError(`${context} must be positive`, value);
12013
+ return parsed;
12014
+ }
12015
+ function boundedInteger(value, maximum, context) {
12016
+ let parsed;
12017
+ if (typeof value === "bigint") {
12018
+ parsed = value;
12019
+ } else if (typeof value === "number" && Number.isSafeInteger(value)) {
12020
+ parsed = BigInt(value);
12021
+ } else {
12022
+ throw decodeError(
12023
+ `${context} must be a lossless non-negative integer`,
12024
+ value
12025
+ );
12026
+ }
12027
+ if (parsed < 0n || parsed > maximum) {
12028
+ throw decodeError(
12029
+ `${context} is outside its supported integer range`,
12030
+ value
12031
+ );
12032
+ }
12033
+ return parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : parsed;
12034
+ }
12035
+ function positiveBoundedInteger(value, maximum, context) {
12036
+ const parsed = boundedInteger(value, maximum, context);
12037
+ if (parsed === 0) throw decodeError(`${context} must be positive`, value);
12038
+ return parsed;
12039
+ }
12040
+ function hasKey(mapping, name) {
12041
+ if (!(mapping instanceof Map)) return Object.hasOwn(mapping, name);
12042
+ if (mapping.has(name)) return true;
12043
+ const binaryName = import_node_buffer44.Buffer.from(name);
12044
+ for (const key of mapping.keys()) {
12045
+ if (import_node_buffer44.Buffer.isBuffer(key) && key.equals(binaryName)) return true;
12046
+ if (key instanceof Uint8Array && import_node_buffer44.Buffer.from(key).equals(binaryName))
12047
+ return true;
12048
+ }
12049
+ return false;
12050
+ }
12051
+ function decodeError(message, raw) {
12052
+ return new FerricStoreError(`invalid server response: ${message}`, { raw });
12053
+ }
12054
+ function strictText2(value) {
12055
+ if (typeof value === "string")
12056
+ return value.isWellFormed() ? value : void 0;
12057
+ if (import_node_buffer44.Buffer.isBuffer(value) || value instanceof Uint8Array) {
12058
+ try {
12059
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
12060
+ } catch {
12061
+ return void 0;
12062
+ }
12063
+ }
12064
+ return void 0;
12065
+ }
12066
+
12067
+ // src/flow-query-types.ts
12068
+ var FlowQueryError = class extends FerricStoreError {
12069
+ code;
12070
+ detail;
12071
+ hint;
12072
+ position;
12073
+ context;
12074
+ constructor(options) {
12075
+ super(options.message, {
12076
+ cause: options.cause,
12077
+ raw: options.raw,
12078
+ retryable: options.retryable,
12079
+ safeToRetry: options.safeToRetry,
12080
+ retryAfterMs: options.retryAfterMs
12081
+ });
12082
+ this.code = options.code;
12083
+ this.detail = options.detail;
12084
+ this.hint = options.hint;
12085
+ this.position = options.position;
12086
+ this.context = options.context;
12087
+ }
12088
+ };
12089
+
12090
+ // src/flow-query-response.ts
12091
+ var FLOW_QUERY_RESULT_CONTRACT = "ferric.flow.query.result/v1";
12092
+ var FLOW_EXPLAIN_CONTRACT = "ferric.flow.explain/v1";
12093
+ var FLOW_QUERY_INDEXES_CONTRACT = "ferric.flow.query.indexes/v1";
12094
+ var USAGE_FIELDS2 = [
12095
+ ["range_seeks", "rangeSeeks"],
12096
+ ["range_pages", "rangePages"],
12097
+ ["scanned_entries", "scannedEntries"],
12098
+ ["scanned_bytes", "scannedBytes"],
12099
+ ["hydrated_records", "hydratedRecords"],
12100
+ ["residual_checks", "residualChecks"],
12101
+ ["duplicate_entries", "duplicateEntries"],
12102
+ ["result_records", "resultRecords"],
12103
+ ["response_bytes", "responseBytes"],
12104
+ ["memory_high_water_bytes", "memoryHighWaterBytes"],
12105
+ ["wall_time_us", "wallTimeUs"]
12106
+ ];
12107
+ var MAX_SIGNED_64 = (1n << 63n) - 1n;
12108
+ var MAX_UNSIGNED_64 = (1n << 64n) - 1n;
12109
+ function decodeFlowQueryResult(value) {
12110
+ const result = decodeFlowQueryResponse(value, (mapping) => freezeMap(mapping));
12111
+ if (result.kind === "records") {
12112
+ return Object.freeze({
12113
+ kind: "records",
12114
+ version: FLOW_QUERY_RESULT_CONTRACT,
12115
+ records: Object.freeze(result.records),
12116
+ page: result.page,
12117
+ quality: result.quality,
12118
+ usage: result.usage,
12119
+ raw: result.raw
12120
+ });
12121
+ }
12122
+ return Object.freeze({
12123
+ kind: "count",
12124
+ version: FLOW_QUERY_RESULT_CONTRACT,
12125
+ count: result.count,
12126
+ quality: result.quality,
12127
+ usage: result.usage,
12128
+ raw: result.raw
12129
+ });
12130
+ }
12131
+ function decodeFlowQueryRecords(value, decodeRecord) {
12132
+ const result = decodeFlowQueryResponse(
12133
+ value,
12134
+ (mapping, index) => decodeRecord(mapping instanceof Map ? freezeMap(mapping) : mapping, index)
12135
+ );
12136
+ if (result.kind === "count") {
12137
+ throw new FerricStoreError("Flow record convenience query returned a count result", {
12138
+ raw: result.raw
12139
+ });
12140
+ }
12141
+ return result.records;
12142
+ }
12143
+ function decodeFlowQueryResponse(value, decodeRecord) {
12144
+ const mapping = requiredMap2(value, "FLOW.QUERY result");
12145
+ requireContract(mapping, "version", FLOW_QUERY_RESULT_CONTRACT, "FLOW.QUERY result");
12146
+ const quality = decodeQuality(field(mapping, "quality"));
12147
+ const usage = decodeUsage(field(mapping, "usage"));
12148
+ const hasRecords = hasKey(mapping, "records");
12149
+ const hasCount = hasKey(mapping, "result");
12150
+ if (hasRecords === hasCount) {
12151
+ throw decodeError("FLOW.QUERY result must contain exactly one records or count shape", value);
12152
+ }
12153
+ const raw = freezeMap(mapping);
12154
+ if (hasRecords) {
12155
+ const rawRecords = field(mapping, "records");
12156
+ if (!Array.isArray(rawRecords) || rawRecords.length > 100) {
12157
+ throw decodeError("FLOW.QUERY records must be an array of at most 100 maps", value);
12158
+ }
12159
+ const records = new Array(rawRecords.length);
12160
+ for (let index = 0; index < rawRecords.length; index += 1) {
12161
+ if (!Object.hasOwn(rawRecords, index)) {
12162
+ throw decodeError("FLOW.QUERY records must be a dense array", value);
12163
+ }
12164
+ records[index] = decodeRecord(
12165
+ requiredMap2(rawRecords[index], `FLOW.QUERY record ${index}`),
12166
+ index
12167
+ );
12168
+ }
12169
+ if (usage.resultRecords !== records.length) {
12170
+ throw decodeError("FLOW.QUERY usage result_records does not match records", value);
12171
+ }
12172
+ return {
12173
+ kind: "records",
12174
+ records,
12175
+ page: decodePage(field(mapping, "page")),
12176
+ quality,
12177
+ usage,
12178
+ raw
12179
+ };
12180
+ }
12181
+ if (hasKey(mapping, "page")) {
12182
+ throw decodeError("FLOW.QUERY count result contains an unexpected page", value);
12183
+ }
12184
+ const countResult = requiredMap2(field(mapping, "result"), "FLOW.QUERY count result");
12185
+ if (requiredText2(countResult, "kind", "FLOW.QUERY count result") !== "count") {
12186
+ throw decodeError("FLOW.QUERY count result kind must be count", value);
12187
+ }
12188
+ const count = boundedInteger(
12189
+ field(countResult, "value"),
12190
+ MAX_SIGNED_64,
12191
+ "FLOW.QUERY count value"
12192
+ );
12193
+ if (usage.resultRecords !== 1) {
12194
+ throw decodeError("FLOW.QUERY count usage result_records must be 1", value);
12195
+ }
12196
+ return {
12197
+ kind: "count",
12198
+ count,
12199
+ quality,
12200
+ usage,
12201
+ raw
12202
+ };
12203
+ }
12204
+ function decodeFlowExplainResult(value) {
12205
+ const mapping = requiredMap2(value, "FLOW.QUERY explain");
12206
+ requireContract(mapping, "version", FLOW_EXPLAIN_CONTRACT, "FLOW.QUERY explain");
12207
+ const queryFingerprint = requiredText2(mapping, "query_fingerprint", "FLOW.QUERY explain");
12208
+ if (!/^[0-9a-f]{64}$/iu.test(queryFingerprint)) {
12209
+ throw decodeError("FLOW.QUERY explain query_fingerprint is invalid", value);
12210
+ }
12211
+ const status = requiredText2(mapping, "status", "FLOW.QUERY explain");
12212
+ if (status !== "planned" && status !== "rejected" && status !== "executed") {
12213
+ throw decodeError(`FLOW.QUERY explain status ${JSON.stringify(status)} is unsupported`, value);
12214
+ }
12215
+ const plan = freezeMetadataMap(
12216
+ requiredMap2(field(mapping, "plan"), "FLOW.QUERY explain plan"),
12217
+ "FLOW.QUERY explain plan"
12218
+ );
12219
+ const estimate = freezeMetadataMap(
12220
+ requiredMap2(field(mapping, "estimate"), "FLOW.QUERY explain estimate"),
12221
+ "FLOW.QUERY explain estimate"
12222
+ );
12223
+ const bounds = freezeMetadataMap(
12224
+ requiredMap2(field(mapping, "bounds"), "FLOW.QUERY explain bounds"),
12225
+ "FLOW.QUERY explain bounds"
12226
+ );
12227
+ const actualValue = field(mapping, "actual");
12228
+ let actual;
12229
+ if (status === "executed") {
12230
+ if (actualValue == null) {
12231
+ throw decodeError("FLOW.QUERY executed explain is missing actual usage", value);
12232
+ }
12233
+ actual = decodeUsage(actualValue);
12234
+ } else if (actualValue != null) {
12235
+ throw decodeError("FLOW.QUERY non-executed explain contains actual usage", value);
12236
+ }
12237
+ const diagnosticValue = field(mapping, "diagnostic");
12238
+ let diagnostic;
12239
+ if (status === "rejected") {
12240
+ diagnostic = tryDecodeFlowQueryError(diagnosticValue);
12241
+ if (diagnostic == null) {
12242
+ throw decodeError("FLOW.QUERY rejected explain has an invalid diagnostic", value);
12243
+ }
12244
+ } else if (diagnosticValue != null) {
12245
+ throw decodeError("FLOW.QUERY non-rejected explain contains a diagnostic", value);
12246
+ }
12247
+ return Object.freeze({
12248
+ version: FLOW_EXPLAIN_CONTRACT,
12249
+ queryFingerprint,
12250
+ status,
12251
+ plan,
12252
+ estimate,
12253
+ bounds,
12254
+ actual,
12255
+ diagnostic,
12256
+ raw: freezeMap(mapping)
12257
+ });
12258
+ }
12259
+ function tryDecodeFlowQueryError(value, cause) {
12260
+ try {
12261
+ const mapping = requiredMap2(value, "FLOW.QUERY diagnostic");
12262
+ const contextValue = field(mapping, "context");
12263
+ const context = contextValue == null ? void 0 : freezeMetadataMap(
12264
+ requiredMap2(contextValue, "FLOW.QUERY diagnostic context"),
12265
+ "FLOW.QUERY diagnostic context"
12266
+ );
12267
+ const position = decodePosition(field(mapping, "position"));
12268
+ return new FlowQueryError({
12269
+ code: requiredText2(mapping, "code", "FLOW.QUERY diagnostic"),
12270
+ message: requiredText2(mapping, "message", "FLOW.QUERY diagnostic"),
12271
+ detail: optionalText2(mapping, "detail", "FLOW.QUERY diagnostic"),
12272
+ hint: optionalText2(mapping, "hint", "FLOW.QUERY diagnostic"),
12273
+ retryable: requiredBoolean(mapping, "retryable", "FLOW.QUERY diagnostic"),
12274
+ safeToRetry: requiredBoolean(mapping, "safe_to_retry", "FLOW.QUERY diagnostic"),
12275
+ retryAfterMs: nonNegativeInteger(
12276
+ field(mapping, "retry_after_ms"),
12277
+ "FLOW.QUERY diagnostic retry_after_ms"
12278
+ ),
12279
+ position,
12280
+ context,
12281
+ raw: value,
12282
+ cause
12283
+ });
12284
+ } catch (error) {
12285
+ if (error instanceof FerricStoreError) return void 0;
12286
+ throw error;
12287
+ }
12288
+ }
12289
+ function decodeFlowQueryIndexStatus(value) {
12290
+ const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES");
12291
+ requireContract(
12292
+ mapping,
12293
+ "contract_version",
12294
+ FLOW_QUERY_INDEXES_CONTRACT,
12295
+ "FLOW.QUERY.INDEXES"
12296
+ );
12297
+ const registry = requiredMap2(field(mapping, "registry"), "FLOW.QUERY.INDEXES registry");
12298
+ const services = freezeMetadataMap(
12299
+ requiredMap2(field(mapping, "services"), "FLOW.QUERY.INDEXES services"),
12300
+ "FLOW.QUERY.INDEXES services"
12301
+ );
12302
+ const rawIndexes = field(mapping, "indexes");
12303
+ if (!Array.isArray(rawIndexes) || rawIndexes.length > 32) {
12304
+ throw decodeError("FLOW.QUERY.INDEXES indexes must contain at most 32 entries", value);
12305
+ }
12306
+ const indexes = new Array(rawIndexes.length);
12307
+ for (let index = 0; index < rawIndexes.length; index += 1) {
12308
+ if (!Object.hasOwn(rawIndexes, index)) {
12309
+ throw decodeError("FLOW.QUERY.INDEXES indexes must be a dense array", value);
12310
+ }
12311
+ indexes[index] = decodeIndex(rawIndexes[index], index);
12312
+ }
12313
+ return Object.freeze({
12314
+ contractVersion: FLOW_QUERY_INDEXES_CONTRACT,
12315
+ observedAtMs: nonNegativeInteger(
12316
+ field(mapping, "observed_at_ms"),
12317
+ "FLOW.QUERY.INDEXES observed_at_ms"
12318
+ ),
12319
+ statisticsMaxAgeMs: nonNegativeInteger(
12320
+ field(mapping, "statistics_max_age_ms"),
12321
+ "FLOW.QUERY.INDEXES statistics_max_age_ms"
12322
+ ),
12323
+ registry: Object.freeze({
12324
+ epoch: boundedInteger(
12325
+ field(registry, "epoch"),
12326
+ MAX_UNSIGNED_64,
12327
+ "FLOW.QUERY.INDEXES epoch"
12328
+ ),
12329
+ catalogVersion: positiveBoundedInteger(
12330
+ field(registry, "catalog_version"),
12331
+ MAX_UNSIGNED_64,
12332
+ "FLOW.QUERY.INDEXES catalog_version"
12333
+ )
12334
+ }),
12335
+ services,
12336
+ indexes: Object.freeze(indexes),
12337
+ raw: freezeMap(mapping)
12338
+ });
12339
+ }
12340
+ function decodeIndex(value, index) {
12341
+ const mapping = requiredMap2(value, `FLOW.QUERY.INDEXES index ${index}`);
12342
+ return Object.freeze({
12343
+ id: requiredText2(mapping, "id", "FLOW.QUERY.INDEXES index"),
12344
+ version: positiveBoundedInteger(
12345
+ field(mapping, "version"),
12346
+ MAX_UNSIGNED_64,
12347
+ "FLOW.QUERY.INDEXES index version"
12348
+ ),
12349
+ buildId: requiredText2(mapping, "build_id", "FLOW.QUERY.INDEXES index"),
12350
+ state: requiredText2(mapping, "state", "FLOW.QUERY.INDEXES index"),
12351
+ queryable: requiredBoolean(mapping, "queryable", "FLOW.QUERY.INDEXES index"),
12352
+ coveringFields: decodeCoveringFields(mapping),
12353
+ format: decodeIndexFormat(mapping),
12354
+ raw: freezeMap(mapping)
12355
+ });
12356
+ }
12357
+ function decodeCoveringFields(mapping) {
12358
+ const raw = field(mapping, "covering_fields");
12359
+ if (!Array.isArray(raw) || raw.length > 32) {
12360
+ throw decodeError(
12361
+ "FLOW.QUERY.INDEXES index covering_fields must contain at most 32 entries",
12362
+ raw
12363
+ );
12364
+ }
12365
+ const fields = new Array(raw.length);
12366
+ const seen = /* @__PURE__ */ new Set();
12367
+ for (let index = 0; index < raw.length; index += 1) {
12368
+ if (!Object.hasOwn(raw, index)) {
12369
+ throw decodeError("FLOW.QUERY.INDEXES index covering_fields must be dense", raw);
12370
+ }
12371
+ const value = boundedText(
12372
+ raw[index],
12373
+ `FLOW.QUERY.INDEXES index covering_fields entry ${index}`,
12374
+ 512
12375
+ );
12376
+ if (seen.has(value)) {
12377
+ throw decodeError("FLOW.QUERY.INDEXES index covering_fields contains duplicates", raw);
12378
+ }
12379
+ seen.add(value);
12380
+ fields[index] = value;
12381
+ }
12382
+ return Object.freeze(fields);
12383
+ }
12384
+ function decodeIndexFormat(mapping) {
12385
+ const raw = requiredMap2(field(mapping, "format"), "FLOW.QUERY.INDEXES index format");
12386
+ if (!hasKey(raw, "counter")) {
12387
+ throw decodeError("FLOW.QUERY.INDEXES index format counter is missing", raw);
12388
+ }
12389
+ const counterValue = field(raw, "counter");
12390
+ const counter = counterValue === null ? void 0 : boundedText(counterValue, "FLOW.QUERY.INDEXES index format counter", 128);
12391
+ return Object.freeze({
12392
+ queryRow: requiredBoundedText2(raw, "query_row", "FLOW.QUERY.INDEXES index format", 128),
12393
+ key: requiredBoundedText2(raw, "key", "FLOW.QUERY.INDEXES index format", 128),
12394
+ entry: requiredBoundedText2(raw, "entry", "FLOW.QUERY.INDEXES index format", 128),
12395
+ reverse: requiredBoundedText2(raw, "reverse", "FLOW.QUERY.INDEXES index format", 128),
12396
+ counter,
12397
+ raw: freezeMap(raw)
12398
+ });
12399
+ }
12400
+ function decodeQuality(value) {
12401
+ const mapping = requiredMap2(value, "FLOW.QUERY quality");
12402
+ return Object.freeze({
12403
+ exactness: requiredBoundedText2(mapping, "exactness", "FLOW.QUERY quality", 64),
12404
+ freshness: requiredBoundedText2(mapping, "freshness", "FLOW.QUERY quality", 64),
12405
+ coverage: requiredBoundedText2(mapping, "coverage", "FLOW.QUERY quality", 64),
12406
+ pagination: requiredBoundedText2(mapping, "pagination", "FLOW.QUERY quality", 64)
12407
+ });
12408
+ }
12409
+ function decodeUsage(value) {
12410
+ const mapping = requiredMap2(value, "FLOW.QUERY usage");
12411
+ const usage = /* @__PURE__ */ Object.create(null);
12412
+ for (const [wireName, property] of USAGE_FIELDS2) {
12413
+ usage[property] = nonNegativeInteger(
12414
+ field(mapping, wireName),
12415
+ `FLOW.QUERY usage ${wireName}`
12416
+ );
12417
+ }
12418
+ return Object.freeze(usage);
12419
+ }
12420
+ function decodePage(value) {
12421
+ const mapping = requiredMap2(value, "FLOW.QUERY page");
12422
+ const hasMore = requiredBoolean(mapping, "has_more", "FLOW.QUERY page");
12423
+ const cursor = optionalText2(mapping, "cursor", "FLOW.QUERY page");
12424
+ if (cursor != null && (!cursor.startsWith("fqc1_") || import_node_buffer45.Buffer.byteLength(cursor) > 4096)) {
12425
+ throw decodeError("FLOW.QUERY page cursor is invalid", value);
12426
+ }
12427
+ if (hasMore !== (cursor != null)) {
12428
+ throw decodeError("FLOW.QUERY page has_more and cursor are inconsistent", value);
12429
+ }
12430
+ return Object.freeze({ hasMore, ...cursor == null ? {} : { cursor } });
12431
+ }
12432
+ function decodePosition(value) {
12433
+ if (value == null) return void 0;
12434
+ const mapping = requiredMap2(value, "FLOW.QUERY diagnostic position");
12435
+ return Object.freeze({
12436
+ byte: positiveInteger(field(mapping, "byte"), "FLOW.QUERY diagnostic position byte"),
12437
+ line: positiveInteger(field(mapping, "line"), "FLOW.QUERY diagnostic position line"),
12438
+ column: positiveInteger(
12439
+ field(mapping, "column"),
12440
+ "FLOW.QUERY diagnostic position column"
12441
+ )
12442
+ });
12443
+ }
12444
+
12445
+ // src/client-core.ts
12446
+ var import_node_buffer50 = require("buffer");
12447
+
12448
+ // src/client-core-helpers.ts
12449
+ var import_node_buffer46 = require("buffer");
12450
+ function bgsaveResponse(response) {
12451
+ if ((typeof response === "string" || import_node_buffer46.Buffer.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
12452
+ return true;
12453
+ }
12454
+ return okResponse(response);
12455
+ }
12456
+ function clientNameResponse(response) {
12457
+ return response == null ? null : textResponse(response, "CLIENT GETNAME");
12458
+ }
12459
+ function fetchOrComputeCompletionToken(options) {
12460
+ if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
12461
+ throw new TypeError(
12462
+ "fetch-or-compute completion requires computeToken"
12463
+ );
12464
+ }
12465
+ if (!import_node_buffer46.Buffer.isBuffer(options.computeToken)) {
12466
+ throw new TypeError("fetch-or-compute computeToken must be a Buffer");
12467
+ }
12468
+ return options.computeToken;
12469
+ }
12470
+ function concatCommandArgs(prefix, suffix) {
12471
+ const args = new Array(prefix.length + suffix.length);
12472
+ for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
12473
+ for (let index = 0; index < suffix.length; index += 1) {
12474
+ args[prefix.length + index] = suffix[index];
12475
+ }
12476
+ return args;
12477
+ }
12478
+ function unsupportedClientTracking() {
12479
+ throw new InvalidCommandError(
12480
+ "CLIENT TRACKING is not supported by the FerricStore native protocol; use native event subscriptions"
12481
+ );
12482
+ }
12483
+ function unsupportedClientCaching() {
12484
+ throw new InvalidCommandError("CLIENT CACHING is not supported by the FerricStore native protocol");
12485
+ }
12486
+
12487
+ // src/client-base.ts
12488
+ var import_node_buffer48 = require("buffer");
12489
+
12490
+ // src/client-executor.ts
12491
+ var import_node_buffer47 = require("buffer");
12492
+ var ErrorMappingExecutor = class {
12493
+ constructor(executor) {
12494
+ this.executor = executor;
12495
+ }
12496
+ executor;
12497
+ async executeCommand(...args) {
12498
+ return await this.executeCommandArgs(args);
12499
+ }
12500
+ async executeCommandArgs(args) {
12501
+ try {
12502
+ return await executeCommandArgs(this.executor, args);
12503
+ } catch (error) {
12504
+ throwMapped(error);
12505
+ }
12506
+ }
12507
+ async executePipeline(commands, options) {
11018
12508
  let results;
11019
12509
  try {
11020
12510
  if (this.executor.executePipeline != null) {
@@ -11332,14 +12822,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
11332
12822
  };
11333
12823
 
11334
12824
  // src/store-utilities.ts
11335
- var import_node_buffer39 = require("buffer");
12825
+ var import_node_buffer49 = require("buffer");
11336
12826
  function encode(codec, value) {
11337
12827
  return codec.encode(value);
11338
12828
  }
11339
12829
  function decode(codec, value) {
11340
12830
  if (value == null) return null;
11341
- if (import_node_buffer39.Buffer.isBuffer(value)) return codec.decode(value);
11342
- if (value instanceof Uint8Array) return codec.decode(import_node_buffer39.Buffer.from(value));
12831
+ if (import_node_buffer49.Buffer.isBuffer(value)) return codec.decode(value);
12832
+ if (value instanceof Uint8Array) return codec.decode(import_node_buffer49.Buffer.from(value));
11343
12833
  return value;
11344
12834
  }
11345
12835
  function number(value) {
@@ -11929,15 +13419,15 @@ function compressionOptions(options) {
11929
13419
  // src/store-decoders.ts
11930
13420
  function decodeHashRecord(codec, value) {
11931
13421
  const result = {};
11932
- for (const [field2, item] of hashPairs(value)) {
11933
- setOwnValue(result, textToken(field2), decode(codec, item));
13422
+ for (const [field3, item] of hashPairs(value)) {
13423
+ setOwnValue(result, textToken(field3), decode(codec, item));
11934
13424
  }
11935
13425
  return result;
11936
13426
  }
11937
13427
  function decodeHashFlatPairs(codec, value) {
11938
13428
  const result = [];
11939
- for (const [field2, item] of hashPairs(value)) {
11940
- result.push(textToken(field2), decode(codec, item));
13429
+ for (const [field3, item] of hashPairs(value)) {
13430
+ result.push(textToken(field3), decode(codec, item));
11941
13431
  }
11942
13432
  return result;
11943
13433
  }
@@ -12057,7 +13547,7 @@ function requiredPair(value, message) {
12057
13547
  }
12058
13548
  function decodeStreamFieldValues(codec, value) {
12059
13549
  const result = [];
12060
- for (const [field2, item] of hashPairs(value)) result.push(textToken(field2), decode(codec, item));
13550
+ for (const [field3, item] of hashPairs(value)) result.push(textToken(field3), decode(codec, item));
12061
13551
  return result;
12062
13552
  }
12063
13553
  var geoSearchMetadataTokens = /* @__PURE__ */ new Set(["WITHCOORD", "WITHDIST", "WITHHASH"]);
@@ -12871,8 +14361,8 @@ var HashStore = class {
12871
14361
  async hset(key, entries) {
12872
14362
  return number(await commandArgs(this.client, keyValueArgs(["HSET", key], this.client.codec, entries)));
12873
14363
  }
12874
- async hget(key, field2) {
12875
- return decode(this.client.codec, await this.client.command("HGET", key, field2));
14364
+ async hget(key, field3) {
14365
+ return decode(this.client.codec, await this.client.command("HGET", key, field3));
12876
14366
  }
12877
14367
  async hdel(key, ...fieldsOrArray) {
12878
14368
  const fields = requireNonEmpty(arrayOrRest(fieldsOrArray), "HDEL", "field");
@@ -12891,8 +14381,8 @@ var HashStore = class {
12891
14381
  async hgetall(key) {
12892
14382
  return decodeHashRecord(this.client.codec, await this.client.command("HGETALL", key));
12893
14383
  }
12894
- async hexists(key, field2) {
12895
- return binaryBooleanResponse(await this.client.command("HEXISTS", key, field2));
14384
+ async hexists(key, field3) {
14385
+ return binaryBooleanResponse(await this.client.command("HEXISTS", key, field3));
12896
14386
  }
12897
14387
  async hkeys(key) {
12898
14388
  return mapArray(await this.client.command("HKEYS", key), "HKEYS", textToken);
@@ -12907,17 +14397,17 @@ var HashStore = class {
12907
14397
  async hlen(key) {
12908
14398
  return number(await this.client.command("HLEN", key));
12909
14399
  }
12910
- async hincrby(key, field2, increment) {
12911
- return integerReply(await this.client.command("HINCRBY", key, field2, increment));
14400
+ async hincrby(key, field3, increment) {
14401
+ return integerReply(await this.client.command("HINCRBY", key, field3, increment));
12912
14402
  }
12913
- async hincrbyfloat(key, field2, increment) {
12914
- return string(await this.client.command("HINCRBYFLOAT", key, field2, increment));
14403
+ async hincrbyfloat(key, field3, increment) {
14404
+ return string(await this.client.command("HINCRBYFLOAT", key, field3, increment));
12915
14405
  }
12916
- async hsetnx(key, field2, value) {
12917
- return binaryBooleanResponse(await this.client.command("HSETNX", key, field2, encode(this.client.codec, value)));
14406
+ async hsetnx(key, field3, value) {
14407
+ return binaryBooleanResponse(await this.client.command("HSETNX", key, field3, encode(this.client.codec, value)));
12918
14408
  }
12919
- async hstrlen(key, field2) {
12920
- return number(await this.client.command("HSTRLEN", key, field2));
14409
+ async hstrlen(key, field3) {
14410
+ return number(await this.client.command("HSTRLEN", key, field3));
12921
14411
  }
12922
14412
  async hrandfield(key, count, withValues = false) {
12923
14413
  if (withValues && count == null) {
@@ -13553,6 +15043,100 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
13553
15043
  }
13554
15044
  };
13555
15045
 
15046
+ // src/client-flow-query.ts
15047
+ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
15048
+ async query(query, params = {}) {
15049
+ if (hasFlowExplainPrefix(query)) {
15050
+ throw new TypeError("query does not accept EXPLAIN; use explain or explainAnalyze");
15051
+ }
15052
+ return decodeFlowQueryResult(await this.executeFlowQuery(query, params));
15053
+ }
15054
+ async explain(query, params = {}) {
15055
+ return await this.executeExplain("EXPLAIN ", query, params);
15056
+ }
15057
+ async explainAnalyze(query, params = {}) {
15058
+ return await this.executeExplain("EXPLAIN ANALYZE ", query, params);
15059
+ }
15060
+ async queryIndexes(indexId) {
15061
+ const args = ["FLOW.QUERY.INDEXES"];
15062
+ if (indexId != null) {
15063
+ validateFlowQueryIndexId(indexId);
15064
+ args.push(indexId);
15065
+ }
15066
+ try {
15067
+ return decodeFlowQueryIndexStatus(await this.commandArgs(args));
15068
+ } catch (error) {
15069
+ this.throwFlowQueryError(error);
15070
+ }
15071
+ }
15072
+ async list(type, options) {
15073
+ return await this.executeFlowRecordQuery(buildFlowListQuery(type, options));
15074
+ }
15075
+ async search(type, options) {
15076
+ return await this.executeFlowRecordQuery(buildFlowSearchQuery(type, options));
15077
+ }
15078
+ async terminals(type, options) {
15079
+ return await this.executeFlowRecordQuery(buildFlowTerminalQuery(type, options));
15080
+ }
15081
+ async failures(type, options) {
15082
+ return await this.executeFlowRecordQuery(buildFlowFailureQuery(type, options));
15083
+ }
15084
+ async byParent(parentFlowId, options) {
15085
+ return await this.executeFlowRecordQuery(
15086
+ buildFlowLineageQuery("parent_flow_id", parentFlowId, options)
15087
+ );
15088
+ }
15089
+ async byRoot(rootFlowId, options) {
15090
+ return await this.executeFlowRecordQuery(
15091
+ buildFlowLineageQuery("root_flow_id", rootFlowId, options)
15092
+ );
15093
+ }
15094
+ async byCorrelation(correlationId, options) {
15095
+ return await this.executeFlowRecordQuery(
15096
+ buildFlowLineageQuery("correlation_id", correlationId, options)
15097
+ );
15098
+ }
15099
+ async stuck(type, options) {
15100
+ return await this.executeFlowRecordQuery(buildFlowStuckQuery(type, options));
15101
+ }
15102
+ records(values) {
15103
+ const records = new Array(values.length);
15104
+ for (let index = 0; index < values.length; index += 1) {
15105
+ if (!Object.hasOwn(values, index)) {
15106
+ throw new TypeError(`Flow record response item ${index} is missing`);
15107
+ }
15108
+ records[index] = flowRecordFromResp(values[index], this.codec);
15109
+ }
15110
+ return records;
15111
+ }
15112
+ async executeFlowQuery(query, params) {
15113
+ const args = flowQueryArgs(query, params);
15114
+ try {
15115
+ return await this.commandArgs(args);
15116
+ } catch (error) {
15117
+ this.throwFlowQueryError(error);
15118
+ }
15119
+ }
15120
+ async executeFlowRecordQuery(request) {
15121
+ const response = await this.executeFlowQuery(request.query, request.params);
15122
+ return decodeFlowQueryRecords(response, (value) => flowRecordFromResp(value, this.codec));
15123
+ }
15124
+ async executeExplain(prefix, query, params) {
15125
+ validateFlowQueryText(query);
15126
+ if (hasFlowExplainPrefix(query)) {
15127
+ throw new TypeError("query already contains an EXPLAIN prefix");
15128
+ }
15129
+ return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query.trim(), params));
15130
+ }
15131
+ throwFlowQueryError(error) {
15132
+ if (error instanceof FerricStoreError) {
15133
+ const diagnostic = tryDecodeFlowQueryError(error.raw, error);
15134
+ if (diagnostic != null) throw diagnostic;
15135
+ }
15136
+ throw error;
15137
+ }
15138
+ };
15139
+
13556
15140
  // src/producer-backpressure.ts
13557
15141
  async function executeProducerWriteWithBackpressure(execute, policy, signal) {
13558
15142
  for (let attempt = 0; ; attempt += 1) {
@@ -13575,7 +15159,7 @@ function throwIfClosed(signal) {
13575
15159
  }
13576
15160
 
13577
15161
  // src/flow-policy.ts
13578
- var import_node_buffer41 = require("buffer");
15162
+ var import_node_buffer51 = require("buffer");
13579
15163
  var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
13580
15164
  function assertFlowPolicyGeneration(value) {
13581
15165
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
@@ -13585,15 +15169,15 @@ function assertFlowPolicyGeneration(value) {
13585
15169
  function flowPolicySnapshotFromResp(value) {
13586
15170
  const policy = requiredRecord(value, "FLOW policy snapshot");
13587
15171
  const maxActiveMs = optionalPositiveInteger(field(policy, "max_active_ms"), "max_active_ms");
13588
- const state = optionalText2(field(policy, "state"), "state");
15172
+ const state = optionalText3(field(policy, "state"), "state");
13589
15173
  const mode = optionalMode(field(policy, "mode"), "mode");
13590
15174
  const version = optionalVersion(field(policy, "version"));
13591
- const indexedStateMeta = optionalText2(field(policy, "indexed_state_meta"), "indexed_state_meta");
15175
+ const indexedStateMeta = optionalText3(field(policy, "indexed_state_meta"), "indexed_state_meta");
13592
15176
  const governance = optionalRecord(field(policy, "governance"), "governance");
13593
15177
  const states = optionalStates(field(policy, "states"));
13594
15178
  return {
13595
- type: requiredText(field(policy, "type"), "type"),
13596
- generation: nonNegativeInteger(field(policy, "generation"), "generation"),
15179
+ type: requiredText3(field(policy, "type"), "type"),
15180
+ generation: nonNegativeInteger2(field(policy, "generation"), "generation"),
13597
15181
  ...state == null ? {} : { state },
13598
15182
  ...version == null ? {} : { version },
13599
15183
  ...mode == null ? {} : { mode },
@@ -13611,21 +15195,21 @@ function retrySnapshot(value, context) {
13611
15195
  const retry2 = requiredRecord(value, `FLOW policy ${context}`);
13612
15196
  const backoff = requiredRecord(field(retry2, "backoff"), `FLOW policy ${context}.backoff`);
13613
15197
  return {
13614
- maxRetries: nonNegativeInteger(field(retry2, "max_retries"), `${context}.max_retries`),
15198
+ maxRetries: nonNegativeInteger2(field(retry2, "max_retries"), `${context}.max_retries`),
13615
15199
  backoff: {
13616
15200
  kind: backoffKind(field(backoff, "kind"), `${context}.backoff.kind`),
13617
- baseMs: nonNegativeInteger(field(backoff, "base_ms"), `${context}.backoff.base_ms`),
13618
- maxMs: nonNegativeInteger(field(backoff, "max_ms"), `${context}.backoff.max_ms`),
13619
- jitterPct: nonNegativeInteger(field(backoff, "jitter_pct"), `${context}.backoff.jitter_pct`)
15201
+ baseMs: nonNegativeInteger2(field(backoff, "base_ms"), `${context}.backoff.base_ms`),
15202
+ maxMs: nonNegativeInteger2(field(backoff, "max_ms"), `${context}.backoff.max_ms`),
15203
+ jitterPct: nonNegativeInteger2(field(backoff, "jitter_pct"), `${context}.backoff.jitter_pct`)
13620
15204
  },
13621
- exhaustedTo: requiredText(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
15205
+ exhaustedTo: requiredText3(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
13622
15206
  };
13623
15207
  }
13624
15208
  function retentionSnapshot(value, context) {
13625
15209
  const retention = requiredRecord(value, `FLOW policy ${context}`);
13626
15210
  return {
13627
- ttlMs: nonNegativeInteger(field(retention, "ttl_ms"), `${context}.ttl_ms`),
13628
- historyMaxEvents: nonNegativeInteger(
15211
+ ttlMs: nonNegativeInteger2(field(retention, "ttl_ms"), `${context}.ttl_ms`),
15212
+ historyMaxEvents: nonNegativeInteger2(
13629
15213
  field(retention, "history_max_events"),
13630
15214
  `${context}.history_max_events`
13631
15215
  )
@@ -13661,11 +15245,11 @@ function requiredRecord(value, context) {
13661
15245
  if (value instanceof Map) {
13662
15246
  const result = {};
13663
15247
  for (const [key, item] of value.entries()) {
13664
- setOwnValue(result, requiredText(key, `${context} key`), item);
15248
+ setOwnValue(result, requiredText3(key, `${context} key`), item);
13665
15249
  }
13666
15250
  return result;
13667
15251
  }
13668
- if (typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer41.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return value;
15252
+ if (typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer51.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return value;
13669
15253
  throw new TypeError(`${context} returned an unexpected response`);
13670
15254
  }
13671
15255
  function optionalRecord(value, context) {
@@ -13680,21 +15264,21 @@ function stringArray(value, context) {
13680
15264
  if (!Object.hasOwn(value, index)) {
13681
15265
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13682
15266
  }
13683
- result[index] = requiredText(value[index], `${context}[${index}]`);
15267
+ result[index] = requiredText3(value[index], `${context}[${index}]`);
13684
15268
  }
13685
15269
  return result;
13686
15270
  }
13687
- function requiredText(value, context) {
15271
+ function requiredText3(value, context) {
13688
15272
  if (typeof value === "string") return value;
13689
- if (import_node_buffer41.Buffer.isBuffer(value) || value instanceof Uint8Array) {
13690
- return import_node_buffer41.Buffer.from(value).toString("utf8");
15273
+ if (import_node_buffer51.Buffer.isBuffer(value) || value instanceof Uint8Array) {
15274
+ return import_node_buffer51.Buffer.from(value).toString("utf8");
13691
15275
  }
13692
15276
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13693
15277
  }
13694
- function optionalText2(value, context) {
13695
- return value == null ? void 0 : requiredText(value, context);
15278
+ function optionalText3(value, context) {
15279
+ return value == null ? void 0 : requiredText3(value, context);
13696
15280
  }
13697
- function nonNegativeInteger(value, context) {
15281
+ function nonNegativeInteger2(value, context) {
13698
15282
  let parsed;
13699
15283
  try {
13700
15284
  parsed = integer(value);
@@ -13706,26 +15290,26 @@ function nonNegativeInteger(value, context) {
13706
15290
  }
13707
15291
  function optionalPositiveInteger(value, context) {
13708
15292
  if (value == null) return void 0;
13709
- const parsed = nonNegativeInteger(value, context);
15293
+ const parsed = nonNegativeInteger2(value, context);
13710
15294
  if (parsed === 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13711
15295
  return parsed;
13712
15296
  }
13713
15297
  function optionalVersion(value) {
13714
15298
  if (value == null) return void 0;
13715
15299
  if (typeof value === "number" || typeof value === "bigint") {
13716
- return nonNegativeInteger(value, "version");
15300
+ return nonNegativeInteger2(value, "version");
13717
15301
  }
13718
- return requiredText(value, "version");
15302
+ return requiredText3(value, "version");
13719
15303
  }
13720
15304
  function backoffKind(value, context) {
13721
- const kind = requiredText(value, context).toLowerCase();
15305
+ const kind = requiredText3(value, context).toLowerCase();
13722
15306
  if (kind === "none" || kind === "fixed" || kind === "linear" || kind === "exponential") {
13723
15307
  return kind;
13724
15308
  }
13725
15309
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13726
15310
  }
13727
15311
  function requiredMode(value, context) {
13728
- const mode = requiredText(value, context).toLowerCase();
15312
+ const mode = requiredText3(value, context).toLowerCase();
13729
15313
  if (mode === "fifo" || mode === "parallel") return mode;
13730
15314
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13731
15315
  }
@@ -13734,7 +15318,7 @@ function optionalMode(value, context) {
13734
15318
  }
13735
15319
 
13736
15320
  // src/client-flow-support.ts
13737
- var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
15321
+ var FerricStoreFlowSupportClient = class extends FerricStoreFlowQueryClient {
13738
15322
  async rewind(id, options = {}) {
13739
15323
  const partitionKey = options.partitionKey;
13740
15324
  const returnRecord = options.returnRecord === true;
@@ -13760,43 +15344,9 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13760
15344
  }
13761
15345
  return flowRecordFromResp(response, this.codec);
13762
15346
  }
13763
- async list(type, options = {}) {
13764
- return await this.indexQuery("FLOW.LIST", type, options);
13765
- }
13766
- async search(type, options = {}) {
13767
- const args = ["FLOW.SEARCH", type];
13768
- appendReadOptions(args, options);
13769
- appendAttributes(args, options.attributes);
13770
- appendSearchStateMeta(args, options.state, options.stateMeta);
13771
- const response = await this.commandArgs(args);
13772
- return this.records(requiredArrayResponse(response, "FLOW.SEARCH"));
13773
- }
13774
- async terminals(type, options = {}) {
13775
- return await this.indexQuery("FLOW.TERMINALS", type, options);
13776
- }
13777
- async failures(type, options = {}) {
13778
- return await this.indexQuery("FLOW.FAILURES", type, options);
13779
- }
13780
- async byParent(parentFlowId, options = {}) {
13781
- return await this.indexQuery("FLOW.BY_PARENT", parentFlowId, options);
13782
- }
13783
- async byRoot(rootFlowId, options = {}) {
13784
- return await this.indexQuery("FLOW.BY_ROOT", rootFlowId, options);
13785
- }
13786
- async byCorrelation(correlationId, options = {}) {
13787
- return await this.indexQuery("FLOW.BY_CORRELATION", correlationId, options);
13788
- }
13789
15347
  async info(type) {
13790
15348
  return parseKvResponse(await this.command("FLOW.INFO", type));
13791
15349
  }
13792
- async stuck(type, options = {}) {
13793
- const args = ["FLOW.STUCK", type];
13794
- append(args, "PARTITION", options.partitionKey);
13795
- append(args, "COUNT", options.count);
13796
- append(args, "OLDER_THAN", options.olderThanMs);
13797
- append(args, "NOW", options.nowMs);
13798
- return this.records(arrayResponse(await this.commandArgs(args)));
13799
- }
13800
15350
  async history(id, options = {}) {
13801
15351
  const args = ["FLOW.HISTORY", id];
13802
15352
  append(args, "PARTITION", options.partitionKey);
@@ -13926,16 +15476,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13926
15476
  }
13927
15477
  return record;
13928
15478
  }
13929
- records(values) {
13930
- const records = new Array(values.length);
13931
- for (let index = 0; index < values.length; index += 1) {
13932
- if (!Object.hasOwn(values, index)) {
13933
- throw new TypeError(`Flow record response item ${index} is missing`);
13934
- }
13935
- records[index] = flowRecordFromResp(values[index], this.codec);
13936
- }
13937
- return records;
13938
- }
13939
15479
  recordsOrResponse(value) {
13940
15480
  if (Array.isArray(value) && value.every(isRecordLike)) {
13941
15481
  return this.records(value);
@@ -13965,12 +15505,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13965
15505
  }
13966
15506
  return results;
13967
15507
  }
13968
- async indexQuery(command, key, options) {
13969
- const args = [command, key];
13970
- appendReadOptions(args, options);
13971
- const response = await this.commandArgs(args);
13972
- return this.records(requiredArrayResponse(response, command));
13973
- }
13974
15508
  appendPartitionOptions(args, options) {
13975
15509
  if (options.partitionKey != null && options.partitionKeys != null) {
13976
15510
  throw new Error("partitionKey and partitionKeys are mutually exclusive");
@@ -13993,7 +15527,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13993
15527
  };
13994
15528
 
13995
15529
  // src/flow-many-snapshot.ts
13996
- var import_node_buffer43 = require("buffer");
15530
+ var import_node_buffer53 = require("buffer");
13997
15531
  var encodedOptionFields = ["error", "payload", "reason", "result"];
13998
15532
  function snapshotCreateItem(item, codec) {
13999
15533
  const snapshot = {
@@ -14011,9 +15545,9 @@ function snapshotCreateItem(item, codec) {
14011
15545
  function snapshotFlowManyOptions(options, codec) {
14012
15546
  const snapshot = { ...options };
14013
15547
  const mutable = snapshot;
14014
- for (const field2 of encodedOptionFields) {
14015
- const value = options[field2];
14016
- if (value != null) mutable[field2] = snapshotFlowValue(codec, value);
15548
+ for (const field3 of encodedOptionFields) {
15549
+ const value = options[field3];
15550
+ if (value != null) mutable[field3] = snapshotFlowValue(codec, value);
14017
15551
  }
14018
15552
  if (options.attributes != null) mutable.attributes = snapshotCommandRecord(options.attributes);
14019
15553
  if (options.attributesMerge != null) {
@@ -14033,7 +15567,7 @@ function snapshotFlowManyOptions(options, codec) {
14033
15567
  }
14034
15568
  function snapshotClaimedItem(item) {
14035
15569
  const wire = item[CLAIMED_ITEM_WIRE];
14036
- const leaseToken = import_node_buffer43.Buffer.from(wire?.leaseToken ?? item.leaseToken);
15570
+ const leaseToken = import_node_buffer53.Buffer.from(wire?.leaseToken ?? item.leaseToken);
14037
15571
  const snapshot = {
14038
15572
  ...item,
14039
15573
  fencingToken: wire?.fencingToken ?? item.fencingToken,
@@ -14050,15 +15584,15 @@ function snapshotClaimedItem(item) {
14050
15584
  function snapshotFencedItem(item) {
14051
15585
  return Object.freeze({
14052
15586
  ...item,
14053
- ...item.leaseToken == null ? {} : { leaseToken: import_node_buffer43.Buffer.from(item.leaseToken) }
15587
+ ...item.leaseToken == null ? {} : { leaseToken: import_node_buffer53.Buffer.from(item.leaseToken) }
14054
15588
  });
14055
15589
  }
14056
15590
  function snapshotClaimedItemWire(wire, leaseToken) {
14057
15591
  return Object.freeze({
14058
15592
  fencingToken: wire.fencingToken,
14059
- id: import_node_buffer43.Buffer.from(wire.id),
15593
+ id: import_node_buffer53.Buffer.from(wire.id),
14060
15594
  leaseToken,
14061
- partitionKey: wire.partitionKey == null ? wire.partitionKey : import_node_buffer43.Buffer.from(wire.partitionKey)
15595
+ partitionKey: wire.partitionKey == null ? wire.partitionKey : import_node_buffer53.Buffer.from(wire.partitionKey)
14062
15596
  });
14063
15597
  }
14064
15598
  function snapshotArray(values) {
@@ -14069,7 +15603,7 @@ function snapshotArray(values) {
14069
15603
  return Object.freeze(snapshot);
14070
15604
  }
14071
15605
  function snapshotStateMeta(stateMeta) {
14072
- return snapshotRecord(stateMeta, (value) => import_node_buffer43.Buffer.isBuffer(value) ? import_node_buffer43.Buffer.from(value) : value);
15606
+ return snapshotRecord(stateMeta, (value) => import_node_buffer53.Buffer.isBuffer(value) ? import_node_buffer53.Buffer.from(value) : value);
14073
15607
  }
14074
15608
  function snapshotCommandRecord(values) {
14075
15609
  const seen = /* @__PURE__ */ new WeakMap();
@@ -14087,7 +15621,7 @@ function snapshotRecord(values, capture) {
14087
15621
  }
14088
15622
  function snapshotCommandArgument(value, seen) {
14089
15623
  if (typeof value !== "object" || value == null) return value;
14090
- if (import_node_buffer43.Buffer.isBuffer(value) || value instanceof Uint8Array) return import_node_buffer43.Buffer.from(value);
15624
+ if (import_node_buffer53.Buffer.isBuffer(value) || value instanceof Uint8Array) return import_node_buffer53.Buffer.from(value);
14091
15625
  const objectValue = value;
14092
15626
  const existing = seen.get(objectValue);
14093
15627
  if (existing != null) return existing;
@@ -15074,6 +16608,142 @@ function nativeOptionsForBootstrap(options, signal) {
15074
16608
  };
15075
16609
  }
15076
16610
 
16611
+ // src/flow-query-projection.ts
16612
+ var import_node_buffer54 = require("buffer");
16613
+ var MAX_PROJECTION_FIELDS = 32;
16614
+ var MAX_DYNAMIC_NAME_BYTES = 64;
16615
+ var FIELD_BRAND = /* @__PURE__ */ Symbol("FerricStoreFlowProjectionField");
16616
+ function field2(source, selector) {
16617
+ return Object.freeze({ source, selector, [FIELD_BRAND]: true });
16618
+ }
16619
+ var run = Object.freeze({
16620
+ id: field2("runs", "run_id"),
16621
+ type: field2("runs", "type"),
16622
+ state: field2("runs", "state"),
16623
+ version: field2("runs", "version"),
16624
+ priority: field2("runs", "priority"),
16625
+ partitionKey: field2("runs", "partition_key"),
16626
+ createdAtMs: field2("runs", "created_at_ms"),
16627
+ updatedAtMs: field2("runs", "updated_at_ms"),
16628
+ nextRunAtMs: field2("runs", "next_run_at_ms"),
16629
+ leaseDeadlineMs: field2("runs", "lease_deadline_ms"),
16630
+ attempts: field2("runs", "attempts"),
16631
+ runState: field2("runs", "run_state"),
16632
+ maxActiveMs: field2("runs", "max_active_ms"),
16633
+ parentFlowId: field2("runs", "parent_flow_id"),
16634
+ rootFlowId: field2("runs", "root_flow_id"),
16635
+ correlationId: field2("runs", "correlation_id"),
16636
+ attributes: field2("runs", "attributes"),
16637
+ stateMetadata: field2("runs", "state_meta"),
16638
+ attribute(name) {
16639
+ return field2("runs", `attribute[${quoteName(name, false)}]`);
16640
+ },
16641
+ stateMeta(state, name) {
16642
+ return field2(
16643
+ "runs",
16644
+ `state_meta[${quoteName(state, true)}][${quoteName(name, false)}]`
16645
+ );
16646
+ }
16647
+ });
16648
+ var event = Object.freeze({
16649
+ id: field2("events", "event_id"),
16650
+ fields: field2("events", "fields"),
16651
+ field(name) {
16652
+ return field2("events", `fields[${quoteName(name, false)}]`);
16653
+ }
16654
+ });
16655
+ var FlowProjection = Object.freeze({ run, event });
16656
+ function projectFlowQuery(query, shape, ...fields) {
16657
+ validateFlowQueryText(query);
16658
+ if (shape !== "record" && shape !== "records") {
16659
+ throw new TypeError("Flow query projection shape must be record or records");
16660
+ }
16661
+ if (fields.length === 0 || fields.length > MAX_PROJECTION_FIELDS) {
16662
+ throw new TypeError(
16663
+ `Flow query projection must contain 1..${MAX_PROJECTION_FIELDS} fields`
16664
+ );
16665
+ }
16666
+ if (!fields.every((item) => item?.[FIELD_BRAND])) {
16667
+ throw new TypeError("Flow query projection accepts only FlowProjection fields");
16668
+ }
16669
+ const source = querySource(query);
16670
+ if (fields.some((item) => item.source !== source)) {
16671
+ throw new TypeError(`Flow query projection fields must belong to ${source}`);
16672
+ }
16673
+ const selectors = fields.map((item) => item.selector);
16674
+ if (new Set(selectors).size !== selectors.length) {
16675
+ throw new TypeError("Flow query projection contains a duplicate field");
16676
+ }
16677
+ if (containsReturnKeyword(query)) {
16678
+ throw new TypeError("Flow query already contains a RETURN clause");
16679
+ }
16680
+ const trimmed = query.trim();
16681
+ const base = trimmed.endsWith(";") ? trimmed.slice(0, -1).trimEnd() : trimmed;
16682
+ const result = `${base} RETURN ${shape.toUpperCase()} (${selectors.join(", ")})`;
16683
+ if (import_node_buffer54.Buffer.byteLength(result, "utf8") > FLOW_QUERY_MAX_BYTES) {
16684
+ throw new TypeError(`FLOW.QUERY query exceeds ${FLOW_QUERY_MAX_BYTES} bytes`);
16685
+ }
16686
+ return result;
16687
+ }
16688
+ function querySource(query) {
16689
+ const match = /^\s*FROM\s+(runs|events)\b/iu.exec(query);
16690
+ if (match?.[1] == null) {
16691
+ throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
16692
+ }
16693
+ return match[1].toLowerCase();
16694
+ }
16695
+ function containsReturnKeyword(query) {
16696
+ let quoted = false;
16697
+ for (let index = 0; index < query.length; ) {
16698
+ const character = query.charAt(index);
16699
+ if (character === "'") {
16700
+ if (quoted && query[index + 1] === "'") {
16701
+ index += 2;
16702
+ continue;
16703
+ }
16704
+ quoted = !quoted;
16705
+ index += 1;
16706
+ continue;
16707
+ }
16708
+ if (!quoted && /[A-Za-z_]/u.test(character)) {
16709
+ let end = index + 1;
16710
+ while (end < query.length && /[A-Za-z0-9_]/u.test(query.charAt(end))) end += 1;
16711
+ if (query.slice(index, end).toUpperCase() === "RETURN") return true;
16712
+ index = end;
16713
+ continue;
16714
+ }
16715
+ index += 1;
16716
+ }
16717
+ return false;
16718
+ }
16719
+ function quoteName(value, allowPrivate) {
16720
+ if (typeof value !== "string") {
16721
+ throw new TypeError("Flow query projection metadata name must be text");
16722
+ }
16723
+ validateUnicodeScalarText2(value);
16724
+ const size = import_node_buffer54.Buffer.byteLength(value, "utf8");
16725
+ if (size === 0 || size > MAX_DYNAMIC_NAME_BYTES || !allowPrivate && value.startsWith("__")) {
16726
+ throw new TypeError(
16727
+ `Flow query projection metadata names must be 1..${MAX_DYNAMIC_NAME_BYTES} UTF-8 bytes`
16728
+ );
16729
+ }
16730
+ return `'${value.replaceAll("'", "''")}'`;
16731
+ }
16732
+ function validateUnicodeScalarText2(value) {
16733
+ for (let index = 0; index < value.length; index += 1) {
16734
+ const code = value.charCodeAt(index);
16735
+ if (code >= 55296 && code <= 56319) {
16736
+ const low = value.charCodeAt(index + 1);
16737
+ if (!(low >= 56320 && low <= 57343)) {
16738
+ throw new TypeError("Flow query projection metadata name must be valid UTF-8");
16739
+ }
16740
+ index += 1;
16741
+ } else if (code >= 56320 && code <= 57343) {
16742
+ throw new TypeError("Flow query projection metadata name must be valid UTF-8");
16743
+ }
16744
+ }
16745
+ }
16746
+
15077
16747
  // src/outcomes.ts
15078
16748
  var OUTCOME_BRAND = /* @__PURE__ */ Symbol("ferricstore.outcome");
15079
16749
  function transition(toState, options = {}) {
@@ -15153,7 +16823,7 @@ var LeaseRenewalGuard = class {
15153
16823
  if (options.leaseRenewal === false) {
15154
16824
  return;
15155
16825
  }
15156
- const intervalMs = positiveInteger(options.leaseRenewIntervalMs, Math.max(1, Math.trunc(leaseMs / 2)));
16826
+ const intervalMs = positiveInteger2(options.leaseRenewIntervalMs, Math.max(1, Math.trunc(leaseMs / 2)));
15157
16827
  this.timer = setLongInterval(() => this.renew(), intervalMs);
15158
16828
  this.timer.unref();
15159
16829
  }
@@ -15225,7 +16895,7 @@ function snapshotLeasedJob(job) {
15225
16895
  return snapshot;
15226
16896
  }
15227
16897
  function workerConcurrency(options) {
15228
- return positiveInteger(options.concurrency ?? options.workers, 1);
16898
+ return positiveInteger2(options.concurrency ?? options.workers, 1);
15229
16899
  }
15230
16900
  function workerRefillStrategy(options) {
15231
16901
  return options.refillStrategy === "wave" ? "wave" : "continuous";
@@ -15268,18 +16938,18 @@ function workerErrorPayload(error, options, codec) {
15268
16938
  }
15269
16939
  function workerBatchSize(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
15270
16940
  return Math.min(
15271
- positiveInteger(options.batchSize, 10),
15272
- positiveInteger(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
16941
+ positiveInteger2(options.batchSize, 10),
16942
+ positiveInteger2(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
15273
16943
  );
15274
16944
  }
15275
16945
  function workerClaimLimit(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
15276
16946
  return Math.min(workerBatchSize(options, flowManyBatchLimit), workerConcurrency(options));
15277
16947
  }
15278
16948
  function workerDrainBatches(options) {
15279
- return positiveInteger(options.claimDrainBatches, 1);
16949
+ return positiveInteger2(options.claimDrainBatches, 1);
15280
16950
  }
15281
16951
  function workerLeaseMs(options, fallback = 3e4) {
15282
- return positiveInteger(options.leaseMs, positiveInteger(fallback, 3e4));
16952
+ return positiveInteger2(options.leaseMs, positiveInteger2(fallback, 3e4));
15283
16953
  }
15284
16954
  function workerIdleSleepMs(options) {
15285
16955
  return nonNegativeDuration(options.idleSleepMs, 250);
@@ -15291,7 +16961,7 @@ function workerClaimBlockMs(options, useBlocking) {
15291
16961
  if (options.signal == null || !Number.isFinite(options.blockMs) || options.blockMs < 0) {
15292
16962
  return options.blockMs;
15293
16963
  }
15294
- const abortPollMs = positiveInteger(options.abortPollMs, 1e3);
16964
+ const abortPollMs = positiveInteger2(options.abortPollMs, 1e3);
15295
16965
  return options.blockMs === 0 ? abortPollMs : Math.min(Math.trunc(options.blockMs), abortPollMs);
15296
16966
  }
15297
16967
  function workerMaxIdleSleepMs(options, idleSleepMs = workerIdleSleepMs(options)) {
@@ -15302,14 +16972,14 @@ function nextWorkerIdleSleepMs(currentIdleSleepMs, maxIdleSleepMs) {
15302
16972
  return Math.min(maxIdleSleepMs, Math.max(1, currentIdleSleepMs * 2));
15303
16973
  }
15304
16974
  async function runContinuousWorkerPool(options) {
15305
- const concurrency = positiveInteger(options.concurrency, 1);
15306
- const maxClaimSize = positiveInteger(options.maxClaimSize, concurrency);
16975
+ const concurrency = positiveInteger2(options.concurrency, 1);
16976
+ const maxClaimSize = positiveInteger2(options.maxClaimSize, concurrency);
15307
16977
  const initialIdleSleepMs = nonNegativeDuration(options.idleSleepMs, 250);
15308
16978
  const maxIdleSleepMs = Math.max(
15309
16979
  initialIdleSleepMs,
15310
16980
  nonNegativeDuration(options.maxIdleSleepMs, 5e3)
15311
16981
  );
15312
- const refillDelayMs = nonNegativeInteger2(options.refillDelayMs, 0);
16982
+ const refillDelayMs = nonNegativeInteger3(options.refillDelayMs, 0);
15313
16983
  const active = /* @__PURE__ */ new Set();
15314
16984
  const pending = [];
15315
16985
  let pendingIndex = 0;
@@ -15425,10 +17095,10 @@ function normalizeWorkflowWorkerConfig(options) {
15425
17095
  ...captured
15426
17096
  });
15427
17097
  }
15428
- function positiveInteger(value, fallback) {
17098
+ function positiveInteger2(value, fallback) {
15429
17099
  return value == null || !Number.isFinite(value) ? fallback : Math.max(1, Math.trunc(value));
15430
17100
  }
15431
- function nonNegativeInteger2(value, fallback) {
17101
+ function nonNegativeInteger3(value, fallback) {
15432
17102
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, Math.trunc(value));
15433
17103
  }
15434
17104
  function nonNegativeDuration(value, fallback) {
@@ -17057,8 +18727,8 @@ var WorkflowWorker = class {
17057
18727
  };
17058
18728
 
17059
18729
  // src/version.ts
17060
- var FERRICSTORE_SDK_VERSION = "0.3.0";
17061
- var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.9.1";
18730
+ var FERRICSTORE_SDK_VERSION = "0.5.0";
18731
+ var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.0";
17062
18732
  var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
17063
18733
  // Annotate the CommonJS export names for ESM import in node:
17064
18734
  0 && (module.exports = {
@@ -17077,6 +18747,8 @@ var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
17077
18747
  FlowAlreadyExistsError,
17078
18748
  FlowBatchError,
17079
18749
  FlowNotFoundError,
18750
+ FlowProjection,
18751
+ FlowQueryError,
17080
18752
  FlowWrongStateError,
17081
18753
  GeoStore,
17082
18754
  HashStore,
@@ -17119,6 +18791,7 @@ var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
17119
18791
  isOutcome,
17120
18792
  isReconnectableClosedConnectionError,
17121
18793
  mapException,
18794
+ projectFlowQuery,
17122
18795
  retry,
17123
18796
  transition
17124
18797
  });