@ferricstore/ferricstore 0.2.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 (113) hide show
  1. package/README.md +72 -3
  2. package/dist/index.cjs +2618 -554
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +247 -33
  5. package/dist/index.d.ts +247 -33
  6. package/dist/index.js +2621 -562
  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 +5 -5
  12. package/docs/api/classes/ConnectionClosedError.html +5 -5
  13. package/docs/api/classes/FerricStoreClient.html +7 -3
  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/ReconnectingExecutor.html +4 -4
  28. package/docs/api/classes/RequestTimeoutError.html +5 -5
  29. package/docs/api/classes/RerouteError.html +5 -5
  30. package/docs/api/classes/StaleLeaseError.html +5 -5
  31. package/docs/api/classes/StalePolicyGenerationError.html +39 -0
  32. package/docs/api/classes/TopologyNativeAdapterPool.html +3 -3
  33. package/docs/api/classes/Workflow.html +1 -1
  34. package/docs/api/classes/WorkflowWorker.html +2 -2
  35. package/docs/api/functions/classifyServerError.html +1 -1
  36. package/docs/api/functions/isReconnectableClosedConnectionError.html +1 -1
  37. package/docs/api/functions/mapException.html +1 -1
  38. package/docs/api/functions/projectFlowQuery.html +1 -0
  39. package/docs/api/hierarchy.html +1 -1
  40. package/docs/api/index.html +36 -5
  41. package/docs/api/interfaces/AdminListOptions.html +1 -1
  42. package/docs/api/interfaces/CancelOptions.html +2 -2
  43. package/docs/api/interfaces/CompleteOptions.html +2 -2
  44. package/docs/api/interfaces/CompleteOutcome.html +1 -1
  45. package/docs/api/interfaces/CreateManyOptions.html +1 -1
  46. package/docs/api/interfaces/EffectCompensateOptions.html +1 -1
  47. package/docs/api/interfaces/EffectConfirmOptions.html +1 -1
  48. package/docs/api/interfaces/EffectFailOptions.html +1 -1
  49. package/docs/api/interfaces/EffectStatusOptions.html +1 -1
  50. package/docs/api/interfaces/ExtendLeaseOptions.html +2 -2
  51. package/docs/api/interfaces/FailOptions.html +2 -2
  52. package/docs/api/interfaces/FailOutcome.html +1 -1
  53. package/docs/api/interfaces/FerricStoreClientFromUrlOptions.html +1 -1
  54. package/docs/api/interfaces/FerricStoreClientOptions.html +1 -1
  55. package/docs/api/interfaces/FlowEventProjectionField.html +4 -0
  56. package/docs/api/interfaces/FlowExplainResult.html +10 -0
  57. package/docs/api/interfaces/FlowPolicyBackoffSnapshot.html +5 -0
  58. package/docs/api/interfaces/FlowPolicyOptions.html +8 -4
  59. package/docs/api/interfaces/FlowPolicyRetentionSnapshot.html +3 -0
  60. package/docs/api/interfaces/FlowPolicyRetrySnapshot.html +4 -0
  61. package/docs/api/interfaces/FlowPolicySnapshot.html +17 -0
  62. package/docs/api/interfaces/FlowPolicyStateSnapshot.html +6 -0
  63. package/docs/api/interfaces/FlowQueryCountResult.html +7 -0
  64. package/docs/api/interfaces/FlowQueryErrorPosition.html +4 -0
  65. package/docs/api/interfaces/FlowQueryIndex.html +9 -0
  66. package/docs/api/interfaces/FlowQueryIndexFormat.html +7 -0
  67. package/docs/api/interfaces/FlowQueryIndexRegistry.html +3 -0
  68. package/docs/api/interfaces/FlowQueryIndexStatus.html +8 -0
  69. package/docs/api/interfaces/FlowQueryPage.html +3 -0
  70. package/docs/api/interfaces/FlowQueryQuality.html +5 -0
  71. package/docs/api/interfaces/FlowQueryRecordsResult.html +8 -0
  72. package/docs/api/interfaces/FlowQueryUsage.html +12 -0
  73. package/docs/api/interfaces/FlowRunProjectionField.html +4 -0
  74. package/docs/api/interfaces/HistoryOptions.html +2 -2
  75. package/docs/api/interfaces/InvocationCreateOptions.html +2 -2
  76. package/docs/api/interfaces/LeaseMutationOptions.html +2 -2
  77. package/docs/api/interfaces/LimitListOptions.html +1 -1
  78. package/docs/api/interfaces/MutateOptions.html +2 -2
  79. package/docs/api/interfaces/NamedValueMutation.html +1 -1
  80. package/docs/api/interfaces/ProtocolCommand.html +2 -2
  81. package/docs/api/interfaces/ReadOptions.html +5 -3
  82. package/docs/api/interfaces/ReclaimOptions.html +1 -1
  83. package/docs/api/interfaces/RequestContext.html +2 -2
  84. package/docs/api/interfaces/RequestContextOptions.html +2 -2
  85. package/docs/api/interfaces/RetryOptions.html +2 -2
  86. package/docs/api/interfaces/RetryOutcome.html +1 -1
  87. package/docs/api/interfaces/RunStepsItem.html +2 -2
  88. package/docs/api/interfaces/RunStepsManyOptions.html +2 -2
  89. package/docs/api/interfaces/SearchOptions.html +4 -3
  90. package/docs/api/interfaces/StepContinueOptions.html +3 -3
  91. package/docs/api/interfaces/TDigestCreateOptions.html +1 -1
  92. package/docs/api/interfaces/TDigestMergeOptions.html +1 -1
  93. package/docs/api/interfaces/TransitionOptions.html +2 -2
  94. package/docs/api/interfaces/TransitionOutcome.html +1 -1
  95. package/docs/api/modules.html +1 -1
  96. package/docs/api/types/ConnectionRequestDisposition.html +1 -1
  97. package/docs/api/types/FlowPolicyBackoffKind.html +1 -0
  98. package/docs/api/types/FlowProjectionField.html +1 -0
  99. package/docs/api/types/FlowProjectionShape.html +1 -0
  100. package/docs/api/types/FlowQueryInteger.html +1 -0
  101. package/docs/api/types/FlowQueryParameter.html +1 -0
  102. package/docs/api/types/FlowQueryParameters.html +1 -0
  103. package/docs/api/types/FlowQueryRecord.html +1 -0
  104. package/docs/api/types/FlowQueryResult.html +1 -0
  105. package/docs/api/types/ManagementPairs.html +1 -1
  106. package/docs/api/types/SearchStateMeta.html +1 -1
  107. package/docs/api/variables/COMMAND_OPCODES.html +1 -1
  108. package/docs/api/variables/FERRICSTORE_MINIMUM_SERVER_VERSION.html +1 -1
  109. package/docs/api/variables/FERRICSTORE_NATIVE_PROTOCOL_VERSION.html +1 -1
  110. package/docs/api/variables/FERRICSTORE_SDK_VERSION.html +1 -1
  111. package/docs/api/variables/FlowProjection.html +1 -0
  112. package/docs/api/variables/MAX_FLOW_POLICY_GENERATION.html +1 -0
  113. 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,
@@ -56,6 +58,7 @@ __export(index_exports, {
56
58
  ListStore: () => ListStore,
57
59
  LockHeldError: () => LockHeldError,
58
60
  LockNotOwnedError: () => LockNotOwnedError,
61
+ MAX_FLOW_POLICY_GENERATION: () => MAX_FLOW_POLICY_GENERATION,
59
62
  NativeAdapter: () => NativeAdapter,
60
63
  OverloadedError: () => OverloadedError,
61
64
  Queue: () => Queue,
@@ -70,6 +73,7 @@ __export(index_exports, {
70
73
  SetStore: () => SetStore,
71
74
  SortedSetStore: () => SortedSetStore,
72
75
  StaleLeaseError: () => StaleLeaseError,
76
+ StalePolicyGenerationError: () => StalePolicyGenerationError,
73
77
  StreamStore: () => StreamStore,
74
78
  TDigestStore: () => TDigestStore,
75
79
  TopKStore: () => TopKStore,
@@ -85,6 +89,7 @@ __export(index_exports, {
85
89
  isOutcome: () => isOutcome,
86
90
  isReconnectableClosedConnectionError: () => isReconnectableClosedConnectionError,
87
91
  mapException: () => mapException,
92
+ projectFlowQuery: () => projectFlowQuery,
88
93
  retry: () => retry,
89
94
  transition: () => transition
90
95
  });
@@ -102,7 +107,7 @@ function assertSafeVariadicDispatch(argumentCount, arrayCapability) {
102
107
  // src/native-adapter.ts
103
108
  var import_node_net3 = require("net");
104
109
  var import_node_tls3 = require("tls");
105
- var import_node_buffer25 = require("buffer");
110
+ var import_node_buffer31 = require("buffer");
106
111
 
107
112
  // src/errors.ts
108
113
  var FerricStoreError = class extends Error {
@@ -150,6 +155,9 @@ var FlowWrongStateError = class extends FerricStoreError {
150
155
  var StaleLeaseError = class extends FerricStoreError {
151
156
  code = "stale_lease";
152
157
  };
158
+ var StalePolicyGenerationError = class extends FerricStoreError {
159
+ code = "stale_policy_generation";
160
+ };
153
161
  var FlowAlreadyExistsError = class extends FerricStoreError {
154
162
  code = "flow_already_exists";
155
163
  };
@@ -215,6 +223,9 @@ function classifyServerError(message, raw, cause, status) {
215
223
  if (code === "stale_lease" || code === "stale_flow_lease" || lower.includes("stale flow lease") || lower.includes("stale lease") || lower.includes("stale token")) {
216
224
  return new StaleLeaseError(message, { cause, raw });
217
225
  }
226
+ if (code === "stale_generation" || code === "stale_policy_generation" || code === "stale_flow_policy_generation" || lower.includes("stale flow policy generation") || lower.includes("stale policy generation")) {
227
+ return new StalePolicyGenerationError(message, { cause, raw });
228
+ }
218
229
  if (code === "flow_not_found" || lower.includes("flow") && (lower.includes("not found") || lower.includes("does not exist"))) {
219
230
  return new FlowNotFoundError(message, { cause, raw });
220
231
  }
@@ -1268,10 +1279,151 @@ var NativeHeartbeat = class {
1268
1279
  };
1269
1280
 
1270
1281
  // src/protocol.ts
1271
- var import_node_buffer21 = require("buffer");
1282
+ var import_node_buffer27 = require("buffer");
1272
1283
 
1273
- // src/command-grammar.ts
1284
+ // src/flow-query-request.ts
1274
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");
1275
1427
 
1276
1428
  // src/command-metadata-flow.ts
1277
1429
  var flowStateIdCommands = /* @__PURE__ */ new Set([
@@ -1662,20 +1814,15 @@ var typeScopedFlowCommands = /* @__PURE__ */ new Set([
1662
1814
  "FLOW.ATTRIBUTE_VALUES",
1663
1815
  "FLOW.ATTRIBUTES",
1664
1816
  "FLOW.BUDGET.LIST",
1665
- "FLOW.FAILURES",
1666
1817
  "FLOW.GOVERNANCE.OVERVIEW",
1667
1818
  "FLOW.INFO",
1668
1819
  "FLOW.LIMIT.LIST",
1669
- "FLOW.LIST",
1670
1820
  "FLOW.POLICY.GET",
1671
1821
  "FLOW.POLICY.SET",
1672
1822
  "FLOW.RETENTION_CLEANUP",
1673
1823
  "FLOW.SCHEDULE.FIRE_DUE",
1674
1824
  "FLOW.SCHEDULE.LIST",
1675
- "FLOW.SEARCH",
1676
- "FLOW.STATS",
1677
- "FLOW.STUCK",
1678
- "FLOW.TERMINALS"
1825
+ "FLOW.STATS"
1679
1826
  ]);
1680
1827
  var flowScheduleCommands = /* @__PURE__ */ new Set([
1681
1828
  "FLOW.SCHEDULE.CREATE",
@@ -1718,8 +1865,8 @@ var secondKeySubcommands = /* @__PURE__ */ new Map([
1718
1865
  ]);
1719
1866
  function commandToken(value) {
1720
1867
  if (typeof value === "string") return value.toUpperCase();
1721
- if (import_node_buffer3.Buffer.isBuffer(value) || value instanceof Uint8Array) {
1722
- 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();
1723
1870
  }
1724
1871
  return void 0;
1725
1872
  }
@@ -1822,7 +1969,7 @@ function safeIntegerArgument(value) {
1822
1969
  if (typeof value === "bigint") {
1823
1970
  return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
1824
1971
  }
1825
- 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;
1826
1973
  if (source == null || !/^[+-]?\d+$/u.test(source)) return void 0;
1827
1974
  const parsed = BigInt(source);
1828
1975
  return parsed >= BigInt(Number.MIN_SAFE_INTEGER) && parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : void 0;
@@ -1875,10 +2022,10 @@ function hasOwnCommandArgument(args, index, end, section) {
1875
2022
  }
1876
2023
 
1877
2024
  // src/protocol-core.ts
1878
- var import_node_buffer7 = require("buffer");
2025
+ var import_node_buffer8 = require("buffer");
1879
2026
 
1880
2027
  // src/protocol-constants.ts
1881
- var import_node_buffer4 = require("buffer");
2028
+ var import_node_buffer5 = require("buffer");
1882
2029
 
1883
2030
  // src/native-protocol-manifest.json
1884
2031
  var native_protocol_manifest_default = {
@@ -1973,7 +2120,6 @@ var COMMAND_OPCODES = {
1973
2120
  "FLOW.VALUE.PUT": 523,
1974
2121
  "FLOW.VALUE.MGET": 524,
1975
2122
  "FLOW.SIGNAL": 525,
1976
- "FLOW.LIST": 526,
1977
2123
  "FLOW.CREATE_MANY": 527,
1978
2124
  "FLOW.COMPLETE_MANY": 528,
1979
2125
  "FLOW.TRANSITION_MANY": 529,
@@ -1982,13 +2128,7 @@ var COMMAND_OPCODES = {
1982
2128
  "FLOW.CANCEL_MANY": 532,
1983
2129
  "FLOW.RECLAIM": 533,
1984
2130
  "FLOW.REWIND": 534,
1985
- "FLOW.TERMINALS": 535,
1986
- "FLOW.FAILURES": 536,
1987
- "FLOW.BY_PARENT": 537,
1988
- "FLOW.BY_ROOT": 538,
1989
- "FLOW.BY_CORRELATION": 539,
1990
2131
  "FLOW.INFO": 540,
1991
- "FLOW.STUCK": 541,
1992
2132
  "FLOW.POLICY.SET": 542,
1993
2133
  "FLOW.POLICY.GET": 543,
1994
2134
  "FLOW.SPAWN_CHILDREN": 544,
@@ -2007,7 +2147,7 @@ var COMMAND_OPCODES = {
2007
2147
  "FLOW.STATS": 557,
2008
2148
  "FLOW.ATTRIBUTES": 558,
2009
2149
  "FLOW.ATTRIBUTE_VALUES": 559,
2010
- "FLOW.SEARCH": 560,
2150
+ "FLOW.QUERY": 561,
2011
2151
  "FLOW.EFFECT.RESERVE": 576,
2012
2152
  "FLOW.EFFECT.CONFIRM": 577,
2013
2153
  "FLOW.EFFECT.FAIL": 578,
@@ -2090,11 +2230,13 @@ var OPCODES = {
2090
2230
  flowRetryMany: COMMAND_OPCODES["FLOW.RETRY_MANY"],
2091
2231
  flowFailMany: COMMAND_OPCODES["FLOW.FAIL_MANY"],
2092
2232
  flowReclaim: COMMAND_OPCODES["FLOW.RECLAIM"],
2233
+ flowPolicySet: COMMAND_OPCODES["FLOW.POLICY.SET"],
2234
+ flowPolicyGet: COMMAND_OPCODES["FLOW.POLICY.GET"],
2093
2235
  flowSpawnChildren: COMMAND_OPCODES["FLOW.SPAWN_CHILDREN"],
2094
2236
  flowStepContinue: COMMAND_OPCODES["FLOW.STEP_CONTINUE"],
2095
2237
  flowStartAndClaim: COMMAND_OPCODES["FLOW.START_AND_CLAIM"],
2096
2238
  flowRunStepsMany: COMMAND_OPCODES["FLOW.RUN_STEPS_MANY"],
2097
- flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
2239
+ flowQuery: COMMAND_OPCODES["FLOW.QUERY"]
2098
2240
  };
2099
2241
  var COMPACT_FLOW_CLAIM_JOBS = 128;
2100
2242
  var COMPACT_OK_LIST = 129;
@@ -2121,11 +2263,12 @@ var COMPACT_FLOW_TRANSITION_MANY_REQUEST = 155;
2121
2263
  var COMPACT_FLOW_TRANSITION_MANY_OK_REQUEST = 156;
2122
2264
  var COMPACT_FLOW_VALUE_MGET_REQUEST = 157;
2123
2265
  var COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST = 158;
2124
- var COMPACT_FLOW_LIST_REQUEST = 159;
2266
+ var COMPACT_FLOW_QUERY_RESULT = 160;
2125
2267
  var COMPACT_PIPELINE_DECODED = /* @__PURE__ */ Symbol("ferricstore.compactPipelineDecoded");
2126
2268
  var NULL_U32 = 4294967295;
2127
- var MIN_I64 = -9223372036854775808n;
2128
- var MAX_I64 = 9223372036854775807n;
2269
+ var MIN_I642 = -9223372036854775808n;
2270
+ var MAX_I642 = 9223372036854775807n;
2271
+ var MAX_U64 = 18446744073709551615n;
2129
2272
  var MAX_SAFE_INTEGER_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
2130
2273
  var MIN_SAFE_INTEGER_BIGINT = BigInt(Number.MIN_SAFE_INTEGER);
2131
2274
  var FLOW_RECORD_FIELD_KEYS = [
@@ -2174,16 +2317,16 @@ var FLOW_RECORD_FIELD_KEYS = [
2174
2317
  ];
2175
2318
 
2176
2319
  // src/protocol-text.ts
2177
- var import_node_buffer5 = require("buffer");
2320
+ var import_node_buffer6 = require("buffer");
2178
2321
  function toBuffer(value) {
2179
- if (import_node_buffer5.Buffer.isBuffer(value)) return value;
2180
- if (value instanceof Uint8Array) return import_node_buffer5.Buffer.from(value);
2181
- 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);
2182
2325
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2183
- return import_node_buffer5.Buffer.from(String(value));
2326
+ return import_node_buffer6.Buffer.from(String(value));
2184
2327
  }
2185
- if (typeof value === "symbol") return import_node_buffer5.Buffer.from(value.description ?? value.toString());
2186
- 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);
2187
2330
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2188
2331
  }
2189
2332
  function asText(value) {
@@ -2191,14 +2334,14 @@ function asText(value) {
2191
2334
  }
2192
2335
  function optionalText(value) {
2193
2336
  if (value == null || value === "") return void 0;
2194
- 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) {
2195
2338
  return asText(value);
2196
2339
  }
2197
2340
  return void 0;
2198
2341
  }
2199
2342
  function commandTokenIs(value, expected) {
2200
2343
  if (typeof value === "string") return value.toUpperCase() === expected;
2201
- if (import_node_buffer5.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2344
+ if (import_node_buffer6.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2202
2345
  return asText(value).toUpperCase() === expected;
2203
2346
  }
2204
2347
  return false;
@@ -2212,7 +2355,7 @@ function commandNameIs(value, expected) {
2212
2355
  }
2213
2356
 
2214
2357
  // src/request-context.ts
2215
- var import_node_buffer6 = require("buffer");
2358
+ var import_node_buffer7 = require("buffer");
2216
2359
  var requestContextCommands = /* @__PURE__ */ new Set([
2217
2360
  "INVOCATION.CREATE",
2218
2361
  "INVOCATION.DEFINITION.GET",
@@ -2267,9 +2410,9 @@ function requestContextCommandToken(value) {
2267
2410
  const upper = value.toUpperCase();
2268
2411
  return isRequestContextCommand(upper) ? upper : void 0;
2269
2412
  }
2270
- if (import_node_buffer6.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2413
+ if (import_node_buffer7.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2271
2414
  if (value[0] !== 73 && value[0] !== 105) return void 0;
2272
- const command = import_node_buffer6.Buffer.from(value).toString("utf8").toUpperCase();
2415
+ const command = import_node_buffer7.Buffer.from(value).toString("utf8").toUpperCase();
2273
2416
  return isRequestContextCommand(command) ? command : void 0;
2274
2417
  }
2275
2418
  return void 0;
@@ -2300,12 +2443,12 @@ function requestContextText(context, fieldName) {
2300
2443
  return value;
2301
2444
  }
2302
2445
  function isPlainObject(value) {
2303
- 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);
2304
2447
  }
2305
2448
  function commandToken2(value) {
2306
2449
  if (typeof value === "string") return value.toUpperCase();
2307
- if (import_node_buffer6.Buffer.isBuffer(value) || value instanceof Uint8Array) {
2308
- 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();
2309
2452
  }
2310
2453
  return "";
2311
2454
  }
@@ -2395,17 +2538,17 @@ function requestFrameTooLarge(maxBytes) {
2395
2538
  );
2396
2539
  }
2397
2540
  function binaryValueByteLength(value) {
2398
- if (import_node_buffer7.Buffer.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2399
- 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);
2400
2543
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2401
- return import_node_buffer7.Buffer.byteLength(String(value));
2544
+ return import_node_buffer8.Buffer.byteLength(String(value));
2402
2545
  }
2403
- 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());
2404
2547
  if (value == null) return 0;
2405
2548
  return toBuffer(value).byteLength;
2406
2549
  }
2407
2550
  function writeCustomPayload(output, offset, value, knownByteLength) {
2408
- if (import_node_buffer7.Buffer.isBuffer(value)) {
2551
+ if (import_node_buffer8.Buffer.isBuffer(value)) {
2409
2552
  value.copy(output, offset);
2410
2553
  return;
2411
2554
  }
@@ -2424,7 +2567,7 @@ function writeCustomPayload(output, offset, value, knownByteLength) {
2424
2567
  } else {
2425
2568
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2426
2569
  }
2427
- 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");
2428
2571
  }
2429
2572
  function compactBinaryEncodedLength(value) {
2430
2573
  return 4 + compactBinaryByteLength(value);
@@ -2437,10 +2580,10 @@ function compactBinaryByteLength(value) {
2437
2580
  return byteLength;
2438
2581
  }
2439
2582
  function isCompactBinaryArgument(value) {
2440
- 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;
2441
2584
  }
2442
2585
  function isCompactBinaryScalar(value) {
2443
- 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;
2444
2587
  }
2445
2588
  function compactOptionalBinaryEncodedLength(value) {
2446
2589
  return value == null ? 4 : compactBinaryEncodedLength(value);
@@ -2506,7 +2649,7 @@ function integerArg(value) {
2506
2649
  throw new FerricStoreError("integer command argument must be an integer");
2507
2650
  }
2508
2651
  const integer2 = BigInt(source);
2509
- if (integer2 < MIN_I64 || integer2 > MAX_I64) {
2652
+ if (integer2 < MIN_I642 || integer2 > MAX_I642) {
2510
2653
  throw new FerricStoreError("integer command argument exceeds the signed 64-bit range");
2511
2654
  }
2512
2655
  return integer2 >= MIN_SAFE_INTEGER_BIGINT && integer2 <= MAX_SAFE_INTEGER_BIGINT ? Number(integer2) : integer2;
@@ -2537,7 +2680,7 @@ function independentMode(value) {
2537
2680
  return 0;
2538
2681
  }
2539
2682
  function optionalI64(value) {
2540
- return typeof value === "number" ? BigInt(value) : MIN_I64;
2683
+ return typeof value === "number" ? BigInt(value) : MIN_I642;
2541
2684
  }
2542
2685
  function compactClaimReturnMode(value) {
2543
2686
  const mode = value == null ? "" : asText(value).toUpperCase();
@@ -2571,18 +2714,18 @@ function setOwnValue2(target, key, value) {
2571
2714
  }
2572
2715
 
2573
2716
  // src/protocol-flow-options.ts
2574
- var import_node_buffer8 = require("buffer");
2717
+ var import_node_buffer9 = require("buffer");
2575
2718
 
2576
2719
  // src/protocol-flow-option-value.ts
2577
- function setFlowOptionValue(payload, field2, value, repeat) {
2578
- if (!repeat || !Object.hasOwn(payload, field2)) {
2579
- setOwnValue2(payload, field2, value);
2720
+ function setFlowOptionValue(payload, field3, value, repeat) {
2721
+ if (!repeat || !Object.hasOwn(payload, field3)) {
2722
+ setOwnValue2(payload, field3, value);
2580
2723
  return;
2581
2724
  }
2582
- const previous = payload[field2];
2725
+ const previous = payload[field3];
2583
2726
  setOwnValue2(
2584
2727
  payload,
2585
- field2,
2728
+ field3,
2586
2729
  Array.isArray(previous) ? [...previous, value] : [previous, value]
2587
2730
  );
2588
2731
  }
@@ -2625,44 +2768,30 @@ function optionMap(args) {
2625
2768
  index += 3;
2626
2769
  continue;
2627
2770
  }
2628
- const field2 = OPTION_FIELDS[token] ?? token.toLowerCase();
2771
+ const field3 = OPTION_FIELDS[token] ?? token.toLowerCase();
2629
2772
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow options")) {
2630
2773
  throw new FerricStoreError(`${token} requires a value`);
2631
2774
  }
2632
2775
  const value = args[index + 1];
2633
- if (BOOL_OPTION_FIELDS.has(field2) && !isBoolToken(value)) {
2776
+ if (BOOL_OPTION_FIELDS.has(field3) && !isBoolToken(value)) {
2634
2777
  return void 0;
2635
2778
  }
2636
- setOwnValue2(payload, field2, BOOL_OPTION_FIELDS.has(field2) ? boolArg(value) : value);
2779
+ setOwnValue2(payload, field3, BOOL_OPTION_FIELDS.has(field3) ? boolArg(value) : value);
2637
2780
  index += 2;
2638
2781
  }
2639
2782
  return payload;
2640
2783
  }
2641
- function ensureObjectField(payload, field2) {
2642
- const value = payload[field2];
2784
+ function ensureObjectField(payload, field3) {
2785
+ const value = payload[field3];
2643
2786
  if (isPlainObject2(value)) {
2644
2787
  return value;
2645
2788
  }
2646
2789
  const next = {};
2647
- setOwnValue2(payload, field2, next);
2790
+ setOwnValue2(payload, field3, next);
2648
2791
  return next;
2649
2792
  }
2650
- function normalizeFlowSearchStateMeta(payload) {
2651
- const stateMeta = payload.state_meta;
2652
- if (!isPlainObject2(stateMeta) || Object.keys(stateMeta).length === 0) {
2653
- return;
2654
- }
2655
- if (Object.values(stateMeta).every(isPlainObject2)) {
2656
- return;
2657
- }
2658
- const state = payload.state;
2659
- if (state == null) {
2660
- throw new FerricStoreError("FLOW.SEARCH STATE_META filters require STATE or nested state metadata");
2661
- }
2662
- payload.state_meta = { [asText(state)]: stateMeta };
2663
- }
2664
2793
  function isPlainObject2(value) {
2665
- 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);
2666
2795
  }
2667
2796
  function parseFlowOptions(args, start, end, config) {
2668
2797
  const payload = {};
@@ -2756,9 +2885,9 @@ function parseFlowOptions(args, start, end, config) {
2756
2885
  case "TRANSITION_TO":
2757
2886
  case "TO_EVENT":
2758
2887
  case "EXPECT_STATE": {
2759
- const field2 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2888
+ const field3 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2760
2889
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2761
- setFlowOptionValue(payload, field2, args[index + 1], token === "IF_STATE");
2890
+ setFlowOptionValue(payload, field3, args[index + 1], token === "IF_STATE");
2762
2891
  index += 2;
2763
2892
  break;
2764
2893
  }
@@ -2766,8 +2895,8 @@ function parseFlowOptions(args, start, end, config) {
2766
2895
  case "RESULT":
2767
2896
  case "ERROR":
2768
2897
  case "REASON": {
2769
- const field2 = token === "LEASE_TOKEN" ? "lease_token" : token.toLowerCase();
2770
- 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;
2771
2900
  index += 2;
2772
2901
  break;
2773
2902
  }
@@ -2789,8 +2918,8 @@ function parseFlowOptions(args, start, end, config) {
2789
2918
  case "VALUE_REF":
2790
2919
  case "STATE_META": {
2791
2920
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options") || !hasOwnCommandArgument(args, index + 2, end, "Flow options")) return void 0;
2792
- const field2 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "VALUE_REF" ? "value_refs" : "state_meta";
2793
- 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);
2794
2923
  setOwnValue2(values, asText(args[index + 1]), args[index + 2]);
2795
2924
  index += 3;
2796
2925
  break;
@@ -2799,8 +2928,8 @@ function parseFlowOptions(args, start, end, config) {
2799
2928
  case "OVERRIDE_VALUE":
2800
2929
  case "ATTRIBUTE_DELETE": {
2801
2930
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2802
- const field2 = token === "DROP_VALUE" ? "drop_values" : token === "OVERRIDE_VALUE" ? "override_values" : "attributes_delete";
2803
- 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);
2804
2933
  values.push(args[index + 1]);
2805
2934
  index += 2;
2806
2935
  break;
@@ -2917,13 +3046,13 @@ function putScalar(payload, key, args, index, end) {
2917
3046
  setOwnValue2(payload, key, args[index]);
2918
3047
  return true;
2919
3048
  }
2920
- function ensureArrayField(payload, field2) {
2921
- const value = payload[field2];
3049
+ function ensureArrayField(payload, field3) {
3050
+ const value = payload[field3];
2922
3051
  if (Array.isArray(value)) {
2923
3052
  return value;
2924
3053
  }
2925
3054
  const next = [];
2926
- setOwnValue2(payload, field2, next);
3055
+ setOwnValue2(payload, field3, next);
2927
3056
  return next;
2928
3057
  }
2929
3058
  function putNumber(payload, key, args, index, end) {
@@ -3144,8 +3273,8 @@ function flowHistoryPayload(args) {
3144
3273
  case "CONSISTENT_PROJECTION":
3145
3274
  case "VALUES": {
3146
3275
  if (!isBoolToken(value)) return void 0;
3147
- const field2 = token === "REV" ? "rev" : token === "INCLUDE_COLD" ? "include_cold" : token === "CONSISTENT_PROJECTION" ? "consistent_projection" : "values";
3148
- 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);
3149
3278
  break;
3150
3279
  }
3151
3280
  default:
@@ -3157,9 +3286,9 @@ function flowHistoryPayload(args) {
3157
3286
  function flowAdminPayload(opcode, args, leadingFields = []) {
3158
3287
  if (args.length < leadingFields.length) return void 0;
3159
3288
  const payload = {};
3160
- for (const [index, field2] of leadingFields.entries()) {
3289
+ for (const [index, field3] of leadingFields.entries()) {
3161
3290
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
3162
- setOwnValue2(payload, field2, args[index]);
3291
+ setOwnValue2(payload, field3, args[index]);
3163
3292
  }
3164
3293
  for (let index = leadingFields.length; index < args.length; ) {
3165
3294
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
@@ -3167,15 +3296,15 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3167
3296
  if (token == null) return void 0;
3168
3297
  if (["ATTRIBUTE", "ATTRIBUTE_MERGE", "STATE_META", "VALUE", "VALUE_REF"].includes(token)) {
3169
3298
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments") || !hasOwnCommandArgument(args, index + 2, args.length, "Flow admin arguments")) return void 0;
3170
- const field3 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "STATE_META" ? "state_meta" : token === "VALUE" ? "values" : "value_refs";
3171
- 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]);
3172
3301
  index += 3;
3173
3302
  continue;
3174
3303
  }
3175
3304
  if (token === "ATTRIBUTE_DELETE" || token === "DROP_VALUE" || token === "OVERRIDE_VALUE") {
3176
3305
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) return void 0;
3177
- const field3 = token === "ATTRIBUTE_DELETE" ? "attributes_delete" : token === "DROP_VALUE" ? "drop_values" : "override_values";
3178
- 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]);
3179
3308
  index += 2;
3180
3309
  continue;
3181
3310
  }
@@ -3194,13 +3323,13 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3194
3323
  index += 2 + count;
3195
3324
  continue;
3196
3325
  }
3197
- const field2 = FLOW_ADMIN_FIELDS[token];
3198
- 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")) {
3199
3328
  return void 0;
3200
3329
  }
3201
3330
  const rawValue = args[index + 1];
3202
- if (FLOW_ADMIN_BOOLEAN_FIELDS.has(field2) && !isBoolToken(rawValue)) return void 0;
3203
- 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);
3204
3333
  index += 2;
3205
3334
  }
3206
3335
  const serverBlockMs = opcode === COMMAND_OPCODES["FLOW.SCHEDULE.FIRE_DUE"] && payload.block_ms != null ? blockDurationMs(payload.block_ms, 1) : void 0;
@@ -3208,7 +3337,7 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3208
3337
  }
3209
3338
 
3210
3339
  // src/protocol-flow-compact.ts
3211
- var import_node_buffer10 = require("buffer");
3340
+ var import_node_buffer11 = require("buffer");
3212
3341
 
3213
3342
  // src/protocol-flow-compact-common.ts
3214
3343
  function compactManyRequestTag(value, regularTag, okOnSuccessTag) {
@@ -3317,7 +3446,7 @@ function parseNamedCountMap(values, start) {
3317
3446
  }
3318
3447
 
3319
3448
  // src/protocol-flow-compact-transition.ts
3320
- var import_node_buffer9 = require("buffer");
3449
+ var import_node_buffer10 = require("buffer");
3321
3450
  function compactFlowTransitionManyPayload(partition, fromState, toState, rawItems, mixed, options, maxBodyBytes) {
3322
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) {
3323
3452
  return void 0;
@@ -3369,7 +3498,7 @@ function compactFlowTransitionManyPayload(partition, fromState, toState, rawItem
3369
3498
  total += 4 + idLength + 4 + itemPartitionLength + 8 + 4 + leaseLength;
3370
3499
  }
3371
3500
  assertCompactPayloadFits(total, maxBodyBytes);
3372
- const out = import_node_buffer9.Buffer.allocUnsafe(total);
3501
+ const out = import_node_buffer10.Buffer.allocUnsafe(total);
3373
3502
  let offset = 0;
3374
3503
  out.writeUInt8(tag, offset);
3375
3504
  offset += 1;
@@ -3427,7 +3556,7 @@ function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options,
3427
3556
  }
3428
3557
  assertCompactPayloadFits(total, maxBodyBytes);
3429
3558
  const tag = mixed ? COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST : auto ? COMPACT_FLOW_CREATE_MANY_REQUEST : COMPACT_FLOW_CREATE_MANY_PARTITION_REQUEST;
3430
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3559
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3431
3560
  let offset = 0;
3432
3561
  out.writeUInt8(tag, offset++);
3433
3562
  offset = writeBinary(out, offset, toBuffer(options.type));
@@ -3472,7 +3601,7 @@ function compactFlowClaimDuePayload(type, options, maxBodyBytes) {
3472
3601
  total += 1;
3473
3602
  }
3474
3603
  assertCompactPayloadFits(total, maxBodyBytes);
3475
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3604
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3476
3605
  let offset = 0;
3477
3606
  out.writeUInt8(COMPACT_FLOW_CLAIM_DUE_REQUEST, offset++);
3478
3607
  offset = writeBinary(out, offset, toBuffer(type));
@@ -3526,7 +3655,7 @@ function compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto
3526
3655
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3527
3656
  }
3528
3657
  assertCompactPayloadFits(total, maxBodyBytes);
3529
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3658
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3530
3659
  let offset = 0;
3531
3660
  out.writeUInt8(
3532
3661
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_COMPLETE_MANY_OK_REQUEST : COMPACT_FLOW_COMPLETE_MANY_REQUEST,
@@ -3573,7 +3702,7 @@ function compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options,
3573
3702
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3574
3703
  }
3575
3704
  assertCompactPayloadFits(total, maxBodyBytes);
3576
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3705
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3577
3706
  let offset = 0;
3578
3707
  out.writeUInt8(
3579
3708
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_RETRY_MANY_OK_REQUEST : COMPACT_FLOW_RETRY_MANY_REQUEST,
@@ -3661,7 +3790,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3661
3790
  total += 4 + idLength + 4 + itemPartitionLength + 8;
3662
3791
  }
3663
3792
  assertCompactPayloadFits(total, maxBodyBytes);
3664
- const out = import_node_buffer10.Buffer.allocUnsafe(total);
3793
+ const out = import_node_buffer11.Buffer.allocUnsafe(total);
3665
3794
  let offset = 0;
3666
3795
  out.writeUInt8(tag, offset);
3667
3796
  offset += 1;
@@ -3684,6 +3813,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3684
3813
  offset += 8;
3685
3814
  }
3686
3815
  return {
3816
+ compactResponseItems: count,
3687
3817
  flags: FLAG_CUSTOM_PAYLOAD,
3688
3818
  opcode: COMMAND_OPCODES["FLOW.CANCEL_MANY"],
3689
3819
  payload: out
@@ -3697,7 +3827,7 @@ function isOptionalSafeIntegerNumber(value) {
3697
3827
  }
3698
3828
 
3699
3829
  // src/protocol-flow-compact-single.ts
3700
- var import_node_buffer11 = require("buffer");
3830
+ var import_node_buffer12 = require("buffer");
3701
3831
  function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3702
3832
  if (refs.length > 4294967295 || maxBytes != null && (typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 0)) return void 0;
3703
3833
  const minimum = 13 + refs.length * 4;
@@ -3714,7 +3844,7 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3714
3844
  total += 4 + byteLength;
3715
3845
  }
3716
3846
  assertCompactPayloadFits(total, maxBodyBytes);
3717
- const out = import_node_buffer11.Buffer.allocUnsafe(total);
3847
+ const out = import_node_buffer12.Buffer.allocUnsafe(total);
3718
3848
  let offset = 0;
3719
3849
  out.writeUInt8(COMPACT_FLOW_VALUE_MGET_REQUEST, offset);
3720
3850
  offset += 1;
@@ -3727,47 +3857,6 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3727
3857
  }
3728
3858
  return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.flowValueMGet, payload: out };
3729
3859
  }
3730
- function compactFlowListPayload(args, maxBodyBytes) {
3731
- const type = args[0];
3732
- if (!isCompactBinaryArgument(type)) return void 0;
3733
- let state;
3734
- let count = 100;
3735
- let returnMode = 0;
3736
- const seen = /* @__PURE__ */ new Set();
3737
- for (let index = 1; index < args.length; index += 2) {
3738
- if (index + 1 >= args.length) return void 0;
3739
- const token = asText(args[index]).toUpperCase();
3740
- if (seen.has(token)) return void 0;
3741
- seen.add(token);
3742
- if (token === "STATE") {
3743
- if (!isCompactBinaryArgument(args[index + 1])) return void 0;
3744
- state = args[index + 1];
3745
- } else if (token === "COUNT") {
3746
- const value = safeIntegerNumberArg(args[index + 1]);
3747
- if (value <= 0) return void 0;
3748
- count = value;
3749
- } else if (token === "RETURN") {
3750
- if (!commandTokenIs(args[index + 1], "META")) return void 0;
3751
- returnMode = 1;
3752
- } else {
3753
- return void 0;
3754
- }
3755
- }
3756
- const typeLength = compactBinaryByteLength(type);
3757
- const stateLength = state == null ? 0 : compactBinaryByteLength(state);
3758
- const total = 1 + 4 + typeLength + 4 + stateLength + 8 + 1;
3759
- assertCompactPayloadFits(total, maxBodyBytes);
3760
- const out = import_node_buffer11.Buffer.allocUnsafe(total);
3761
- let offset = 0;
3762
- out.writeUInt8(COMPACT_FLOW_LIST_REQUEST, offset);
3763
- offset += 1;
3764
- offset = writeBinaryValue(out, offset, type, typeLength);
3765
- offset = writeOptionalBinaryValue(out, offset, state, stateLength);
3766
- out.writeBigInt64BE(BigInt(count), offset);
3767
- offset += 8;
3768
- out.writeUInt8(returnMode, offset);
3769
- return { flags: FLAG_CUSTOM_PAYLOAD, opcode: COMMAND_OPCODES["FLOW.LIST"], payload: out };
3770
- }
3771
3860
 
3772
3861
  // src/protocol-flow-routing.ts
3773
3862
  function withFlowPartitionRouting(command, payload) {
@@ -3816,15 +3905,6 @@ function expandFlowClaimStates(args) {
3816
3905
  }
3817
3906
 
3818
3907
  // src/protocol-flow.ts
3819
- function hasFlowCommandOnlyOption(command, args) {
3820
- if (command !== "FLOW.SEARCH") return false;
3821
- for (let index = 1; index < args.length; ) {
3822
- const token = asText(args[index]).toUpperCase();
3823
- if (token === "INDEXED_STATE_META") return true;
3824
- index += token === "ATTRIBUTE" || token === "STATE_META" ? 3 : 2;
3825
- }
3826
- return false;
3827
- }
3828
3908
  function flowCreatePayload(args) {
3829
3909
  if (args.length < 7) return void 0;
3830
3910
  const id = args[0];
@@ -3881,9 +3961,9 @@ function flowValueMGetPayload(args, maxBodyBytes, allowCompact) {
3881
3961
  }
3882
3962
  if (allowCompact) {
3883
3963
  const compact = compactFlowValueMGetPayload(refs, payload.max_bytes, maxBodyBytes);
3884
- if (compact != null) return compact;
3964
+ if (compact != null) return { ...compact, compactResponseItems: refs.length };
3885
3965
  }
3886
- return { opcode: OPCODES.flowValueMGet, payload };
3966
+ return { compactResponseItems: refs.length, opcode: OPCODES.flowValueMGet, payload };
3887
3967
  }
3888
3968
  function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3889
3969
  if (args.length < 2) return void 0;
@@ -3919,7 +3999,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3919
3999
  if (items2 == null) return void 0;
3920
4000
  const payload2 = { ...options, items: items2 };
3921
4001
  if (!auto && !mixed) payload2.partition_key = partition;
3922
- return { opcode: OPCODES.flowCreateMany, payload: payload2 };
4002
+ return { compactResponseItems: items2.length, opcode: OPCODES.flowCreateMany, payload: payload2 };
3923
4003
  }
3924
4004
  const rawItems = denseCommandArgumentTail(args, itemsIndex + 1, "ITEMS");
3925
4005
  const width = mixed ? 3 : 2;
@@ -3933,7 +4013,9 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3933
4013
  options,
3934
4014
  maxBodyBytes
3935
4015
  );
3936
- if (compact != null) return compact;
4016
+ if (compact != null) {
4017
+ return { ...compact, compactResponseItems: rawItems.length / width };
4018
+ }
3937
4019
  }
3938
4020
  const items = [];
3939
4021
  for (let index = 0; index < rawItems.length; index += width) {
@@ -3945,7 +4027,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3945
4027
  }
3946
4028
  const payload = { ...options, items };
3947
4029
  if (!auto && !mixed) payload.partition_key = partition;
3948
- return { opcode: OPCODES.flowCreateMany, payload };
4030
+ return { compactResponseItems: items.length, opcode: OPCODES.flowCreateMany, payload };
3949
4031
  }
3950
4032
  function flowClaimDuePayload(args, maxBodyBytes, allowCompact) {
3951
4033
  if (args.length < 1) return void 0;
@@ -4108,7 +4190,9 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4108
4190
  if (rawItems.length === 0 || rawItems.length % width !== 0) return void 0;
4109
4191
  if (allowCompact) {
4110
4192
  const compact = command === "FLOW.RETRY_MANY" ? compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options, maxBodyBytes) : compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto, options, maxBodyBytes);
4111
- if (compact != null) return compact;
4193
+ if (compact != null) {
4194
+ return { ...compact, compactResponseItems: rawItems.length / width };
4195
+ }
4112
4196
  }
4113
4197
  const items = [];
4114
4198
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4120,7 +4204,7 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4120
4204
  }
4121
4205
  const payload = { ...options, items };
4122
4206
  if (!auto && !mixed) payload.partition_key = partition;
4123
- return { opcode, payload };
4207
+ return { compactResponseItems: items.length, opcode, payload };
4124
4208
  }
4125
4209
  function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4126
4210
  if (args.length < 4) return void 0;
@@ -4160,7 +4244,9 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4160
4244
  options,
4161
4245
  maxBodyBytes
4162
4246
  ) : void 0;
4163
- if (compact != null) return compact;
4247
+ if (compact != null) {
4248
+ return { ...compact, compactResponseItems: rawItems.length / width };
4249
+ }
4164
4250
  }
4165
4251
  const items = [];
4166
4252
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4180,7 +4266,11 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4180
4266
  items
4181
4267
  };
4182
4268
  if (!mixed) payload.partition_key = args[0];
4183
- return { opcode: OPCODES.flowTransitionMany, payload };
4269
+ return {
4270
+ compactResponseItems: items.length,
4271
+ opcode: OPCODES.flowTransitionMany,
4272
+ payload
4273
+ };
4184
4274
  }
4185
4275
  function flowSpawnChildrenPayload(args) {
4186
4276
  if (args.length < 2) return void 0;
@@ -4223,13 +4313,6 @@ function flowSpawnChildrenPayload(args) {
4223
4313
  payload: { id: args[0], ...options, children }
4224
4314
  };
4225
4315
  }
4226
- function flowSearchPayload(args) {
4227
- if (args.length < 1) return void 0;
4228
- const payload = optionMap(args.slice(1));
4229
- if (payload == null) return void 0;
4230
- normalizeFlowSearchStateMeta(payload);
4231
- return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
4232
- }
4233
4316
 
4234
4317
  // src/protocol-flow-signal.ts
4235
4318
  function flowSignalPayload(args) {
@@ -4254,6 +4337,162 @@ function flowSignalPayload(args) {
4254
4337
  return { opcode: OPCODES.flowSignal, payload: { id: args[0], ...options } };
4255
4338
  }
4256
4339
 
4340
+ // src/protocol-flow-policy.ts
4341
+ var import_node_buffer13 = require("buffer");
4342
+ var BACKOFF_FIELDS = {
4343
+ BASE_MS: "base_ms",
4344
+ MAX_MS: "max_ms",
4345
+ JITTER_PCT: "jitter_pct"
4346
+ };
4347
+ var RETENTION_FIELDS = {
4348
+ RETENTION_TTL: "ttl_ms",
4349
+ RETENTION_TTL_MS: "ttl_ms",
4350
+ HISTORY_MAX_EVENTS: "history_max_events"
4351
+ };
4352
+ function flowPolicySetPayload(args) {
4353
+ if (!hasOwnCommandArgument(args, 0, args.length, "Flow policy arguments")) return void 0;
4354
+ if (!isBinaryArgument(args[0])) return void 0;
4355
+ const payload = { type: args[0] };
4356
+ const states = {};
4357
+ let target = payload;
4358
+ for (let index = 1; index < args.length; index += 2) {
4359
+ if (!hasOwnCommandArgument(args, index, args.length, "Flow policy arguments") || !hasOwnCommandArgument(args, index + 1, args.length, "Flow policy arguments")) return void 0;
4360
+ const token = optionalText(args[index])?.toUpperCase();
4361
+ const value = args[index + 1];
4362
+ if (token == null || value == null) return void 0;
4363
+ if (token === "STATE") {
4364
+ if (!isBinaryArgument(value)) return void 0;
4365
+ const state = asText(value);
4366
+ target = {};
4367
+ setOwnValue2(states, state, target);
4368
+ setOwnValue2(payload, "states", states);
4369
+ continue;
4370
+ }
4371
+ if (token === "MODE") {
4372
+ if (!isBinaryArgument(value)) return void 0;
4373
+ const mode = optionalText(value)?.toLowerCase();
4374
+ if (target === payload || mode !== "fifo" && mode !== "parallel") return void 0;
4375
+ setOwnValue2(target, "mode", mode);
4376
+ continue;
4377
+ }
4378
+ if (token === "EXPECTED_GENERATION") {
4379
+ if (target !== payload) return void 0;
4380
+ const generation = integerOption(value);
4381
+ if (generation == null || generation < 0) return void 0;
4382
+ setOwnValue2(payload, "expected_generation", generation);
4383
+ continue;
4384
+ }
4385
+ if (token === "REPLACE") {
4386
+ if (target !== payload || !isBoolToken(value)) return void 0;
4387
+ setOwnValue2(payload, "replace", boolArg(value));
4388
+ continue;
4389
+ }
4390
+ if (token === "MAX_ACTIVE_MS") {
4391
+ if (target !== payload) return void 0;
4392
+ const maxActiveMs = maxActiveOption(value);
4393
+ if (maxActiveMs == null) return void 0;
4394
+ setOwnValue2(payload, "max_active_ms", maxActiveMs);
4395
+ continue;
4396
+ }
4397
+ if (token === "INDEXED_STATE_META") {
4398
+ if (target !== payload || !isBinaryArgument(value)) return void 0;
4399
+ setOwnValue2(payload, "indexed_state_meta", value);
4400
+ continue;
4401
+ }
4402
+ if (token === "INDEXED_ATTRIBUTES") {
4403
+ if (target !== payload) return void 0;
4404
+ const names = indexedAttributes(value);
4405
+ if (names == null) return void 0;
4406
+ setOwnValue2(payload, "indexed_attributes", names);
4407
+ continue;
4408
+ }
4409
+ if (token === "MAX_RETRIES") {
4410
+ const parsed = integerOption(value);
4411
+ if (parsed == null) return void 0;
4412
+ setOwnValue2(objectField(target, "retry"), "max_retries", parsed);
4413
+ continue;
4414
+ }
4415
+ if (token === "EXHAUSTED_TO") {
4416
+ if (!isBinaryArgument(value)) return void 0;
4417
+ setOwnValue2(objectField(target, "retry"), "exhausted_to", value);
4418
+ continue;
4419
+ }
4420
+ const backoffField = BACKOFF_FIELDS[token];
4421
+ if (backoffField != null) {
4422
+ const parsed = integerOption(value);
4423
+ if (parsed == null) return void 0;
4424
+ setOwnValue2(objectField(objectField(target, "retry"), "backoff"), backoffField, parsed);
4425
+ continue;
4426
+ }
4427
+ if (token === "BACKOFF") {
4428
+ if (!isBinaryArgument(value)) return void 0;
4429
+ const kind = optionalText(value)?.toLowerCase();
4430
+ if (kind == null) return void 0;
4431
+ setOwnValue2(objectField(objectField(target, "retry"), "backoff"), "kind", kind);
4432
+ continue;
4433
+ }
4434
+ const retentionField = RETENTION_FIELDS[token];
4435
+ if (retentionField != null) {
4436
+ if (target === payload) return void 0;
4437
+ const parsed = integerOption(value);
4438
+ if (parsed == null) return void 0;
4439
+ setOwnValue2(objectField(target, "retention"), retentionField, parsed);
4440
+ continue;
4441
+ }
4442
+ return void 0;
4443
+ }
4444
+ return { opcode: OPCODES.flowPolicySet, payload };
4445
+ }
4446
+ function flowPolicyGetPayload(args) {
4447
+ if (!hasOwnCommandArgument(args, 0, args.length, "Flow policy arguments")) return void 0;
4448
+ if (!isBinaryArgument(args[0])) return void 0;
4449
+ if (args.length !== 1 && args.length !== 3) return void 0;
4450
+ const payload = { type: args[0] };
4451
+ if (args.length === 3) {
4452
+ if (!hasOwnCommandArgument(args, 1, args.length, "Flow policy arguments") || !hasOwnCommandArgument(args, 2, args.length, "Flow policy arguments") || optionalText(args[1])?.toUpperCase() !== "STATE" || !isBinaryArgument(args[2])) return void 0;
4453
+ setOwnValue2(payload, "state", args[2]);
4454
+ }
4455
+ return { opcode: OPCODES.flowPolicyGet, payload };
4456
+ }
4457
+ function integerOption(value) {
4458
+ try {
4459
+ return safeIntegerNumberArg(value);
4460
+ } catch {
4461
+ return void 0;
4462
+ }
4463
+ }
4464
+ function maxActiveOption(value) {
4465
+ if (isBinaryArgument(value) && asText(value).toLowerCase() === "infinity") {
4466
+ return "infinity";
4467
+ }
4468
+ return integerOption(value);
4469
+ }
4470
+ function isBinaryArgument(value) {
4471
+ return typeof value === "string" || import_node_buffer13.Buffer.isBuffer(value) || value instanceof Uint8Array;
4472
+ }
4473
+ function objectField(target, name) {
4474
+ const existing = Object.hasOwn(target, name) ? target[name] : void 0;
4475
+ if (typeof existing === "object" && existing != null && !Array.isArray(existing)) {
4476
+ return existing;
4477
+ }
4478
+ const value = {};
4479
+ setOwnValue2(target, name, value);
4480
+ return value;
4481
+ }
4482
+ function indexedAttributes(value) {
4483
+ if (Array.isArray(value)) {
4484
+ return value.every((item) => typeof item === "string") ? value : void 0;
4485
+ }
4486
+ const source = optionalText(value);
4487
+ if (source == null) return void 0;
4488
+ try {
4489
+ const parsed = JSON.parse(source);
4490
+ return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : void 0;
4491
+ } catch {
4492
+ return void 0;
4493
+ }
4494
+ }
4495
+
4257
4496
  // src/protocol-connection-policy.ts
4258
4497
  function assertCommandDoesNotRequirePinnedConnection(args) {
4259
4498
  const outer = commandName(args[0]);
@@ -4301,7 +4540,7 @@ function commandRequiresOrderedPipelineExecution(args) {
4301
4540
  }
4302
4541
 
4303
4542
  // src/protocol-compact-request.ts
4304
- var import_node_buffer12 = require("buffer");
4543
+ var import_node_buffer14 = require("buffer");
4305
4544
  function compactMsetPayload(args, maxBodyBytes) {
4306
4545
  if (args.length % 2 !== 0) throw new FerricStoreError("MSET requires key/value pairs");
4307
4546
  const minimum = 6 + args.length * 4;
@@ -4320,7 +4559,7 @@ function compactMsetPayload(args, maxBodyBytes) {
4320
4559
  total += 4 + byteLength;
4321
4560
  }
4322
4561
  assertCompactPayloadFits(total, maxBodyBytes);
4323
- const out = import_node_buffer12.Buffer.allocUnsafe(total);
4562
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4324
4563
  let offset = writeCompactPipelineHeader(out, 1, args.length / 2);
4325
4564
  for (let index = 0; index < args.length; index += 1) {
4326
4565
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4344,7 +4583,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4344
4583
  total += 4 + byteLength;
4345
4584
  }
4346
4585
  assertCompactPayloadFits(total, maxBodyBytes);
4347
- const out = import_node_buffer12.Buffer.allocUnsafe(total);
4586
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4348
4587
  let offset = writeCompactPipelineHeader(out, mode, args.length);
4349
4588
  for (let index = 0; index < args.length; index += 1) {
4350
4589
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4354,7 +4593,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4354
4593
  function compactPipelinePayload(commands, maxBodyBytes) {
4355
4594
  if (commands.length === 0) {
4356
4595
  assertCompactPayloadFits(6, maxBodyBytes);
4357
- const out = import_node_buffer12.Buffer.allocUnsafe(6);
4596
+ const out = import_node_buffer14.Buffer.allocUnsafe(6);
4358
4597
  writeCompactPipelineHeader(out, 128 | 2, 0);
4359
4598
  return out;
4360
4599
  }
@@ -4396,7 +4635,7 @@ function compactSetPipelinePayload(commands, maxBodyBytes) {
4396
4635
  total += 8 + keyByteLength + valueByteLength;
4397
4636
  }
4398
4637
  assertCompactPayloadFits(total, maxBodyBytes);
4399
- const out = import_node_buffer12.Buffer.allocUnsafe(total);
4638
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4400
4639
  let offset = writeCompactPipelineHeader(out, 128 | 1, commands.length);
4401
4640
  for (let index = 0; index < commands.length; index += 1) {
4402
4641
  offset = writeBinaryValue(out, offset, argumentValues[index * 2], argumentByteLengths[index * 2] ?? 0);
@@ -4431,7 +4670,7 @@ function compactGetPipelinePayload(commands, maxBodyBytes) {
4431
4670
  total += 4 + keyByteLength;
4432
4671
  }
4433
4672
  assertCompactPayloadFits(total, maxBodyBytes);
4434
- const out = import_node_buffer12.Buffer.allocUnsafe(total);
4673
+ const out = import_node_buffer14.Buffer.allocUnsafe(total);
4435
4674
  let offset = writeCompactPipelineHeader(out, 128 | 2, commands.length);
4436
4675
  for (let index = 0; index < commands.length; index += 1) {
4437
4676
  offset = writeBinaryValue(out, offset, keys[index], keyByteLengths[index] ?? 0);
@@ -4445,7 +4684,7 @@ function compactArgumentsEligible(args, sparseMessage) {
4445
4684
  }
4446
4685
  return true;
4447
4686
  }
4448
- function compactPipelineEligible(commands, commandName4, argumentCount) {
4687
+ function compactPipelineEligible(commands, commandName5, argumentCount) {
4449
4688
  for (let index = 0; index < commands.length; index += 1) {
4450
4689
  const command = commands[index];
4451
4690
  if (!Object.hasOwn(commands, index) || !Array.isArray(command)) {
@@ -4457,7 +4696,7 @@ function compactPipelineEligible(commands, commandName4, argumentCount) {
4457
4696
  throw new TypeError("pipeline command arguments must be dense");
4458
4697
  }
4459
4698
  }
4460
- if (!commandNameIs(command[0], commandName4)) return false;
4699
+ if (!commandNameIs(command[0], commandName5)) return false;
4461
4700
  for (let argumentIndex = 1; argumentIndex < argumentCount; argumentIndex += 1) {
4462
4701
  if (!isCompactBinaryScalar(command[argumentIndex])) return false;
4463
4702
  }
@@ -4472,7 +4711,7 @@ function writeCompactPipelineHeader(out, mode, count) {
4472
4711
  }
4473
4712
 
4474
4713
  // src/protocol-kv.ts
4475
- var import_node_buffer13 = require("buffer");
4714
+ var import_node_buffer15 = require("buffer");
4476
4715
  function collectionProtocolCommand(command, args) {
4477
4716
  switch (command) {
4478
4717
  case "CAS":
@@ -4543,8 +4782,8 @@ function stringSetPayload(args) {
4543
4782
  if (value == null || token === "EX" && value > Math.floor(Number.MAX_SAFE_INTEGER / 1e3)) {
4544
4783
  return void 0;
4545
4784
  }
4546
- const field2 = token === "EX" || token === "PX" ? "ttl" : token.toLowerCase();
4547
- 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);
4548
4787
  expirySeen = true;
4549
4788
  index += 2;
4550
4789
  } else if (token === "NX") {
@@ -4643,25 +4882,25 @@ function hashSetCommand(args) {
4643
4882
  if (!isBinaryCommandArgument(args[0]) || args.length < 3 || args.length % 2 !== 1) return void 0;
4644
4883
  const fields = /* @__PURE__ */ Object.create(null);
4645
4884
  for (let index = 1; index < args.length; index += 2) {
4646
- const field2 = args[index];
4885
+ const field3 = args[index];
4647
4886
  const value = args[index + 1];
4648
- if (typeof field2 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4649
- setOwnValue2(fields, field2, value);
4887
+ if (typeof field3 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4888
+ setOwnValue2(fields, field3, value);
4650
4889
  }
4651
4890
  return { opcode: COMMAND_OPCODES.HSET, payload: { fields, key: args[0] } };
4652
4891
  }
4653
4892
  function keyOnlyCommand(opcode, args) {
4654
4893
  return args.length === 1 && isBinaryCommandArgument(args[0]) ? { opcode, payload: { key: args[0] } } : void 0;
4655
4894
  }
4656
- function binaryFieldsCommand(opcode, args, field2, length) {
4895
+ function binaryFieldsCommand(opcode, args, field3, length) {
4657
4896
  if (args.length !== length || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1])) return void 0;
4658
- return { opcode, payload: { [field2]: args[1], key: args[0] } };
4897
+ return { opcode, payload: { [field3]: args[1], key: args[0] } };
4659
4898
  }
4660
- function binaryListCommand(opcode, args, field2) {
4899
+ function binaryListCommand(opcode, args, field3) {
4661
4900
  if (!isBinaryCommandArgument(args[0]) || args.length < 2) return void 0;
4662
4901
  const values = args.slice(1);
4663
4902
  if (!values.every(isBinaryCommandArgument)) return void 0;
4664
- return { opcode, payload: { [field2]: values, key: args[0] } };
4903
+ return { opcode, payload: { [field3]: values, key: args[0] } };
4665
4904
  }
4666
4905
  function listPopCommand(opcode, args) {
4667
4906
  if (!isBinaryCommandArgument(args[0]) || args.length !== 1 && args.length !== 2) return void 0;
@@ -4719,17 +4958,35 @@ function parsedNumber(value) {
4719
4958
  }
4720
4959
  }
4721
4960
  function isBinaryCommandArgument(value) {
4722
- return typeof value === "string" || import_node_buffer13.Buffer.isBuffer(value);
4961
+ return typeof value === "string" || import_node_buffer15.Buffer.isBuffer(value);
4723
4962
  }
4724
4963
  function isDirectKvValueArgument(value) {
4725
4964
  return isBinaryCommandArgument(value) || typeof value === "object" && value != null;
4726
4965
  }
4727
4966
  function binaryToken(value) {
4728
- return typeof value === "string" ? value.toUpperCase() : import_node_buffer13.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);
4729
4987
  }
4730
4988
 
4731
4989
  // src/protocol-value.ts
4732
- var import_node_buffer14 = require("buffer");
4733
4990
  function planValueWithLimit(value, maxBytes) {
4734
4991
  const budget = {
4735
4992
  maxBytes,
@@ -4784,7 +5041,7 @@ function planContainerValue(value, budget, ancestors, depth) {
4784
5041
  let byteLength = 5;
4785
5042
  let index = 0;
4786
5043
  for (const [key, item] of entries) {
4787
- const keyByteLength = import_node_buffer14.Buffer.byteLength(key);
5044
+ const keyByteLength = import_node_buffer17.Buffer.byteLength(key);
4788
5045
  consumeEncodeBytes(budget, 4 + keyByteLength);
4789
5046
  const valuePlan = planValueAt(item, budget, ancestors, depth + 1);
4790
5047
  entryPlans[index] = { key, keyByteLength, value: valuePlan };
@@ -4823,17 +5080,21 @@ function planScalarValue(value, budget) {
4823
5080
  return { byteLength: 9, tag: 3, value: BigInt(value) };
4824
5081
  }
4825
5082
  if (typeof value === "bigint") {
4826
- if (value < MIN_I64 || value > MAX_I64) {
4827
- 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 };
4828
5086
  }
4829
- consumeEncodeBytes(budget, 9);
4830
- 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");
4831
5092
  }
4832
5093
  if (typeof value === "number") {
4833
5094
  consumeEncodeBytes(budget, 9);
4834
5095
  return { byteLength: 9, tag: 7, value };
4835
5096
  }
4836
- if (typeof value === "string" || import_node_buffer14.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5097
+ if (typeof value === "string" || import_node_buffer17.Buffer.isBuffer(value) || value instanceof Uint8Array) {
4837
5098
  const valueByteLength = binaryValueByteLength(value);
4838
5099
  const byteLength = 5 + valueByteLength;
4839
5100
  consumeEncodeBytes(budget, byteLength);
@@ -4857,7 +5118,7 @@ function writeValuePlan(output, start, plan) {
4857
5118
  offset += 4;
4858
5119
  if (typeof plan.value === "string") {
4859
5120
  output.write(plan.value, offset, plan.valueByteLength, "utf8");
4860
- } else if (import_node_buffer14.Buffer.isBuffer(plan.value)) {
5121
+ } else if (import_node_buffer17.Buffer.isBuffer(plan.value)) {
4861
5122
  plan.value.copy(output, offset);
4862
5123
  } else {
4863
5124
  output.set(plan.value, offset);
@@ -4882,6 +5143,9 @@ function writeValuePlan(output, start, plan) {
4882
5143
  case 7:
4883
5144
  output.writeDoubleBE(plan.value, offset);
4884
5145
  return offset + 8;
5146
+ case 8:
5147
+ output.writeBigUInt64BE(plan.value, offset);
5148
+ return offset + 8;
4885
5149
  }
4886
5150
  }
4887
5151
  function consumeEncodeBytes(budget, bytes2) {
@@ -4939,7 +5203,7 @@ function decodeValueAt(data, offset, limits, budget, depth) {
4939
5203
  const key = readBinary(data, offset);
4940
5204
  offset = key.offset;
4941
5205
  const item = decodeValueAt(data, offset, limits, budget, depth + 1);
4942
- setOwnValue2(value, key.value.toString("utf8"), item.value);
5206
+ setProtocolMapEntry(value, key.value, item.value);
4943
5207
  offset = item.offset;
4944
5208
  }
4945
5209
  return { value, offset };
@@ -4948,6 +5212,14 @@ function decodeValueAt(data, offset, limits, budget, depth) {
4948
5212
  requireAvailable(data, offset, 8);
4949
5213
  return { value: data.readDoubleBE(offset), offset: offset + 8 };
4950
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
+ }
4951
5223
  throw new FerricStoreError(`unknown protocol value tag ${tag}`);
4952
5224
  }
4953
5225
  function decodeValueWithBudget(data, offset, budget) {
@@ -4991,20 +5263,20 @@ function requireAvailable(data, offset, size) {
4991
5263
  }
4992
5264
 
4993
5265
  // src/key-slot-validation.ts
4994
- var import_node_buffer16 = require("buffer");
5266
+ var import_node_buffer19 = require("buffer");
4995
5267
 
4996
5268
  // src/topology-utilities.ts
4997
- var import_node_buffer15 = require("buffer");
5269
+ var import_node_buffer18 = require("buffer");
4998
5270
  function isPlainObject3(value) {
4999
- return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer15.Buffer.isBuffer(value);
5271
+ return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer18.Buffer.isBuffer(value);
5000
5272
  }
5001
5273
  function getField(source, ...keys) {
5002
5274
  if (source instanceof Map) {
5003
5275
  for (const key of keys) {
5004
5276
  if (source.has(key)) return source.get(key);
5005
- const bufferKey = import_node_buffer15.Buffer.from(key);
5277
+ const bufferKey = import_node_buffer18.Buffer.from(key);
5006
5278
  for (const [itemKey, value] of source.entries()) {
5007
- if (import_node_buffer15.Buffer.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
5279
+ if (import_node_buffer18.Buffer.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
5008
5280
  }
5009
5281
  }
5010
5282
  return void 0;
@@ -5018,14 +5290,14 @@ function getField(source, ...keys) {
5018
5290
  }
5019
5291
  function textOrUndefined(value) {
5020
5292
  if (typeof value === "string") return value;
5021
- if (import_node_buffer15.Buffer.isBuffer(value)) return value.toString("utf8");
5293
+ if (import_node_buffer18.Buffer.isBuffer(value)) return value.toString("utf8");
5022
5294
  return void 0;
5023
5295
  }
5024
5296
  function numberOrUndefined(value) {
5025
5297
  return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
5026
5298
  }
5027
- function nativeEventName(event) {
5028
- return textOrUndefined(getField(event.value, "event"))?.toUpperCase();
5299
+ function nativeEventName(event2) {
5300
+ return textOrUndefined(getField(event2.value, "event"))?.toUpperCase();
5029
5301
  }
5030
5302
  function endpointFromRange(item) {
5031
5303
  const endpointValue = getField(item, "endpoint");
@@ -5193,7 +5465,7 @@ function stringHashRange(key) {
5193
5465
  var validatedCommands = /* @__PURE__ */ new WeakSet();
5194
5466
  function assertAtomicKeyValueCommandSharesSlot(args) {
5195
5467
  const value = args[0];
5196
- const command = (typeof value === "string" ? value : import_node_buffer16.Buffer.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5468
+ const command = (typeof value === "string" ? value : import_node_buffer19.Buffer.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5197
5469
  if (command === "MSET" || command === "MSETNX") {
5198
5470
  assertKeyValueCommandSharesSlot(args, command);
5199
5471
  }
@@ -5203,7 +5475,7 @@ function assertKeyValueCommandSharesSlot(args, command) {
5203
5475
  let expectedSlot;
5204
5476
  for (let index = 1; index < args.length; index += 2) {
5205
5477
  const key = args[index];
5206
- if (typeof key !== "string" && !import_node_buffer16.Buffer.isBuffer(key)) return;
5478
+ if (typeof key !== "string" && !import_node_buffer19.Buffer.isBuffer(key)) return;
5207
5479
  const slot = routingSlotForKey(key);
5208
5480
  expectedSlot ??= slot;
5209
5481
  if (slot !== expectedSlot) {
@@ -5214,62 +5486,202 @@ function assertKeyValueCommandSharesSlot(args, command) {
5214
5486
  }
5215
5487
 
5216
5488
  // src/protocol-response.ts
5217
- var import_node_buffer20 = require("buffer");
5489
+ var import_node_buffer26 = require("buffer");
5218
5490
 
5219
5491
  // src/protocol-compact-response.ts
5220
- var import_node_buffer19 = require("buffer");
5492
+ var import_node_buffer25 = require("buffer");
5221
5493
 
5222
5494
  // src/native-negotiation.ts
5223
- var import_node_buffer17 = require("buffer");
5495
+ var import_node_buffer20 = require("buffer");
5224
5496
  var EMPTY_COMPACT_RESPONSE_OPCODES = /* @__PURE__ */ new Map();
5225
5497
  function nativeNegotiation(value) {
5226
5498
  const capabilities = field(value, "capabilities") ?? value;
5227
5499
  const limits = field(capabilities, "limits");
5228
- 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");
5229
5503
  const maxResponseBytes = positiveSafeInteger3(field(limits, "max_response_bytes"));
5230
5504
  return {
5231
5505
  compactResponseOpcodes: parseCompactResponseOpcodes(
5232
5506
  field(responseCodecs, "compact_response_opcodes")
5233
5507
  ),
5508
+ flowQuery: parseFlowQueryNegotiation(capabilities, schemas),
5234
5509
  ...maxResponseBytes == null ? {} : { maxResponseBytes }
5235
5510
  };
5236
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
+ }
5237
5628
  function compactResponseOpcodeSupports(capabilities, codec, opcode) {
5238
5629
  return capabilities?.get(codec)?.has(opcode) === true;
5239
5630
  }
5240
5631
  function parseCompactResponseOpcodes(value) {
5632
+ if (value == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
5241
5633
  const entries = mapEntries(value);
5242
- 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
+ }
5243
5640
  const result = /* @__PURE__ */ new Map();
5641
+ let totalOpcodes = 0;
5244
5642
  for (const [rawName, rawOpcodes] of entries) {
5245
- const name = text2(rawName);
5246
- if (name == null || name.length === 0 || !Array.isArray(rawOpcodes)) continue;
5247
- const opcodes = /* @__PURE__ */ new Set();
5248
- let valid = true;
5249
- for (let index = 0; index < rawOpcodes.length; index += 1) {
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
+ }
5657
+ const opcodes = /* @__PURE__ */ new Set();
5658
+ for (let index = 0; index < rawOpcodes.length; index += 1) {
5250
5659
  if (!Object.hasOwn(rawOpcodes, index)) {
5251
- valid = false;
5252
- break;
5660
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} must be dense`);
5253
5661
  }
5254
- const opcode = unsigned16(rawOpcodes[index]);
5662
+ const opcode = strictUnsigned16(rawOpcodes[index]);
5255
5663
  if (opcode == null) {
5256
- valid = false;
5257
- 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`);
5258
5668
  }
5259
5669
  opcodes.add(opcode);
5260
5670
  }
5261
- if (valid) result.set(name, opcodes);
5671
+ result.set(name, opcodes);
5262
5672
  }
5263
5673
  return result;
5264
5674
  }
5265
5675
  function mapEntries(value) {
5266
5676
  if (value instanceof Map) return [...value.entries()];
5267
- 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;
5268
5678
  return Object.entries(value);
5269
5679
  }
5270
- function unsigned16(value) {
5271
- const parsed = nonNegativeSafeInteger2(value);
5272
- 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;
5273
5685
  }
5274
5686
  function positiveSafeInteger3(value) {
5275
5687
  const parsed = nonNegativeSafeInteger2(value);
@@ -5288,14 +5700,14 @@ function nonNegativeSafeInteger2(value) {
5288
5700
  }
5289
5701
  function text2(value) {
5290
5702
  if (typeof value === "string") return value;
5291
- if (import_node_buffer17.Buffer.isBuffer(value) || value instanceof Uint8Array) {
5292
- return import_node_buffer17.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");
5293
5705
  }
5294
5706
  return void 0;
5295
5707
  }
5296
5708
 
5297
5709
  // src/protocol-compact-collections.ts
5298
- var import_node_buffer18 = require("buffer");
5710
+ var import_node_buffer21 = require("buffer");
5299
5711
  function decodeCompactIntegerList(data, budget) {
5300
5712
  requireAvailable(data, 0, 5);
5301
5713
  const count = data.readUInt32BE(1);
@@ -5360,7 +5772,7 @@ function readCompactBinaryMap(data, offset, budget) {
5360
5772
  for (let index = 0; index < count; index += 1) {
5361
5773
  const key = readBinary(data, offset);
5362
5774
  const value = readBinary(data, key.offset);
5363
- setOwnValue2(values, key.value.toString("utf8"), value.value);
5775
+ setProtocolMapEntry(values, key.value, value.value);
5364
5776
  offset = value.offset;
5365
5777
  }
5366
5778
  return { value: values, offset };
@@ -5376,11 +5788,246 @@ function requireCompactContainer(count, budget) {
5376
5788
  consumeDecodeItems(count, budget);
5377
5789
  }
5378
5790
 
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);
5804
+ }
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);
5812
+ }
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;
5842
+ }
5843
+ if (!isDecodedRecord(value)) return value;
5844
+ for (const key of Object.keys(value)) {
5845
+ setOwnValue2(value, key, detachDecodedBinary(value[key], backingBytes));
5846
+ }
5847
+ return value;
5848
+ }
5849
+ function detachBuffer(value, backingBytes) {
5850
+ if (backingBytes <= Math.max(MIN_PINNED_BACKING_BYTES, value.byteLength * 2)) {
5851
+ return value;
5852
+ }
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
+
5379
6025
  // src/protocol-compact-response.ts
5380
6026
  function tryDecodeCompactResponse(opcode, body, hints) {
5381
6027
  if (body.byteLength === 0) return { found: false, value: void 0 };
5382
6028
  const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
5383
6029
  const tag = body.readUInt8(0);
6030
+ validateCompactResponseItems(tag, opcode, body, hints);
5384
6031
  const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
5385
6032
  if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
5386
6033
  const values = decodeCompactOkList(body, budget);
@@ -5431,6 +6078,9 @@ function tryDecodeCompactResponse(opcode, body, hints) {
5431
6078
  value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(read.value) : read.value
5432
6079
  };
5433
6080
  }
6081
+ if (tag === COMPACT_FLOW_QUERY_RESULT && supports(hints, "flow_query_result_v1", opcode)) {
6082
+ return { found: true, value: decodeCompactFlowQueryResult(body, budget) };
6083
+ }
5434
6084
  return { found: false, value: void 0 };
5435
6085
  }
5436
6086
  function supports(hints, codec, opcode) {
@@ -5441,7 +6091,7 @@ function decodeCompactOkList(data, budget) {
5441
6091
  const count = data.readUInt32BE(1);
5442
6092
  requireCompactContainer2(count, budget);
5443
6093
  if (data.byteLength !== 5) throw new FerricStoreError("invalid compact OK list response");
5444
- return Array.from({ length: count }, () => import_node_buffer19.Buffer.from("OK"));
6094
+ return Array.from({ length: count }, () => import_node_buffer25.Buffer.from("OK"));
5445
6095
  }
5446
6096
  function decodeCompactKvGet(data) {
5447
6097
  requireAvailable(data, 0, 2);
@@ -5487,7 +6137,7 @@ function decodeCompactMgetFixed(data, budget) {
5487
6137
  if (size === NULL_U32 || data.byteLength !== expected) {
5488
6138
  throw new FerricStoreError("invalid compact fixed MGET response");
5489
6139
  }
5490
- if (size === 0) return new Array(count).fill(import_node_buffer19.Buffer.alloc(0));
6140
+ if (size === 0) return new Array(count).fill(import_node_buffer25.Buffer.alloc(0));
5491
6141
  const values = new Array(count);
5492
6142
  for (let index = 0, offset = 9; index < count; index += 1, offset += size) {
5493
6143
  values[index] = data.subarray(offset, offset + size);
@@ -5548,7 +6198,7 @@ function decodeCompactPipeline(data, budget, claimModes) {
5548
6198
  const read = readBinary(data, offset);
5549
6199
  const errorStatus = status === 1 ? "busy" : "error";
5550
6200
  values[index] = classifyServerError(
5551
- errorMessage(status === 1 ? 4 : 1, read.value),
6201
+ protocolErrorMessage(status === 1 ? 4 : 1, read.value),
5552
6202
  read.value,
5553
6203
  void 0,
5554
6204
  errorStatus
@@ -5658,13 +6308,13 @@ function readCompactFlowRecord(data, offset, budget = { remainingItems: DEFAULT_
5658
6308
  let key;
5659
6309
  if (keyId === 0) {
5660
6310
  const read2 = readBinary(data, offset);
5661
- key = read2.value.toString("utf8");
6311
+ key = read2.value;
5662
6312
  offset = read2.offset;
5663
6313
  } else {
5664
6314
  key = FLOW_RECORD_FIELD_KEYS[keyId] ?? `field_${keyId}`;
5665
6315
  }
5666
6316
  const read = decodeValueWithBudget(data, offset, budget);
5667
- setOwnValue2(record, key, read.value);
6317
+ setProtocolMapEntry(record, key, read.value);
5668
6318
  offset = read.offset;
5669
6319
  }
5670
6320
  return { value: record, offset };
@@ -5700,15 +6350,29 @@ function requireCompactContainer2(count, budget) {
5700
6350
  }
5701
6351
  consumeDecodeItems(count, budget);
5702
6352
  }
5703
- function errorMessage(status, value) {
5704
- if (typeof value === "string") return value;
5705
- if (import_node_buffer19.Buffer.isBuffer(value)) return value.toString("utf8");
5706
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5707
- const message = value.message;
5708
- 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
+ );
5709
6363
  }
5710
- return `ERR native request failed status=${status}: ${String(value)}`;
5711
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
+ ]);
5712
6376
 
5713
6377
  // src/protocol-response.ts
5714
6378
  function decodeResponse(frame, expectedOpcode, hints = {}) {
@@ -5726,9 +6390,16 @@ function decodeResponse(frame, expectedOpcode, hints = {}) {
5726
6390
  }
5727
6391
  const status = frame.body.readUInt16BE(0);
5728
6392
  const body = frame.body.subarray(2);
5729
- 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
+ );
5730
6401
  if (status === STATUS_OK) return value;
5731
- const message = errorMessage2(status, value);
6402
+ const message = protocolErrorMessage(status, value);
5732
6403
  throw classifyServerError(message, value, void 0, status);
5733
6404
  }
5734
6405
  function unwrapPipelineResponse(value, options = {}, expectedItems) {
@@ -5767,7 +6438,7 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5767
6438
  continue;
5768
6439
  }
5769
6440
  const error = classifyServerError(
5770
- errorMessage2(status === "busy" ? 4 : 1, payload),
6441
+ protocolErrorMessage(status === "busy" ? 4 : 1, payload),
5771
6442
  payload,
5772
6443
  void 0,
5773
6444
  status
@@ -5782,28 +6453,24 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5782
6453
  return out;
5783
6454
  }
5784
6455
  function pipelineStatus(value) {
5785
- if (typeof value !== "string" && !import_node_buffer20.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return null;
6456
+ if (typeof value !== "string" && !import_node_buffer26.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return null;
5786
6457
  const status = asText(value).toLowerCase();
5787
6458
  return status === "ok" || status === "busy" || status === "error" ? status : null;
5788
6459
  }
5789
- function decodeResponseValue(opcode, body, hints) {
5790
- const compact = tryDecodeCompactResponse(opcode, body, hints);
5791
- 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
+ }
5792
6468
  const decoded = decodeValue(body);
5793
6469
  if (decoded.offset !== body.byteLength) {
5794
6470
  throw new FerricStoreError("native protocol response has trailing bytes", { raw: body });
5795
6471
  }
5796
6472
  return decoded.value;
5797
6473
  }
5798
- function errorMessage2(status, value) {
5799
- if (typeof value === "string") return value;
5800
- if (import_node_buffer20.Buffer.isBuffer(value)) return value.toString("utf8");
5801
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5802
- const message = value.message;
5803
- return typeof message === "string" ? message : String(message);
5804
- }
5805
- return `ERR native request failed status=${status}: ${String(value)}`;
5806
- }
5807
6474
 
5808
6475
  // src/protocol.ts
5809
6476
  function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
@@ -5813,7 +6480,7 @@ function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGE
5813
6480
  const bodyLength = customPayload ? binaryValueByteLength(command.payload) : plan?.byteLength ?? 0;
5814
6481
  if (bodyLength > bodyLimit) throw requestFrameTooLarge(bodyLimit);
5815
6482
  const flags = command.flags ?? 0;
5816
- const frame = import_node_buffer21.Buffer.allocUnsafe(HEADER_SIZE + bodyLength);
6483
+ const frame = import_node_buffer27.Buffer.allocUnsafe(HEADER_SIZE + bodyLength);
5817
6484
  frame.write(MAGIC, 0, "ascii");
5818
6485
  frame.writeUInt8(REQUEST_VERSION, 4);
5819
6486
  frame.writeUInt8(flags, 5);
@@ -5914,18 +6581,18 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5914
6581
  }
5915
6582
  if (command === "SET" && commandArgs2.length >= 2) {
5916
6583
  const payload = stringSetPayload(commandArgs2);
5917
- return payload == null ? commandExec(args) : { opcode: OPCODES.set, payload };
6584
+ return payload == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.set, payload };
5918
6585
  }
5919
6586
  if (command === "MGET" && commandArgs2.length > 0) {
5920
6587
  const compact = allowCustomPayload ? compactKeyPipelinePayload(OPCODES.mget, commandArgs2, 2, maxBodyBytes) : void 0;
5921
- if (compact != null) return compact;
5922
- 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);
5923
6590
  }
5924
6591
  if (command === "MSET" && commandArgs2.length >= 2 && commandArgs2.length % 2 === 0) {
5925
6592
  const compact = allowCustomPayload ? compactMsetPayload(commandArgs2, maxBodyBytes) : void 0;
5926
- if (compact != null) return compact;
6593
+ if (compact != null) return { ...compact, compactResponseItems: 1 };
5927
6594
  const pairs = typedKeyValuePairs(commandArgs2);
5928
- return pairs == null ? commandExec(args) : { opcode: OPCODES.mset, payload: { pairs } };
6595
+ return pairs == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.mset, payload: { pairs } };
5929
6596
  }
5930
6597
  if (command === "DEL" && commandArgs2.length > 0) {
5931
6598
  return commandArgs2.every(isBinaryCommandArgument) ? { opcode: OPCODES.del, payload: { keys: commandArgs2 } } : commandExec(args);
@@ -5935,8 +6602,14 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5935
6602
  if (command === "FLOW.HISTORY") {
5936
6603
  return flowHistoryPayload(commandArgs2) ?? commandExec(args);
5937
6604
  }
5938
- if (command === "FLOW.LIST") {
5939
- return (allowCustomPayload ? compactFlowListPayload(commandArgs2, maxBodyBytes) : void 0) ?? commandExec(args);
6605
+ if (command === "FLOW.QUERY") {
6606
+ return { opcode: OPCODES.flowQuery, payload: flowQueryPayload(commandArgs2) };
6607
+ }
6608
+ if (command === "FLOW.POLICY.SET") {
6609
+ return flowPolicySetPayload(commandArgs2) ?? commandExec(args);
6610
+ }
6611
+ if (command === "FLOW.POLICY.GET") {
6612
+ return flowPolicyGetPayload(commandArgs2) ?? commandExec(args);
5940
6613
  }
5941
6614
  const flowAdmin = FLOW_ADMIN_COMMANDS[command];
5942
6615
  if (flowAdmin != null) {
@@ -6089,24 +6762,17 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
6089
6762
  if (command === "FLOW.RUN_STEPS_MANY") {
6090
6763
  return flowAdminPayload(OPCODES.flowRunStepsMany, commandArgs2) ?? commandExec(args);
6091
6764
  }
6092
- if (command === "FLOW.SEARCH") {
6093
- if (hasFlowCommandOnlyOption(command, commandArgs2)) {
6094
- const fallback = commandExec(args);
6095
- try {
6096
- const parsed = flowSearchPayload(commandArgs2);
6097
- return parsed == null ? fallback : withFlowPartitionRouting(fallback, parsed.payload);
6098
- } catch {
6099
- return fallback;
6100
- }
6101
- }
6102
- return flowSearchPayload(commandArgs2) ?? commandExec(args);
6103
- }
6104
6765
  return commandExec(args);
6105
6766
  }
6106
6767
  function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6107
6768
  const compact = compactPipelinePayload(commands, maxBodyBytes);
6108
6769
  if (compact != null) {
6109
- 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
+ };
6110
6776
  }
6111
6777
  const protocols = new Array(commands.length);
6112
6778
  for (let index = 0; index < commands.length; index += 1) {
@@ -6145,6 +6811,7 @@ function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6145
6811
  const pipelineClaimModes = pipelineProtocols.map((protocol) => protocol.compactClaimMode);
6146
6812
  const hasPipelineClaimMode = pipelineClaimModes.some((mode) => mode != null);
6147
6813
  return {
6814
+ compactResponseItems: commands.length,
6148
6815
  opcode: OPCODES.pipeline,
6149
6816
  payload: {
6150
6817
  atomicity: "none",
@@ -6193,7 +6860,7 @@ var import_node_net2 = require("net");
6193
6860
  var import_node_tls2 = require("tls");
6194
6861
 
6195
6862
  // src/client-native-options.ts
6196
- var import_node_buffer22 = require("buffer");
6863
+ var import_node_buffer28 = require("buffer");
6197
6864
 
6198
6865
  // src/string-array-snapshot.ts
6199
6866
  function snapshotOwnStringArray(values, name) {
@@ -6276,7 +6943,7 @@ function snapshotTlsOptions(options) {
6276
6943
  return Object.freeze(snapshot);
6277
6944
  }
6278
6945
  function snapshotTlsValue(value, name) {
6279
- if (import_node_buffer22.Buffer.isBuffer(value)) return import_node_buffer22.Buffer.from(value);
6946
+ if (import_node_buffer28.Buffer.isBuffer(value)) return import_node_buffer28.Buffer.from(value);
6280
6947
  if (value instanceof Uint8Array) return value.slice();
6281
6948
  if (Array.isArray(value)) {
6282
6949
  const snapshot = new Array(value.length);
@@ -6831,7 +7498,7 @@ var NativeChunkAssembler = class {
6831
7498
  };
6832
7499
 
6833
7500
  // src/native-response-handler.ts
6834
- var import_node_buffer23 = require("buffer");
7501
+ var import_node_buffer29 = require("buffer");
6835
7502
 
6836
7503
  // src/native-receive-buffer.ts
6837
7504
  var FRAME_ASSEMBLY_PAGE_BYTES = 64 * 1024;
@@ -7131,7 +7798,7 @@ var NativeResponseHandler = class {
7131
7798
  compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
7132
7799
  });
7133
7800
  if (frame.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
7134
- const event = {
7801
+ const event2 = {
7135
7802
  flags: frame.flags,
7136
7803
  laneId: frame.laneId,
7137
7804
  opcode: frame.opcode,
@@ -7139,7 +7806,7 @@ var NativeResponseHandler = class {
7139
7806
  };
7140
7807
  if (frame.opcode === OPCODES.goaway) this.options.beginDraining();
7141
7808
  try {
7142
- const callback = this.options.onEvent?.(event);
7809
+ const callback = this.options.onEvent?.(event2);
7143
7810
  if (callback != null) void Promise.resolve(callback).catch(() => void 0);
7144
7811
  } catch {
7145
7812
  }
@@ -7166,7 +7833,7 @@ var NativeRequestScheduler = class {
7166
7833
  };
7167
7834
 
7168
7835
  // src/native-write-queue.ts
7169
- var import_node_buffer24 = require("buffer");
7836
+ var import_node_buffer30 = require("buffer");
7170
7837
  var NativeWriteQueue = class {
7171
7838
  constructor(socket, maxQueuedWriteBytes, isClosed, hasPending, rejectPending) {
7172
7839
  this.socket = socket;
@@ -7303,12 +7970,14 @@ var NativeConnectionCapabilities = class {
7303
7970
  }
7304
7971
  configuredRequestFrameBytes;
7305
7972
  compactResponseOpcodes = EMPTY_COMPACT_RESPONSE_OPCODES;
7973
+ flowQuery;
7306
7974
  requestFrameBytes;
7307
7975
  negotiatedRequestFrameBytes;
7308
7976
  apply(value) {
7309
7977
  const limits = startupLimits(value);
7310
7978
  const negotiation = nativeNegotiation(value);
7311
7979
  this.compactResponseOpcodes = negotiation.compactResponseOpcodes;
7980
+ this.flowQuery = negotiation.flowQuery;
7312
7981
  if (limits.frameBytes != null) {
7313
7982
  this.negotiatedRequestFrameBytes = Math.min(
7314
7983
  this.configuredRequestFrameBytes,
@@ -7328,6 +7997,19 @@ var NativeConnectionCapabilities = class {
7328
7997
  }
7329
7998
  };
7330
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
+
7331
8013
  // src/native-adapter.ts
7332
8014
  var NativeAdapter = class _NativeAdapter {
7333
8015
  socket;
@@ -7486,13 +8168,7 @@ var NativeAdapter = class _NativeAdapter {
7486
8168
  const response = await this.request({
7487
8169
  laneId: 0,
7488
8170
  opcode: OPCODES.startup,
7489
- payload: {
7490
- client_name: clientName ?? "ferricstore-typescript",
7491
- compact_flow_responses: true,
7492
- compression: "none",
7493
- driver_name: clientName ?? "ferricstore-typescript",
7494
- ...events == null || events.length === 0 ? {} : { events: [...events] }
7495
- }
8171
+ payload: nativeStartupPayload(clientName, events)
7496
8172
  });
7497
8173
  this.applyStartupLimits(response);
7498
8174
  const authRequired = field(response, "auth_required");
@@ -7552,6 +8228,7 @@ var NativeAdapter = class _NativeAdapter {
7552
8228
  if (!hasFlowControlCredit) this.pendingControlRequests += 1;
7553
8229
  this.pending.set(requestId, {
7554
8230
  ...command.compactClaimMode == null ? {} : { compactClaimMode: command.compactClaimMode },
8231
+ ...command.compactResponseItems == null ? {} : { compactResponseItems: command.compactResponseItems },
7555
8232
  hasFlowControlCredit,
7556
8233
  indefinite: timeoutMs == null,
7557
8234
  laneId,
@@ -7683,7 +8360,30 @@ function executeCommandArgs(executor, args) {
7683
8360
  }
7684
8361
 
7685
8362
  // src/reconnecting-executor.ts
7686
- var import_node_buffer26 = require("buffer");
8363
+ var import_node_buffer33 = require("buffer");
8364
+
8365
+ // src/command-retry-policy.ts
8366
+ var import_node_buffer32 = require("buffer");
8367
+ function isCasMutation(args) {
8368
+ const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
8369
+ const name = commandName2(args[offset]);
8370
+ if (name === "CAS") return true;
8371
+ if (name !== "FLOW.POLICY.SET") return false;
8372
+ for (let index = offset + 2; index < args.length; index += 2) {
8373
+ if (!Object.hasOwn(args, index)) return false;
8374
+ if (commandName2(args[index]) === "EXPECTED_GENERATION") return true;
8375
+ }
8376
+ return false;
8377
+ }
8378
+ function commandName2(value) {
8379
+ if (typeof value === "string") return value.toUpperCase();
8380
+ if (import_node_buffer32.Buffer.isBuffer(value) || value instanceof Uint8Array) {
8381
+ return import_node_buffer32.Buffer.from(value).toString("utf8").toUpperCase();
8382
+ }
8383
+ return void 0;
8384
+ }
8385
+
8386
+ // src/reconnecting-executor.ts
7687
8387
  var ReconnectingExecutor = class {
7688
8388
  constructor(createExecutor, options = {}) {
7689
8389
  this.createExecutor = createExecutor;
@@ -7714,7 +8414,12 @@ var ReconnectingExecutor = class {
7714
8414
  async executeCommandArgs(args) {
7715
8415
  const snapshot = snapshotCommandArguments(args);
7716
8416
  assertCommandHasStableConnectionState(snapshot);
7717
- return await this.withReconnect((executor) => executeCommandArgs(executor, snapshot));
8417
+ const casMutation = isCasMutation(snapshot);
8418
+ return await this.withReconnect(
8419
+ (executor) => executeCommandArgs(executor, snapshot),
8420
+ casMutation ? isClosedConnectionError : isReconnectableClosedConnectionError,
8421
+ !casMutation
8422
+ );
7718
8423
  }
7719
8424
  async ready() {
7720
8425
  await this.executorPromise;
@@ -7799,7 +8504,7 @@ var ReconnectingExecutor = class {
7799
8504
  })();
7800
8505
  await this.closePromise;
7801
8506
  }
7802
- async withReconnect(operation, reconnectable = isReconnectableClosedConnectionError) {
8507
+ async withReconnect(operation, reconnectable = isReconnectableClosedConnectionError, replayAllowed = true) {
7803
8508
  let executor = await this.executorPromise;
7804
8509
  let retries = 0;
7805
8510
  for (; ; ) {
@@ -7808,6 +8513,10 @@ var ReconnectingExecutor = class {
7808
8513
  return await operation(executor);
7809
8514
  } catch (error) {
7810
8515
  if (this.closed || retries >= this.maxRetries || !reconnectable(error)) throw error;
8516
+ if (!replayAllowed) {
8517
+ await this.reconnect(executor).catch(() => void 0);
8518
+ throw error;
8519
+ }
7811
8520
  for (; ; ) {
7812
8521
  retries += 1;
7813
8522
  try {
@@ -7860,6 +8569,9 @@ var ReconnectingExecutor = class {
7860
8569
  function isReconnectableClosedConnectionError(error) {
7861
8570
  return error instanceof ConnectionClosedError && error.requestDisposition === "unsent";
7862
8571
  }
8572
+ function isClosedConnectionError(error) {
8573
+ return error instanceof ConnectionClosedError;
8574
+ }
7863
8575
  function isReadOnlyReconnectableClosedConnectionError(error) {
7864
8576
  const pending = [error];
7865
8577
  const seen = /* @__PURE__ */ new Set();
@@ -7878,19 +8590,91 @@ function normalizeNonNegativeInteger2(value, fallback) {
7878
8590
  }
7879
8591
 
7880
8592
  // src/topology.ts
7881
- var import_node_buffer28 = require("buffer");
8593
+ var import_node_buffer36 = require("buffer");
7882
8594
 
7883
8595
  // src/topology-routing.ts
7884
- var import_node_buffer27 = require("buffer");
8596
+ var import_node_buffer35 = require("buffer");
8597
+
8598
+ // src/flow-partition-route-cache.ts
8599
+ var import_node_buffer34 = require("buffer");
7885
8600
  var import_node_crypto = require("crypto");
7886
- var FLOW_PARTITION_ROUTE_CACHE_MAX = 1024;
7887
- 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
7888
8672
  function routingKeyFromProtocolPayload(name, command) {
7889
8673
  if (command.opcode < 256 || name === "CLUSTER.KEYSLOT" || name === "SHARDS" || name === "ROUTE") {
7890
8674
  return void 0;
7891
8675
  }
7892
8676
  if (isPlainObject3(command.payload)) {
7893
- for (const field2 of [
8677
+ for (const field3 of [
7894
8678
  "key",
7895
8679
  "partition_key",
7896
8680
  "id",
@@ -7900,8 +8684,8 @@ function routingKeyFromProtocolPayload(name, command) {
7900
8684
  "correlation_id",
7901
8685
  "scope"
7902
8686
  ]) {
7903
- const value = getField(command.payload, field2);
7904
- if (typeof value === "string" || import_node_buffer27.Buffer.isBuffer(value)) {
8687
+ const value = getField(command.payload, field3);
8688
+ if (typeof value === "string" || import_node_buffer35.Buffer.isBuffer(value)) {
7905
8689
  return value;
7906
8690
  }
7907
8691
  }
@@ -7935,6 +8719,7 @@ function flowRoutingData(name, args) {
7935
8719
  if (flowScheduleCommands.has(name)) {
7936
8720
  return void 0;
7937
8721
  }
8722
+ if (name === "FLOW.QUERY") return void 0;
7938
8723
  if (flowApprovalIdCommands.has(name)) {
7939
8724
  const id = flowArgs[0];
7940
8725
  return flowRoutingResult(flowLogicalPartitionRoutingKey(id));
@@ -7948,7 +8733,7 @@ function flowRoutingData(name, args) {
7948
8733
  if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
7949
8734
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
7950
8735
  }
7951
- if (import_node_buffer27.Buffer.isBuffer(partition)) {
8736
+ if (import_node_buffer35.Buffer.isBuffer(partition)) {
7952
8737
  const text3 = partition.toString("utf8").toUpperCase();
7953
8738
  if (text3 !== "AUTO" && text3 !== "MIXED") {
7954
8739
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
@@ -8039,46 +8824,17 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
8039
8824
  return { handled: false };
8040
8825
  }
8041
8826
  function isRoutingKey(value) {
8042
- return typeof value === "string" || import_node_buffer27.Buffer.isBuffer(value);
8043
- }
8044
- function flowLogicalPartitionRoutingKey(value) {
8045
- if (typeof value !== "string" && !import_node_buffer27.Buffer.isBuffer(value)) {
8046
- return void 0;
8047
- }
8048
- const bytes2 = import_node_buffer27.Buffer.isBuffer(value) ? value : import_node_buffer27.Buffer.from(value);
8049
- const text3 = bytes2.toString("utf8");
8050
- const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(text3);
8051
- if (autoMatch != null) {
8052
- const bucket = Number(autoMatch[1]);
8053
- if (bucket < 256) {
8054
- return `{fa:${bucket}}`;
8055
- }
8056
- }
8057
- const cacheKey = `${import_node_buffer27.Buffer.isBuffer(value) ? "b" : "s"}:${bytes2.toString("base64")}`;
8058
- const cached = flowPartitionRouteCache.get(cacheKey);
8059
- if (cached != null) {
8060
- flowPartitionRouteCache.delete(cacheKey);
8061
- flowPartitionRouteCache.set(cacheKey, cached);
8062
- return cached;
8063
- }
8064
- const digest = (0, import_node_crypto.createHash)("sha256").update(bytes2).digest("base64url");
8065
- const routeKey = `{f:${digest}}`;
8066
- if (flowPartitionRouteCache.size >= FLOW_PARTITION_ROUTE_CACHE_MAX) {
8067
- const oldest = flowPartitionRouteCache.keys().next().value;
8068
- if (oldest != null) flowPartitionRouteCache.delete(oldest);
8069
- }
8070
- flowPartitionRouteCache.set(cacheKey, routeKey);
8071
- return routeKey;
8827
+ return typeof value === "string" || import_node_buffer35.Buffer.isBuffer(value);
8072
8828
  }
8073
8829
  function flowAutoIdRoutingKey(value) {
8074
- if (typeof value !== "string" && !import_node_buffer27.Buffer.isBuffer(value)) {
8830
+ if (typeof value !== "string" && !import_node_buffer35.Buffer.isBuffer(value)) {
8075
8831
  return void 0;
8076
8832
  }
8077
- const bucket = (import_node_buffer27.Buffer.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
8833
+ const bucket = (import_node_buffer35.Buffer.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
8078
8834
  return `{fa:${bucket}}`;
8079
8835
  }
8080
8836
  function flowClaimLogicalPartitionRoutingKey(value) {
8081
- if (typeof value !== "string" && !import_node_buffer27.Buffer.isBuffer(value)) return void 0;
8837
+ if (typeof value !== "string" && !import_node_buffer35.Buffer.isBuffer(value)) return void 0;
8082
8838
  const selector = commandPart(value);
8083
8839
  if (selector === "AUTO" || selector === "ANY") return void 0;
8084
8840
  if (selector === "GLOBAL") return "{f}";
@@ -8093,7 +8849,7 @@ function singleShardFlowClaimPartitionKey(values) {
8093
8849
  return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
8094
8850
  }
8095
8851
  function singleShardKey(keys) {
8096
- if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !import_node_buffer27.Buffer.isBuffer(key))) {
8852
+ if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !import_node_buffer35.Buffer.isBuffer(key))) {
8097
8853
  return void 0;
8098
8854
  }
8099
8855
  const usable = keys;
@@ -8104,7 +8860,7 @@ function singleShardKey(keys) {
8104
8860
  const firstSlot = routingSlotForKey(first);
8105
8861
  return usable.every((key) => routingSlotForKey(key) === firstSlot) ? first : void 0;
8106
8862
  }
8107
- function commandName2(args) {
8863
+ function commandName3(args) {
8108
8864
  return commandView(args).name;
8109
8865
  }
8110
8866
  var commandPart = commandToken;
@@ -8126,7 +8882,7 @@ function routedKeyGroups(keys, routeKey) {
8126
8882
  const groups = /* @__PURE__ */ new Map();
8127
8883
  for (let index = 0; index < keys.length; index += 1) {
8128
8884
  const key = keys[index];
8129
- if (typeof key !== "string" && !import_node_buffer27.Buffer.isBuffer(key)) return void 0;
8885
+ if (typeof key !== "string" && !import_node_buffer35.Buffer.isBuffer(key)) return void 0;
8130
8886
  const route = routeKey(key);
8131
8887
  const groupKey = `${route.endpointKey}\0${route.laneId}`;
8132
8888
  const group = groups.get(groupKey);
@@ -8518,7 +9274,7 @@ var TopologyPipelineExecutor = class {
8518
9274
  commands.forEach((command, index) => {
8519
9275
  const routed = this.context.routeData(command);
8520
9276
  if (routed == null) {
8521
- if (decomposableCommandNames.has(commandName2(command) ?? "")) standalone.push({ command, index });
9277
+ if (decomposableCommandNames.has(commandName3(command) ?? "")) standalone.push({ command, index });
8522
9278
  else {
8523
9279
  controlCommands.push(command);
8524
9280
  controlIndices.push(index);
@@ -8734,7 +9490,7 @@ function topologyRouteIsCurrent(topology, route) {
8734
9490
  // src/topology-route-planner.ts
8735
9491
  function topologyRouteData(args, route) {
8736
9492
  if (args.length === 0) return void 0;
8737
- const name = commandName2(args);
9493
+ const name = commandName3(args);
8738
9494
  if (name?.startsWith("FLOW.") === true) {
8739
9495
  const routed = flowRoutingData(name, args);
8740
9496
  return routed == null ? void 0 : {
@@ -8763,7 +9519,7 @@ var TopologyScatterExecutor = class {
8763
9519
  }
8764
9520
  dependencies;
8765
9521
  async execute(args) {
8766
- const name = commandName2(args);
9522
+ const name = commandName3(args);
8767
9523
  if (name === "MGET") {
8768
9524
  const value = await this.scatterArray(name, args.slice(1));
8769
9525
  return value == null ? { handled: false } : { handled: true, value };
@@ -8845,6 +9601,18 @@ var TopologyScatterExecutor = class {
8845
9601
  }
8846
9602
  };
8847
9603
 
9604
+ // src/topology-reroute-retry.ts
9605
+ async function canRetrySafeReroute(error, attempt, retryAllowed, refresh, assertOpen) {
9606
+ if (attempt !== 0 || !isRetryableRouteError(error)) return false;
9607
+ const refreshed = await refresh().then(
9608
+ () => true,
9609
+ () => false
9610
+ );
9611
+ if (!refreshed || !retryAllowed || !await waitForExplicitlySafeReroute(error)) return false;
9612
+ assertOpen();
9613
+ return true;
9614
+ }
9615
+
8848
9616
  // src/topology.ts
8849
9617
  var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8850
9618
  adapterOptions;
@@ -8886,15 +9654,15 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8886
9654
  this.adapterOptions = {
8887
9655
  ...adapterOptions,
8888
9656
  events: [.../* @__PURE__ */ new Set([...adapterOptions.events ?? [], "TOPOLOGY_CHANGED"])],
8889
- onEvent: (event) => {
9657
+ onEvent: (event2) => {
8890
9658
  try {
8891
- const callback = userOnEvent?.(event);
9659
+ const callback = userOnEvent?.(event2);
8892
9660
  if (callback != null) {
8893
9661
  void Promise.resolve(callback).catch(() => void 0);
8894
9662
  }
8895
9663
  } catch {
8896
9664
  }
8897
- if (!this.closed && nativeEventName(event) === "TOPOLOGY_CHANGED") {
9665
+ if (!this.closed && nativeEventName(event2) === "TOPOLOGY_CHANGED") {
8898
9666
  this.requestTopologyRefresh();
8899
9667
  }
8900
9668
  }
@@ -9030,6 +9798,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9030
9798
  this.assertOpen();
9031
9799
  const snapshot = snapshotCommandArguments(args);
9032
9800
  assertCommandHasStableConnectionState(snapshot);
9801
+ const casMutation = isCasMutation(snapshot);
9033
9802
  let rerouteAttempt = 0;
9034
9803
  for (let planningAttempt = 0; planningAttempt < MAX_TOPOLOGY_PLANNING_ATTEMPTS; planningAttempt += 1) {
9035
9804
  const routed = this.routeData(snapshot);
@@ -9045,7 +9814,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9045
9814
  try {
9046
9815
  return routed.command == null ? await adapter.executeCommandOnLane(snapshot, routed.route.laneId) : await adapter.executeProtocolCommand(routed.command, routed.route.laneId);
9047
9816
  } catch (error) {
9048
- if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt)) {
9817
+ if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt, !casMutation)) {
9049
9818
  rerouteAttempt += 1;
9050
9819
  continue;
9051
9820
  }
@@ -9087,6 +9856,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9087
9856
  assertCommandHasStableConnectionState(command);
9088
9857
  }
9089
9858
  let rerouteAttempt = 0;
9859
+ const containsCasMutation = snapshot.some(isCasMutation);
9090
9860
  for (let planningAttempt = 0; planningAttempt < MAX_TOPOLOGY_PLANNING_ATTEMPTS; planningAttempt += 1) {
9091
9861
  const route = singleRouteForCommands(snapshot, (command) => this.routeData(command));
9092
9862
  if (route == null) return void 0;
@@ -9095,7 +9865,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9095
9865
  try {
9096
9866
  return await adapter.executeFusedPipelineOnLane(snapshot, route.laneId, snapshotOptions);
9097
9867
  } catch (error) {
9098
- if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt)) {
9868
+ if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt, !containsCasMutation)) {
9099
9869
  rerouteAttempt += 1;
9100
9870
  continue;
9101
9871
  }
@@ -9104,15 +9874,14 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9104
9874
  }
9105
9875
  throw new StaleTopologyRouteError();
9106
9876
  }
9107
- async refreshAndCanRetrySafeReroute(error, attempt) {
9108
- if (attempt !== 0 || !isRetryableRouteError(error)) return false;
9109
- const refreshed = await this.refreshTopology().then(
9110
- () => true,
9111
- () => false
9877
+ async refreshAndCanRetrySafeReroute(error, attempt, retryAllowed = true) {
9878
+ return await canRetrySafeReroute(
9879
+ error,
9880
+ attempt,
9881
+ retryAllowed,
9882
+ async () => await this.refreshTopology(),
9883
+ () => this.assertOpen()
9112
9884
  );
9113
- if (!refreshed || !await waitForExplicitlySafeReroute(error)) return false;
9114
- this.assertOpen();
9115
- return true;
9116
9885
  }
9117
9886
  async executePipelineOnRoute(commands, route, options) {
9118
9887
  const adapter = await this.adapterForCurrentRoute(route);
@@ -9202,7 +9971,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9202
9971
  };
9203
9972
 
9204
9973
  // src/response-map-preservation.ts
9205
- var import_node_buffer29 = require("buffer");
9974
+ var import_node_buffer37 = require("buffer");
9206
9975
  function toStringKeyMapPreservingValues(value) {
9207
9976
  if (value == null) return void 0;
9208
9977
  const result = {};
@@ -9212,7 +9981,7 @@ function toStringKeyMapPreservingValues(value) {
9212
9981
  }
9213
9982
  return result;
9214
9983
  }
9215
- if (typeof value === "object" && !Array.isArray(value) && !import_node_buffer29.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9984
+ if (typeof value === "object" && !Array.isArray(value) && !import_node_buffer37.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9216
9985
  for (const [key, item] of Object.entries(value)) {
9217
9986
  setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
9218
9987
  }
@@ -9221,7 +9990,7 @@ function toStringKeyMapPreservingValues(value) {
9221
9990
  return void 0;
9222
9991
  }
9223
9992
  function normalizeMapStructurePreservingBytes(value) {
9224
- if (import_node_buffer29.Buffer.isBuffer(value) || value instanceof Uint8Array) return value;
9993
+ if (import_node_buffer37.Buffer.isBuffer(value) || value instanceof Uint8Array) return value;
9225
9994
  if (value instanceof Map) {
9226
9995
  const result = {};
9227
9996
  for (const [key, item] of value.entries()) {
@@ -9243,7 +10012,7 @@ function normalizeMapStructurePreservingBytes(value) {
9243
10012
  }
9244
10013
 
9245
10014
  // src/native-kv-responses.ts
9246
- var import_node_buffer30 = require("buffer");
10015
+ var import_node_buffer38 = require("buffer");
9247
10016
  function rateLimitResultFromResp(value) {
9248
10017
  if (!Array.isArray(value) || value.length !== 4) {
9249
10018
  throw new TypeError("RATELIMIT.ADD returned an unexpected response");
@@ -9300,13 +10069,13 @@ function fetchOrComputeResultFromResp(value, codec) {
9300
10069
  }
9301
10070
  function decodePayload(codec, value) {
9302
10071
  if (value == null) return null;
9303
- if (import_node_buffer30.Buffer.isBuffer(value)) return codec.decode(value);
9304
- if (value instanceof Uint8Array) return codec.decode(import_node_buffer30.Buffer.from(value));
9305
- if (typeof value === "string") return codec.decode(import_node_buffer30.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));
9306
10075
  return normalizeRefMeta(value);
9307
10076
  }
9308
10077
  function requiredResponseString(value, context) {
9309
- if (typeof value !== "string" && !import_node_buffer30.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
10078
+ if (typeof value !== "string" && !import_node_buffer38.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9310
10079
  throw new TypeError(`${context} returned an unexpected response`);
9311
10080
  }
9312
10081
  const result = text(value);
@@ -9323,7 +10092,7 @@ function requiredNonNegativeInteger(value, context) {
9323
10092
  return result;
9324
10093
  }
9325
10094
  function responseBytes(value, context) {
9326
- if (typeof value !== "string" && !import_node_buffer30.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
10095
+ if (typeof value !== "string" && !import_node_buffer38.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
9327
10096
  throw new TypeError(`${context} returned an unexpected response`);
9328
10097
  }
9329
10098
  return bytes(value);
@@ -9646,17 +10415,6 @@ function finiteNonNegativeInteger(value, fallback) {
9646
10415
  function finiteNonNegativeNumber(value, fallback) {
9647
10416
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, value);
9648
10417
  }
9649
- function appendReadOptions(args, options) {
9650
- append(args, "COUNT", options.count);
9651
- append(args, "PARTITION", options.partitionKey);
9652
- append(args, "FROM_MS", options.fromMs);
9653
- append(args, "TO_MS", options.toMs);
9654
- appendBool(args, "REV", options.rev);
9655
- append(args, "STATE", options.state);
9656
- appendBool(args, "TERMINAL_ONLY", options.terminalOnly);
9657
- appendBool(args, "INCLUDE_COLD", options.includeCold);
9658
- appendBool(args, "CONSISTENT_PROJECTION", options.consistentProjection);
9659
- }
9660
10418
  function appendAttributeQueryOptions(args, options) {
9661
10419
  append(args, "STATE", options.state);
9662
10420
  append(args, "PARTITION", options.partitionKey);
@@ -9710,22 +10468,6 @@ function appendAttributes(args, attributes) {
9710
10468
  args.push("ATTRIBUTE", name, value);
9711
10469
  }
9712
10470
  }
9713
- function appendSearchStateMeta(args, state, stateMeta) {
9714
- const entries = Object.entries(stateMeta ?? {});
9715
- if (entries.length === 0) {
9716
- return;
9717
- }
9718
- if (entries.every(([, value]) => isPlainObject5(value))) {
9719
- for (const [metaState, values] of entries) {
9720
- args.push("STATE_META", metaState, values);
9721
- }
9722
- return;
9723
- }
9724
- if (state == null) {
9725
- throw new Error("search stateMeta filters require state or nested state metadata");
9726
- }
9727
- args.push("STATE_META", state, stateMeta);
9728
- }
9729
10471
  function normalizeAdminResponse(value) {
9730
10472
  return normalizeRefMeta(value);
9731
10473
  }
@@ -10033,7 +10775,7 @@ function groupAutoPartitionItems(items) {
10033
10775
  }
10034
10776
 
10035
10777
  // src/client-values.ts
10036
- var import_node_buffer31 = require("buffer");
10778
+ var import_node_buffer39 = require("buffer");
10037
10779
  async function valueMGetEntries(client, refs, options = {}) {
10038
10780
  const refCount = refs.length;
10039
10781
  if (refCount === 0) {
@@ -10068,12 +10810,12 @@ async function valueMGetEntries(client, refs, options = {}) {
10068
10810
  const item = response[index];
10069
10811
  if (item == null) {
10070
10812
  entries[index] = { found: false };
10071
- } else if (import_node_buffer31.Buffer.isBuffer(item)) {
10813
+ } else if (import_node_buffer39.Buffer.isBuffer(item)) {
10072
10814
  entries[index] = { found: true, value: client.codec.decode(item) };
10073
10815
  } else if (item instanceof Uint8Array) {
10074
- entries[index] = { found: true, value: client.codec.decode(import_node_buffer31.Buffer.from(item)) };
10816
+ entries[index] = { found: true, value: client.codec.decode(import_node_buffer39.Buffer.from(item)) };
10075
10817
  } else if (typeof item === "string") {
10076
- entries[index] = { found: true, value: client.codec.decode(import_node_buffer31.Buffer.from(item)) };
10818
+ entries[index] = { found: true, value: client.codec.decode(import_node_buffer39.Buffer.from(item)) };
10077
10819
  } else {
10078
10820
  entries[index] = { found: true, value: item };
10079
10821
  }
@@ -10082,10 +10824,10 @@ async function valueMGetEntries(client, refs, options = {}) {
10082
10824
  }
10083
10825
 
10084
10826
  // src/auto-batch.ts
10085
- var import_node_buffer33 = require("buffer");
10827
+ var import_node_buffer41 = require("buffer");
10086
10828
 
10087
10829
  // src/auto-batch-ordering.ts
10088
- var import_node_buffer32 = require("buffer");
10830
+ var import_node_buffer40 = require("buffer");
10089
10831
  function autoBatchOrderingPlan(batch) {
10090
10832
  const accesses = /* @__PURE__ */ new Map();
10091
10833
  const fallbackDependencies = [];
@@ -10200,13 +10942,13 @@ function flowManyAutoBatchIds(command, name) {
10200
10942
  return fixedFlowItemIds(
10201
10943
  command,
10202
10944
  mixed ? 4 : 3,
10203
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && import_node_buffer32.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)])
10204
10946
  );
10205
10947
  }
10206
10948
  return fixedFlowItemIds(
10207
10949
  command,
10208
10950
  mixed ? 4 : 3,
10209
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer32.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)])
10210
10952
  );
10211
10953
  }
10212
10954
  function createManyAutoBatchIds(command) {
@@ -10219,7 +10961,7 @@ function createManyAutoBatchIds(command) {
10219
10961
  const ids = fixedFlowItemIds(
10220
10962
  command,
10221
10963
  width,
10222
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer32.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]),
10223
10965
  markerIndex
10224
10966
  );
10225
10967
  if (ids != null) return ids;
@@ -10237,7 +10979,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
10237
10979
  let cursor = markerIndex + 2;
10238
10980
  for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
10239
10981
  const id = command[cursor];
10240
- if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !import_node_buffer32.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;
10241
10983
  ids.push(id);
10242
10984
  cursor += 3;
10243
10985
  const afterValues = skipExtendedNamedItems(command, cursor, true);
@@ -10256,7 +10998,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
10256
10998
  for (let index = 0; index < count; index += 1) {
10257
10999
  const name = command[firstItem + index * 2];
10258
11000
  const value = command[firstItem + index * 2 + 1];
10259
- if (!isAutoBatchResourceValue(name) || (encodedValues ? !import_node_buffer32.Buffer.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
11001
+ if (!isAutoBatchResourceValue(name) || (encodedValues ? !import_node_buffer40.Buffer.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
10260
11002
  }
10261
11003
  return firstItem + count * 2;
10262
11004
  }
@@ -10271,7 +11013,7 @@ function runStepsManyAutoBatchIds(command) {
10271
11013
  ids.push(item);
10272
11014
  continue;
10273
11015
  }
10274
- if (typeof item !== "object" || item == null || Array.isArray(item) || import_node_buffer32.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;
10275
11017
  const id = item.id;
10276
11018
  if (!isAutoBatchResourceValue(id)) return void 0;
10277
11019
  ids.push(id);
@@ -10312,7 +11054,7 @@ function flowValuePutOwner(command, start) {
10312
11054
  }
10313
11055
  var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
10314
11056
  function isAutoBatchResourceValue(value) {
10315
- return typeof value === "string" || import_node_buffer32.Buffer.isBuffer(value);
11057
+ return typeof value === "string" || import_node_buffer40.Buffer.isBuffer(value);
10316
11058
  }
10317
11059
  function isFencingToken(value) {
10318
11060
  return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
@@ -10321,7 +11063,7 @@ function nonNegativeItemCount(value) {
10321
11063
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
10322
11064
  }
10323
11065
  function autoBatchResourceKey(namespace, value) {
10324
- return `${namespace}:${import_node_buffer32.Buffer.from(value).toString("base64")}`;
11066
+ return `${namespace}:${import_node_buffer40.Buffer.from(value).toString("base64")}`;
10325
11067
  }
10326
11068
  function autoBatchCommandName(command) {
10327
11069
  return commandView(command).name ?? null;
@@ -10697,7 +11439,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10697
11439
  const results = new Array(claimed.length);
10698
11440
  let cursor = 0;
10699
11441
  let failure;
10700
- const run = async () => {
11442
+ const run2 = async () => {
10701
11443
  while (failure == null) {
10702
11444
  const index = cursor;
10703
11445
  cursor += 1;
@@ -10710,7 +11452,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10710
11452
  }
10711
11453
  }
10712
11454
  };
10713
- 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));
10714
11456
  if (failure != null) {
10715
11457
  const hydratedItems = [];
10716
11458
  for (let index = 0; index < results.length; index += 1) {
@@ -10730,55 +11472,1023 @@ function claimFailure(error) {
10730
11472
  }
10731
11473
 
10732
11474
  // src/client-flow-support.ts
10733
- var import_node_buffer39 = require("buffer");
11475
+ var import_node_buffer52 = require("buffer");
10734
11476
 
10735
- // src/client-core.ts
10736
- var import_node_buffer38 = require("buffer");
11477
+ // src/flow-query-builder.ts
11478
+ var import_node_buffer43 = require("buffer");
10737
11479
 
10738
- // src/client-core-helpers.ts
10739
- var import_node_buffer34 = require("buffer");
10740
- function bgsaveResponse(response) {
10741
- if ((typeof response === "string" || import_node_buffer34.Buffer.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
10742
- 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;
10743
11490
  }
10744
- return okResponse(response);
10745
- }
10746
- function clientNameResponse(response) {
10747
- return response == null ? null : textResponse(response, "CLIENT GETNAME");
10748
- }
10749
- function fetchOrComputeCompletionToken(options) {
10750
- if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
11491
+ if (nested.some(Boolean)) {
10751
11492
  throw new TypeError(
10752
- "fetch-or-compute completion requires computeToken"
11493
+ "stateMeta must be entirely flat or entirely nested by state"
10753
11494
  );
10754
11495
  }
10755
- if (!import_node_buffer34.Buffer.isBuffer(options.computeToken)) {
10756
- 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
+ );
10757
11500
  }
10758
- return options.computeToken;
11501
+ return { [state]: value };
10759
11502
  }
10760
- function concatCommandArgs(prefix, suffix) {
10761
- const args = new Array(prefix.length + suffix.length);
10762
- for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
10763
- for (let index = 0; index < suffix.length; index += 1) {
10764
- 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
+ }
10765
11517
  }
10766
- return args;
11518
+ return entries;
10767
11519
  }
10768
- function unsupportedClientTracking() {
10769
- throw new InvalidCommandError(
10770
- "CLIENT TRACKING is not supported by the FerricStore native protocol; use native event subscriptions"
10771
- );
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]]);
10772
11528
  }
10773
- function unsupportedClientCaching() {
10774
- 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;
11535
+ }
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;
11550
+ }
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;
11564
+ }
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
+ );
11593
+ }
11594
+ }
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");
10775
12485
  }
10776
12486
 
10777
12487
  // src/client-base.ts
10778
- var import_node_buffer36 = require("buffer");
12488
+ var import_node_buffer48 = require("buffer");
10779
12489
 
10780
12490
  // src/client-executor.ts
10781
- var import_node_buffer35 = require("buffer");
12491
+ var import_node_buffer47 = require("buffer");
10782
12492
  var ErrorMappingExecutor = class {
10783
12493
  constructor(executor) {
10784
12494
  this.executor = executor;
@@ -11112,14 +12822,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
11112
12822
  };
11113
12823
 
11114
12824
  // src/store-utilities.ts
11115
- var import_node_buffer37 = require("buffer");
12825
+ var import_node_buffer49 = require("buffer");
11116
12826
  function encode(codec, value) {
11117
12827
  return codec.encode(value);
11118
12828
  }
11119
12829
  function decode(codec, value) {
11120
12830
  if (value == null) return null;
11121
- if (import_node_buffer37.Buffer.isBuffer(value)) return codec.decode(value);
11122
- if (value instanceof Uint8Array) return codec.decode(import_node_buffer37.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));
11123
12833
  return value;
11124
12834
  }
11125
12835
  function number(value) {
@@ -11180,7 +12890,7 @@ function requireNonEmpty(values, command, noun = "argument") {
11180
12890
  if (values.length === 0) throw new TypeError(`${command} requires at least one ${noun}`);
11181
12891
  return values;
11182
12892
  }
11183
- function commandName3(args) {
12893
+ function commandName4(args) {
11184
12894
  return typeof args[0] === "string" ? args[0] : "command";
11185
12895
  }
11186
12896
  function commandArgs(client, args) {
@@ -11195,7 +12905,7 @@ function arrayOrRest(values) {
11195
12905
  function appendXReadStreams(args, streams) {
11196
12906
  const offset = args.length;
11197
12907
  const streamCount = streams.length;
11198
- requireNonEmpty(streams, commandName3(args), "stream");
12908
+ requireNonEmpty(streams, commandName4(args), "stream");
11199
12909
  args.length = offset + 1 + streamCount * 2;
11200
12910
  args[offset] = "STREAMS";
11201
12911
  for (let index = 0; index < streamCount; index += 1) {
@@ -11205,7 +12915,7 @@ function appendXReadStreams(args, streams) {
11205
12915
  const stream = streams[index];
11206
12916
  if (stream == null) throw new TypeError("XREAD streams must contain only stream descriptors");
11207
12917
  if (!Object.hasOwn(stream, "key") || !Object.hasOwn(stream, "id")) {
11208
- throw new TypeError(`${commandName3(args)} streams require own key and id fields`);
12918
+ throw new TypeError(`${commandName4(args)} streams require own key and id fields`);
11209
12919
  }
11210
12920
  args[offset + 1 + index] = stream.key;
11211
12921
  args[offset + 1 + streamCount + index] = stream.id;
@@ -11227,7 +12937,7 @@ function concatArgs(...parts) {
11227
12937
  return args;
11228
12938
  }
11229
12939
  function encodedArgs(prefix, codec, values, allowEmpty = false) {
11230
- if (!allowEmpty) requireNonEmpty(values, commandName3(prefix));
12940
+ if (!allowEmpty) requireNonEmpty(values, commandName4(prefix));
11231
12941
  const args = new Array(prefix.length + values.length);
11232
12942
  for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
11233
12943
  for (let index = 0; index < values.length; index += 1) {
@@ -11241,7 +12951,7 @@ function encodedArgs(prefix, codec, values, allowEmpty = false) {
11241
12951
  function keyValueArgs(prefix, codec, entries) {
11242
12952
  const validateTuples = Array.isArray(entries);
11243
12953
  const pairs = validateTuples ? entries : Object.entries(entries);
11244
- requireNonEmpty(pairs, commandName3(prefix), "entry");
12954
+ requireNonEmpty(pairs, commandName4(prefix), "entry");
11245
12955
  const args = new Array(prefix.length + pairs.length * 2);
11246
12956
  for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
11247
12957
  for (let index = 0; index < pairs.length; index += 1) {
@@ -11255,7 +12965,7 @@ function keyValueArgs(prefix, codec, entries) {
11255
12965
  return args;
11256
12966
  }
11257
12967
  function encodedEntryArgs(prefix, codec, entries) {
11258
- requireNonEmpty(entries, commandName3(prefix), "entry");
12968
+ requireNonEmpty(entries, commandName4(prefix), "entry");
11259
12969
  const args = new Array(prefix.length + entries.length * 2);
11260
12970
  for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
11261
12971
  for (let index = 0; index < entries.length; index += 1) {
@@ -11709,15 +13419,15 @@ function compressionOptions(options) {
11709
13419
  // src/store-decoders.ts
11710
13420
  function decodeHashRecord(codec, value) {
11711
13421
  const result = {};
11712
- for (const [field2, item] of hashPairs(value)) {
11713
- setOwnValue(result, textToken(field2), decode(codec, item));
13422
+ for (const [field3, item] of hashPairs(value)) {
13423
+ setOwnValue(result, textToken(field3), decode(codec, item));
11714
13424
  }
11715
13425
  return result;
11716
13426
  }
11717
13427
  function decodeHashFlatPairs(codec, value) {
11718
13428
  const result = [];
11719
- for (const [field2, item] of hashPairs(value)) {
11720
- result.push(textToken(field2), decode(codec, item));
13429
+ for (const [field3, item] of hashPairs(value)) {
13430
+ result.push(textToken(field3), decode(codec, item));
11721
13431
  }
11722
13432
  return result;
11723
13433
  }
@@ -11837,7 +13547,7 @@ function requiredPair(value, message) {
11837
13547
  }
11838
13548
  function decodeStreamFieldValues(codec, value) {
11839
13549
  const result = [];
11840
- 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));
11841
13551
  return result;
11842
13552
  }
11843
13553
  var geoSearchMetadataTokens = /* @__PURE__ */ new Set(["WITHCOORD", "WITHDIST", "WITHHASH"]);
@@ -12651,8 +14361,8 @@ var HashStore = class {
12651
14361
  async hset(key, entries) {
12652
14362
  return number(await commandArgs(this.client, keyValueArgs(["HSET", key], this.client.codec, entries)));
12653
14363
  }
12654
- async hget(key, field2) {
12655
- 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));
12656
14366
  }
12657
14367
  async hdel(key, ...fieldsOrArray) {
12658
14368
  const fields = requireNonEmpty(arrayOrRest(fieldsOrArray), "HDEL", "field");
@@ -12671,8 +14381,8 @@ var HashStore = class {
12671
14381
  async hgetall(key) {
12672
14382
  return decodeHashRecord(this.client.codec, await this.client.command("HGETALL", key));
12673
14383
  }
12674
- async hexists(key, field2) {
12675
- return binaryBooleanResponse(await this.client.command("HEXISTS", key, field2));
14384
+ async hexists(key, field3) {
14385
+ return binaryBooleanResponse(await this.client.command("HEXISTS", key, field3));
12676
14386
  }
12677
14387
  async hkeys(key) {
12678
14388
  return mapArray(await this.client.command("HKEYS", key), "HKEYS", textToken);
@@ -12687,17 +14397,17 @@ var HashStore = class {
12687
14397
  async hlen(key) {
12688
14398
  return number(await this.client.command("HLEN", key));
12689
14399
  }
12690
- async hincrby(key, field2, increment) {
12691
- 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));
12692
14402
  }
12693
- async hincrbyfloat(key, field2, increment) {
12694
- 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));
12695
14405
  }
12696
- async hsetnx(key, field2, value) {
12697
- 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)));
12698
14408
  }
12699
- async hstrlen(key, field2) {
12700
- return number(await this.client.command("HSTRLEN", key, field2));
14409
+ async hstrlen(key, field3) {
14410
+ return number(await this.client.command("HSTRLEN", key, field3));
12701
14411
  }
12702
14412
  async hrandfield(key, count, withValues = false) {
12703
14413
  if (withValues && count == null) {
@@ -13333,6 +15043,100 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
13333
15043
  }
13334
15044
  };
13335
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
+
13336
15140
  // src/producer-backpressure.ts
13337
15141
  async function executeProducerWriteWithBackpressure(execute, policy, signal) {
13338
15142
  for (let attempt = 0; ; attempt += 1) {
@@ -13354,8 +15158,167 @@ function throwIfClosed(signal) {
13354
15158
  throw new FerricStoreError("FerricStore client is closed", { raw: signal.reason });
13355
15159
  }
13356
15160
 
15161
+ // src/flow-policy.ts
15162
+ var import_node_buffer51 = require("buffer");
15163
+ var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
15164
+ function assertFlowPolicyGeneration(value) {
15165
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
15166
+ throw new TypeError("expectedGeneration must be a nonnegative safe integer");
15167
+ }
15168
+ }
15169
+ function flowPolicySnapshotFromResp(value) {
15170
+ const policy = requiredRecord(value, "FLOW policy snapshot");
15171
+ const maxActiveMs = optionalPositiveInteger(field(policy, "max_active_ms"), "max_active_ms");
15172
+ const state = optionalText3(field(policy, "state"), "state");
15173
+ const mode = optionalMode(field(policy, "mode"), "mode");
15174
+ const version = optionalVersion(field(policy, "version"));
15175
+ const indexedStateMeta = optionalText3(field(policy, "indexed_state_meta"), "indexed_state_meta");
15176
+ const governance = optionalRecord(field(policy, "governance"), "governance");
15177
+ const states = optionalStates(field(policy, "states"));
15178
+ return {
15179
+ type: requiredText3(field(policy, "type"), "type"),
15180
+ generation: nonNegativeInteger2(field(policy, "generation"), "generation"),
15181
+ ...state == null ? {} : { state },
15182
+ ...version == null ? {} : { version },
15183
+ ...mode == null ? {} : { mode },
15184
+ ...maxActiveMs == null ? {} : { maxActiveMs },
15185
+ retry: retrySnapshot(field(policy, "retry"), "retry"),
15186
+ retention: retentionSnapshot(field(policy, "retention"), "retention"),
15187
+ indexedAttributes: stringArray(field(policy, "indexed_attributes"), "indexed_attributes"),
15188
+ ...indexedStateMeta == null ? {} : { indexedStateMeta },
15189
+ ...governance == null ? {} : { governance },
15190
+ ...states == null ? {} : { states },
15191
+ raw: value
15192
+ };
15193
+ }
15194
+ function retrySnapshot(value, context) {
15195
+ const retry2 = requiredRecord(value, `FLOW policy ${context}`);
15196
+ const backoff = requiredRecord(field(retry2, "backoff"), `FLOW policy ${context}.backoff`);
15197
+ return {
15198
+ maxRetries: nonNegativeInteger2(field(retry2, "max_retries"), `${context}.max_retries`),
15199
+ backoff: {
15200
+ kind: backoffKind(field(backoff, "kind"), `${context}.backoff.kind`),
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`)
15204
+ },
15205
+ exhaustedTo: requiredText3(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
15206
+ };
15207
+ }
15208
+ function retentionSnapshot(value, context) {
15209
+ const retention = requiredRecord(value, `FLOW policy ${context}`);
15210
+ return {
15211
+ ttlMs: nonNegativeInteger2(field(retention, "ttl_ms"), `${context}.ttl_ms`),
15212
+ historyMaxEvents: nonNegativeInteger2(
15213
+ field(retention, "history_max_events"),
15214
+ `${context}.history_max_events`
15215
+ )
15216
+ };
15217
+ }
15218
+ function optionalStates(value) {
15219
+ if (value == null) return void 0;
15220
+ const source = requiredRecord(value, "FLOW policy states");
15221
+ const result = {};
15222
+ for (const [state, raw] of Object.entries(source)) {
15223
+ const policy = requiredRecord(raw, `FLOW policy state ${state}`);
15224
+ const maxActiveMs = optionalPositiveInteger(
15225
+ field(policy, "max_active_ms"),
15226
+ `states.${state}.max_active_ms`
15227
+ );
15228
+ const governance = optionalRecord(field(policy, "governance"), `states.${state}.governance`);
15229
+ Object.defineProperty(result, state, {
15230
+ configurable: true,
15231
+ enumerable: true,
15232
+ value: {
15233
+ mode: requiredMode(field(policy, "mode"), `states.${state}.mode`),
15234
+ ...maxActiveMs == null ? {} : { maxActiveMs },
15235
+ retry: retrySnapshot(field(policy, "retry"), `states.${state}.retry`),
15236
+ retention: retentionSnapshot(field(policy, "retention"), `states.${state}.retention`),
15237
+ ...governance == null ? {} : { governance }
15238
+ },
15239
+ writable: true
15240
+ });
15241
+ }
15242
+ return result;
15243
+ }
15244
+ function requiredRecord(value, context) {
15245
+ if (value instanceof Map) {
15246
+ const result = {};
15247
+ for (const [key, item] of value.entries()) {
15248
+ setOwnValue(result, requiredText3(key, `${context} key`), item);
15249
+ }
15250
+ return result;
15251
+ }
15252
+ if (typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer51.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return value;
15253
+ throw new TypeError(`${context} returned an unexpected response`);
15254
+ }
15255
+ function optionalRecord(value, context) {
15256
+ return value == null ? void 0 : requiredRecord(value, `FLOW policy ${context}`);
15257
+ }
15258
+ function stringArray(value, context) {
15259
+ if (!Array.isArray(value)) {
15260
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15261
+ }
15262
+ const result = new Array(value.length);
15263
+ for (let index = 0; index < value.length; index += 1) {
15264
+ if (!Object.hasOwn(value, index)) {
15265
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15266
+ }
15267
+ result[index] = requiredText3(value[index], `${context}[${index}]`);
15268
+ }
15269
+ return result;
15270
+ }
15271
+ function requiredText3(value, context) {
15272
+ if (typeof value === "string") return value;
15273
+ if (import_node_buffer51.Buffer.isBuffer(value) || value instanceof Uint8Array) {
15274
+ return import_node_buffer51.Buffer.from(value).toString("utf8");
15275
+ }
15276
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15277
+ }
15278
+ function optionalText3(value, context) {
15279
+ return value == null ? void 0 : requiredText3(value, context);
15280
+ }
15281
+ function nonNegativeInteger2(value, context) {
15282
+ let parsed;
15283
+ try {
15284
+ parsed = integer(value);
15285
+ } catch {
15286
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15287
+ }
15288
+ if (parsed < 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15289
+ return parsed;
15290
+ }
15291
+ function optionalPositiveInteger(value, context) {
15292
+ if (value == null) return void 0;
15293
+ const parsed = nonNegativeInteger2(value, context);
15294
+ if (parsed === 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15295
+ return parsed;
15296
+ }
15297
+ function optionalVersion(value) {
15298
+ if (value == null) return void 0;
15299
+ if (typeof value === "number" || typeof value === "bigint") {
15300
+ return nonNegativeInteger2(value, "version");
15301
+ }
15302
+ return requiredText3(value, "version");
15303
+ }
15304
+ function backoffKind(value, context) {
15305
+ const kind = requiredText3(value, context).toLowerCase();
15306
+ if (kind === "none" || kind === "fixed" || kind === "linear" || kind === "exponential") {
15307
+ return kind;
15308
+ }
15309
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15310
+ }
15311
+ function requiredMode(value, context) {
15312
+ const mode = requiredText3(value, context).toLowerCase();
15313
+ if (mode === "fifo" || mode === "parallel") return mode;
15314
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15315
+ }
15316
+ function optionalMode(value, context) {
15317
+ return value == null ? void 0 : requiredMode(value, context);
15318
+ }
15319
+
13357
15320
  // src/client-flow-support.ts
13358
- var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
15321
+ var FerricStoreFlowSupportClient = class extends FerricStoreFlowQueryClient {
13359
15322
  async rewind(id, options = {}) {
13360
15323
  const partitionKey = options.partitionKey;
13361
15324
  const returnRecord = options.returnRecord === true;
@@ -13381,43 +15344,9 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13381
15344
  }
13382
15345
  return flowRecordFromResp(response, this.codec);
13383
15346
  }
13384
- async list(type, options = {}) {
13385
- return await this.indexQuery("FLOW.LIST", type, options);
13386
- }
13387
- async search(type, options = {}) {
13388
- const args = ["FLOW.SEARCH", type];
13389
- appendReadOptions(args, options);
13390
- appendAttributes(args, options.attributes);
13391
- appendSearchStateMeta(args, options.state, options.stateMeta);
13392
- const response = await this.commandArgs(args);
13393
- return this.records(requiredArrayResponse(response, "FLOW.SEARCH"));
13394
- }
13395
- async terminals(type, options = {}) {
13396
- return await this.indexQuery("FLOW.TERMINALS", type, options);
13397
- }
13398
- async failures(type, options = {}) {
13399
- return await this.indexQuery("FLOW.FAILURES", type, options);
13400
- }
13401
- async byParent(parentFlowId, options = {}) {
13402
- return await this.indexQuery("FLOW.BY_PARENT", parentFlowId, options);
13403
- }
13404
- async byRoot(rootFlowId, options = {}) {
13405
- return await this.indexQuery("FLOW.BY_ROOT", rootFlowId, options);
13406
- }
13407
- async byCorrelation(correlationId, options = {}) {
13408
- return await this.indexQuery("FLOW.BY_CORRELATION", correlationId, options);
13409
- }
13410
15347
  async info(type) {
13411
15348
  return parseKvResponse(await this.command("FLOW.INFO", type));
13412
15349
  }
13413
- async stuck(type, options = {}) {
13414
- const args = ["FLOW.STUCK", type];
13415
- append(args, "PARTITION", options.partitionKey);
13416
- append(args, "COUNT", options.count);
13417
- append(args, "OLDER_THAN", options.olderThanMs);
13418
- append(args, "NOW", options.nowMs);
13419
- return this.records(arrayResponse(await this.commandArgs(args)));
13420
- }
13421
15350
  async history(id, options = {}) {
13422
15351
  const args = ["FLOW.HISTORY", id];
13423
15352
  append(args, "PARTITION", options.partitionKey);
@@ -13496,27 +15425,36 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13496
15425
  }
13497
15426
  async installPolicy(type, options = {}) {
13498
15427
  const args = ["FLOW.POLICY.SET", type];
15428
+ const expectedGeneration = Object.hasOwn(options, "expectedGeneration") ? options.expectedGeneration : void 0;
15429
+ const replace = Object.hasOwn(options, "replace") ? options.replace : void 0;
15430
+ if (expectedGeneration != null) assertFlowPolicyGeneration(expectedGeneration);
15431
+ if (replace != null && typeof replace !== "boolean") {
15432
+ throw new TypeError("replace must be a boolean");
15433
+ }
15434
+ append(args, "EXPECTED_GENERATION", expectedGeneration);
15435
+ appendBool(args, "REPLACE", replace);
13499
15436
  if (options.indexedAttributes != null) {
13500
15437
  args.push("INDEXED_ATTRIBUTES", JSON.stringify(options.indexedAttributes));
13501
15438
  }
13502
15439
  append(args, "INDEXED_STATE_META", options.indexedStateMeta);
13503
15440
  append(args, "MAX_ACTIVE_MS", options.maxActiveMs);
15441
+ if (options.state == null) append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
13504
15442
  append(args, "STATE", options.state);
13505
15443
  appendPolicyMode(args, options.state, options.mode);
13506
15444
  if (options.retry != null) {
13507
15445
  appendRetryPolicy(args, options.retry);
13508
15446
  }
15447
+ if (options.state != null) append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
13509
15448
  for (const [state, policy] of Object.entries(options.states ?? {})) {
13510
15449
  args.push("STATE", state);
13511
15450
  appendFlowStatePolicy(args, policy);
13512
15451
  }
13513
- append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
13514
- return await this.commandArgs(args);
15452
+ return flowPolicySnapshotFromResp(await this.commandArgs(args));
13515
15453
  }
13516
15454
  async policyGet(type, options = {}) {
13517
15455
  const args = ["FLOW.POLICY.GET", type];
13518
15456
  append(args, "STATE", options.state);
13519
- return parseKvResponse(await this.commandArgs(args));
15457
+ return flowPolicySnapshotFromResp(await this.commandArgs(args));
13520
15458
  }
13521
15459
  async retentionCleanup() {
13522
15460
  return parseKvResponse(await this.command("FLOW.RETENTION_CLEANUP"));
@@ -13538,16 +15476,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13538
15476
  }
13539
15477
  return record;
13540
15478
  }
13541
- records(values) {
13542
- const records = new Array(values.length);
13543
- for (let index = 0; index < values.length; index += 1) {
13544
- if (!Object.hasOwn(values, index)) {
13545
- throw new TypeError(`Flow record response item ${index} is missing`);
13546
- }
13547
- records[index] = flowRecordFromResp(values[index], this.codec);
13548
- }
13549
- return records;
13550
- }
13551
15479
  recordsOrResponse(value) {
13552
15480
  if (Array.isArray(value) && value.every(isRecordLike)) {
13553
15481
  return this.records(value);
@@ -13577,12 +15505,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13577
15505
  }
13578
15506
  return results;
13579
15507
  }
13580
- async indexQuery(command, key, options) {
13581
- const args = [command, key];
13582
- appendReadOptions(args, options);
13583
- const response = await this.commandArgs(args);
13584
- return this.records(requiredArrayResponse(response, command));
13585
- }
13586
15508
  appendPartitionOptions(args, options) {
13587
15509
  if (options.partitionKey != null && options.partitionKeys != null) {
13588
15510
  throw new Error("partitionKey and partitionKeys are mutually exclusive");
@@ -13605,7 +15527,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13605
15527
  };
13606
15528
 
13607
15529
  // src/flow-many-snapshot.ts
13608
- var import_node_buffer40 = require("buffer");
15530
+ var import_node_buffer53 = require("buffer");
13609
15531
  var encodedOptionFields = ["error", "payload", "reason", "result"];
13610
15532
  function snapshotCreateItem(item, codec) {
13611
15533
  const snapshot = {
@@ -13623,9 +15545,9 @@ function snapshotCreateItem(item, codec) {
13623
15545
  function snapshotFlowManyOptions(options, codec) {
13624
15546
  const snapshot = { ...options };
13625
15547
  const mutable = snapshot;
13626
- for (const field2 of encodedOptionFields) {
13627
- const value = options[field2];
13628
- 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);
13629
15551
  }
13630
15552
  if (options.attributes != null) mutable.attributes = snapshotCommandRecord(options.attributes);
13631
15553
  if (options.attributesMerge != null) {
@@ -13645,7 +15567,7 @@ function snapshotFlowManyOptions(options, codec) {
13645
15567
  }
13646
15568
  function snapshotClaimedItem(item) {
13647
15569
  const wire = item[CLAIMED_ITEM_WIRE];
13648
- const leaseToken = import_node_buffer40.Buffer.from(wire?.leaseToken ?? item.leaseToken);
15570
+ const leaseToken = import_node_buffer53.Buffer.from(wire?.leaseToken ?? item.leaseToken);
13649
15571
  const snapshot = {
13650
15572
  ...item,
13651
15573
  fencingToken: wire?.fencingToken ?? item.fencingToken,
@@ -13662,15 +15584,15 @@ function snapshotClaimedItem(item) {
13662
15584
  function snapshotFencedItem(item) {
13663
15585
  return Object.freeze({
13664
15586
  ...item,
13665
- ...item.leaseToken == null ? {} : { leaseToken: import_node_buffer40.Buffer.from(item.leaseToken) }
15587
+ ...item.leaseToken == null ? {} : { leaseToken: import_node_buffer53.Buffer.from(item.leaseToken) }
13666
15588
  });
13667
15589
  }
13668
15590
  function snapshotClaimedItemWire(wire, leaseToken) {
13669
15591
  return Object.freeze({
13670
15592
  fencingToken: wire.fencingToken,
13671
- id: import_node_buffer40.Buffer.from(wire.id),
15593
+ id: import_node_buffer53.Buffer.from(wire.id),
13672
15594
  leaseToken,
13673
- partitionKey: wire.partitionKey == null ? wire.partitionKey : import_node_buffer40.Buffer.from(wire.partitionKey)
15595
+ partitionKey: wire.partitionKey == null ? wire.partitionKey : import_node_buffer53.Buffer.from(wire.partitionKey)
13674
15596
  });
13675
15597
  }
13676
15598
  function snapshotArray(values) {
@@ -13681,7 +15603,7 @@ function snapshotArray(values) {
13681
15603
  return Object.freeze(snapshot);
13682
15604
  }
13683
15605
  function snapshotStateMeta(stateMeta) {
13684
- return snapshotRecord(stateMeta, (value) => import_node_buffer40.Buffer.isBuffer(value) ? import_node_buffer40.Buffer.from(value) : value);
15606
+ return snapshotRecord(stateMeta, (value) => import_node_buffer53.Buffer.isBuffer(value) ? import_node_buffer53.Buffer.from(value) : value);
13685
15607
  }
13686
15608
  function snapshotCommandRecord(values) {
13687
15609
  const seen = /* @__PURE__ */ new WeakMap();
@@ -13699,7 +15621,7 @@ function snapshotRecord(values, capture) {
13699
15621
  }
13700
15622
  function snapshotCommandArgument(value, seen) {
13701
15623
  if (typeof value !== "object" || value == null) return value;
13702
- if (import_node_buffer40.Buffer.isBuffer(value) || value instanceof Uint8Array) return import_node_buffer40.Buffer.from(value);
15624
+ if (import_node_buffer53.Buffer.isBuffer(value) || value instanceof Uint8Array) return import_node_buffer53.Buffer.from(value);
13703
15625
  const objectValue = value;
13704
15626
  const existing = seen.get(objectValue);
13705
15627
  if (existing != null) return existing;
@@ -14686,6 +16608,142 @@ function nativeOptionsForBootstrap(options, signal) {
14686
16608
  };
14687
16609
  }
14688
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
+
14689
16747
  // src/outcomes.ts
14690
16748
  var OUTCOME_BRAND = /* @__PURE__ */ Symbol("ferricstore.outcome");
14691
16749
  function transition(toState, options = {}) {
@@ -14765,7 +16823,7 @@ var LeaseRenewalGuard = class {
14765
16823
  if (options.leaseRenewal === false) {
14766
16824
  return;
14767
16825
  }
14768
- 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)));
14769
16827
  this.timer = setLongInterval(() => this.renew(), intervalMs);
14770
16828
  this.timer.unref();
14771
16829
  }
@@ -14837,7 +16895,7 @@ function snapshotLeasedJob(job) {
14837
16895
  return snapshot;
14838
16896
  }
14839
16897
  function workerConcurrency(options) {
14840
- return positiveInteger(options.concurrency ?? options.workers, 1);
16898
+ return positiveInteger2(options.concurrency ?? options.workers, 1);
14841
16899
  }
14842
16900
  function workerRefillStrategy(options) {
14843
16901
  return options.refillStrategy === "wave" ? "wave" : "continuous";
@@ -14880,18 +16938,18 @@ function workerErrorPayload(error, options, codec) {
14880
16938
  }
14881
16939
  function workerBatchSize(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
14882
16940
  return Math.min(
14883
- positiveInteger(options.batchSize, 10),
14884
- positiveInteger(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
16941
+ positiveInteger2(options.batchSize, 10),
16942
+ positiveInteger2(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
14885
16943
  );
14886
16944
  }
14887
16945
  function workerClaimLimit(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
14888
16946
  return Math.min(workerBatchSize(options, flowManyBatchLimit), workerConcurrency(options));
14889
16947
  }
14890
16948
  function workerDrainBatches(options) {
14891
- return positiveInteger(options.claimDrainBatches, 1);
16949
+ return positiveInteger2(options.claimDrainBatches, 1);
14892
16950
  }
14893
16951
  function workerLeaseMs(options, fallback = 3e4) {
14894
- return positiveInteger(options.leaseMs, positiveInteger(fallback, 3e4));
16952
+ return positiveInteger2(options.leaseMs, positiveInteger2(fallback, 3e4));
14895
16953
  }
14896
16954
  function workerIdleSleepMs(options) {
14897
16955
  return nonNegativeDuration(options.idleSleepMs, 250);
@@ -14903,7 +16961,7 @@ function workerClaimBlockMs(options, useBlocking) {
14903
16961
  if (options.signal == null || !Number.isFinite(options.blockMs) || options.blockMs < 0) {
14904
16962
  return options.blockMs;
14905
16963
  }
14906
- const abortPollMs = positiveInteger(options.abortPollMs, 1e3);
16964
+ const abortPollMs = positiveInteger2(options.abortPollMs, 1e3);
14907
16965
  return options.blockMs === 0 ? abortPollMs : Math.min(Math.trunc(options.blockMs), abortPollMs);
14908
16966
  }
14909
16967
  function workerMaxIdleSleepMs(options, idleSleepMs = workerIdleSleepMs(options)) {
@@ -14914,14 +16972,14 @@ function nextWorkerIdleSleepMs(currentIdleSleepMs, maxIdleSleepMs) {
14914
16972
  return Math.min(maxIdleSleepMs, Math.max(1, currentIdleSleepMs * 2));
14915
16973
  }
14916
16974
  async function runContinuousWorkerPool(options) {
14917
- const concurrency = positiveInteger(options.concurrency, 1);
14918
- const maxClaimSize = positiveInteger(options.maxClaimSize, concurrency);
16975
+ const concurrency = positiveInteger2(options.concurrency, 1);
16976
+ const maxClaimSize = positiveInteger2(options.maxClaimSize, concurrency);
14919
16977
  const initialIdleSleepMs = nonNegativeDuration(options.idleSleepMs, 250);
14920
16978
  const maxIdleSleepMs = Math.max(
14921
16979
  initialIdleSleepMs,
14922
16980
  nonNegativeDuration(options.maxIdleSleepMs, 5e3)
14923
16981
  );
14924
- const refillDelayMs = nonNegativeInteger(options.refillDelayMs, 0);
16982
+ const refillDelayMs = nonNegativeInteger3(options.refillDelayMs, 0);
14925
16983
  const active = /* @__PURE__ */ new Set();
14926
16984
  const pending = [];
14927
16985
  let pendingIndex = 0;
@@ -15037,10 +17095,10 @@ function normalizeWorkflowWorkerConfig(options) {
15037
17095
  ...captured
15038
17096
  });
15039
17097
  }
15040
- function positiveInteger(value, fallback) {
17098
+ function positiveInteger2(value, fallback) {
15041
17099
  return value == null || !Number.isFinite(value) ? fallback : Math.max(1, Math.trunc(value));
15042
17100
  }
15043
- function nonNegativeInteger(value, fallback) {
17101
+ function nonNegativeInteger3(value, fallback) {
15044
17102
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, Math.trunc(value));
15045
17103
  }
15046
17104
  function nonNegativeDuration(value, fallback) {
@@ -16456,6 +18514,7 @@ var Workflow = class {
16456
18514
  }
16457
18515
  return await this.client.installPolicy(this.type, {
16458
18516
  ...options,
18517
+ replace: Object.hasOwn(options, "replace") ? options.replace ?? true : true,
16459
18518
  states
16460
18519
  });
16461
18520
  }
@@ -16668,8 +18727,8 @@ var WorkflowWorker = class {
16668
18727
  };
16669
18728
 
16670
18729
  // src/version.ts
16671
- var FERRICSTORE_SDK_VERSION = "0.2.0";
16672
- var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.8.0";
18730
+ var FERRICSTORE_SDK_VERSION = "0.5.0";
18731
+ var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.0";
16673
18732
  var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16674
18733
  // Annotate the CommonJS export names for ESM import in node:
16675
18734
  0 && (module.exports = {
@@ -16688,6 +18747,8 @@ var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16688
18747
  FlowAlreadyExistsError,
16689
18748
  FlowBatchError,
16690
18749
  FlowNotFoundError,
18750
+ FlowProjection,
18751
+ FlowQueryError,
16691
18752
  FlowWrongStateError,
16692
18753
  GeoStore,
16693
18754
  HashStore,
@@ -16699,6 +18760,7 @@ var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16699
18760
  ListStore,
16700
18761
  LockHeldError,
16701
18762
  LockNotOwnedError,
18763
+ MAX_FLOW_POLICY_GENERATION,
16702
18764
  NativeAdapter,
16703
18765
  OverloadedError,
16704
18766
  Queue,
@@ -16713,6 +18775,7 @@ var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16713
18775
  SetStore,
16714
18776
  SortedSetStore,
16715
18777
  StaleLeaseError,
18778
+ StalePolicyGenerationError,
16716
18779
  StreamStore,
16717
18780
  TDigestStore,
16718
18781
  TopKStore,
@@ -16728,6 +18791,7 @@ var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16728
18791
  isOutcome,
16729
18792
  isReconnectableClosedConnectionError,
16730
18793
  mapException,
18794
+ projectFlowQuery,
16731
18795
  retry,
16732
18796
  transition
16733
18797
  });