@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.js CHANGED
@@ -58,6 +58,9 @@ var FlowWrongStateError = class extends FerricStoreError {
58
58
  var StaleLeaseError = class extends FerricStoreError {
59
59
  code = "stale_lease";
60
60
  };
61
+ var StalePolicyGenerationError = class extends FerricStoreError {
62
+ code = "stale_policy_generation";
63
+ };
61
64
  var FlowAlreadyExistsError = class extends FerricStoreError {
62
65
  code = "flow_already_exists";
63
66
  };
@@ -123,6 +126,9 @@ function classifyServerError(message, raw, cause, status) {
123
126
  if (code === "stale_lease" || code === "stale_flow_lease" || lower.includes("stale flow lease") || lower.includes("stale lease") || lower.includes("stale token")) {
124
127
  return new StaleLeaseError(message, { cause, raw });
125
128
  }
129
+ if (code === "stale_generation" || code === "stale_policy_generation" || code === "stale_flow_policy_generation" || lower.includes("stale flow policy generation") || lower.includes("stale policy generation")) {
130
+ return new StalePolicyGenerationError(message, { cause, raw });
131
+ }
126
132
  if (code === "flow_not_found" || lower.includes("flow") && (lower.includes("not found") || lower.includes("does not exist"))) {
127
133
  return new FlowNotFoundError(message, { cause, raw });
128
134
  }
@@ -1176,10 +1182,151 @@ var NativeHeartbeat = class {
1176
1182
  };
1177
1183
 
1178
1184
  // src/protocol.ts
1179
- import { Buffer as Buffer22 } from "buffer";
1185
+ import { Buffer as Buffer27 } from "buffer";
1180
1186
 
1181
- // src/command-grammar.ts
1187
+ // src/flow-query-request.ts
1182
1188
  import { Buffer as Buffer4 } from "buffer";
1189
+ var FLOW_QUERY_LANGUAGE_VERSION = "FQL1";
1190
+ var FLOW_QUERY_MAX_BYTES = 16 * 1024;
1191
+ var FLOW_QUERY_MAX_PARAMETERS = 64;
1192
+ var FLOW_QUERY_MAX_PARAMETER_NAME_BYTES = 128;
1193
+ var MIN_I64 = -(1n << 63n);
1194
+ var MAX_I64 = (1n << 63n) - 1n;
1195
+ var INDEX_ID = /^[A-Za-z0-9_.:-]{1,64}$/u;
1196
+ function flowQueryArgs(query, params = {}) {
1197
+ validateFlowQueryText(query);
1198
+ const entries = flowQueryParameterEntries(params);
1199
+ const args = ["FLOW.QUERY", FLOW_QUERY_LANGUAGE_VERSION, query];
1200
+ for (const [name, value] of entries) args.push(name, value);
1201
+ return args;
1202
+ }
1203
+ function flowQueryPayload(args) {
1204
+ if (args.length < 2) throw new TypeError("FLOW.QUERY requires version and query");
1205
+ if ((args.length - 2) % 2 !== 0) {
1206
+ throw new TypeError("FLOW.QUERY parameters must be name/value pairs");
1207
+ }
1208
+ const version = commandText(args[0], "FLOW.QUERY version");
1209
+ if (version !== FLOW_QUERY_LANGUAGE_VERSION) {
1210
+ throw new TypeError(`FLOW.QUERY requires version ${FLOW_QUERY_LANGUAGE_VERSION}`);
1211
+ }
1212
+ const query = commandText(args[1], "FLOW.QUERY query");
1213
+ validateFlowQueryText(query);
1214
+ const parameterCount = (args.length - 2) / 2;
1215
+ if (parameterCount > FLOW_QUERY_MAX_PARAMETERS) {
1216
+ throw new TypeError(`FLOW.QUERY accepts at most ${FLOW_QUERY_MAX_PARAMETERS} named parameters`);
1217
+ }
1218
+ const params = /* @__PURE__ */ Object.create(null);
1219
+ for (let index = 2; index < args.length; index += 2) {
1220
+ const name = commandText(args[index], "FLOW.QUERY parameter name");
1221
+ validateFlowQueryParameterName(name);
1222
+ if (Object.hasOwn(params, name)) {
1223
+ throw new TypeError(`FLOW.QUERY parameter ${JSON.stringify(name)} is duplicated`);
1224
+ }
1225
+ params[name] = normalizeFlowQueryParameter(args[index + 1], name);
1226
+ }
1227
+ return {
1228
+ version,
1229
+ query,
1230
+ ...parameterCount === 0 ? {} : { params }
1231
+ };
1232
+ }
1233
+ function validateFlowQueryText(query) {
1234
+ if (typeof query !== "string") throw new TypeError("FLOW.QUERY query must be text");
1235
+ if (query.trim().length === 0) throw new TypeError("FLOW.QUERY query must not be empty");
1236
+ validateUnicodeScalarText(query, "FLOW.QUERY query");
1237
+ if (Buffer4.byteLength(query, "utf8") > FLOW_QUERY_MAX_BYTES) {
1238
+ throw new TypeError(`FLOW.QUERY query exceeds ${FLOW_QUERY_MAX_BYTES} bytes`);
1239
+ }
1240
+ }
1241
+ function validateFlowQueryIndexId(indexId) {
1242
+ if (typeof indexId !== "string" || !INDEX_ID.test(indexId)) {
1243
+ throw new TypeError(
1244
+ "query index id must be 1..64 ASCII letters, digits, '_', '-', ':', or '.'"
1245
+ );
1246
+ }
1247
+ }
1248
+ function hasFlowExplainPrefix(query) {
1249
+ const source = query.trimStart();
1250
+ const prefix = source.slice(0, 7);
1251
+ return prefix.toUpperCase() === "EXPLAIN" && (source.length === 7 || /[\t\n\r ]/u.test(source[7] ?? ""));
1252
+ }
1253
+ function flowQueryParameterEntries(params) {
1254
+ if (typeof params !== "object" || params == null || Array.isArray(params)) {
1255
+ throw new TypeError("FLOW.QUERY params must be a plain object");
1256
+ }
1257
+ const prototype = Object.getPrototypeOf(params);
1258
+ if (prototype !== null && prototype !== Object.prototype) {
1259
+ throw new TypeError("FLOW.QUERY params must be a plain object");
1260
+ }
1261
+ const keys = Reflect.ownKeys(params);
1262
+ if (keys.some((key) => typeof key !== "string")) {
1263
+ throw new TypeError("FLOW.QUERY parameter names must be strings");
1264
+ }
1265
+ if (keys.length > FLOW_QUERY_MAX_PARAMETERS) {
1266
+ throw new TypeError(`FLOW.QUERY accepts at most ${FLOW_QUERY_MAX_PARAMETERS} named parameters`);
1267
+ }
1268
+ const names = keys.sort();
1269
+ return names.map((name) => {
1270
+ validateFlowQueryParameterName(name);
1271
+ return [name, normalizeFlowQueryParameter(params[name], name)];
1272
+ });
1273
+ }
1274
+ function validateFlowQueryParameterName(name) {
1275
+ validateUnicodeScalarText(name, "FLOW.QUERY parameter name");
1276
+ const size = Buffer4.byteLength(name, "utf8");
1277
+ if (size === 0 || size > FLOW_QUERY_MAX_PARAMETER_NAME_BYTES) {
1278
+ throw new TypeError(
1279
+ `FLOW.QUERY parameter names must be 1..${FLOW_QUERY_MAX_PARAMETER_NAME_BYTES} bytes`
1280
+ );
1281
+ }
1282
+ }
1283
+ function normalizeFlowQueryParameter(value, name) {
1284
+ if (typeof value === "string") {
1285
+ validateUnicodeScalarText(value, `FLOW.QUERY parameter ${JSON.stringify(name)}`);
1286
+ return value;
1287
+ }
1288
+ if (Buffer4.isBuffer(value)) return value;
1289
+ if (value instanceof Uint8Array) return Buffer4.from(value);
1290
+ if (typeof value === "boolean") return value;
1291
+ if (typeof value === "bigint" && value >= MIN_I64 && value <= MAX_I64) return value;
1292
+ if (typeof value === "number" && Number.isFinite(value)) {
1293
+ if (!Number.isInteger(value) || Number.isSafeInteger(value)) return value;
1294
+ }
1295
+ throw new TypeError(
1296
+ `FLOW.QUERY parameter ${JSON.stringify(name)} must be text, bytes, boolean, a finite float, or a signed 64-bit integer`
1297
+ );
1298
+ }
1299
+ function commandText(value, context) {
1300
+ if (typeof value === "string") {
1301
+ validateUnicodeScalarText(value, context);
1302
+ return value;
1303
+ }
1304
+ if (Buffer4.isBuffer(value) || value instanceof Uint8Array) {
1305
+ try {
1306
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
1307
+ } catch (error) {
1308
+ throw new TypeError(`${context} must be valid UTF-8`, { cause: error });
1309
+ }
1310
+ }
1311
+ throw new TypeError(`${context} must be text`);
1312
+ }
1313
+ function validateUnicodeScalarText(value, context) {
1314
+ for (let index = 0; index < value.length; index += 1) {
1315
+ const code = value.charCodeAt(index);
1316
+ if (code >= 55296 && code <= 56319) {
1317
+ const low = value.charCodeAt(index + 1);
1318
+ if (!(low >= 56320 && low <= 57343)) {
1319
+ throw new TypeError(`${context} must be valid UTF-8`);
1320
+ }
1321
+ index += 1;
1322
+ } else if (code >= 56320 && code <= 57343) {
1323
+ throw new TypeError(`${context} must be valid UTF-8`);
1324
+ }
1325
+ }
1326
+ }
1327
+
1328
+ // src/command-grammar.ts
1329
+ import { Buffer as Buffer5 } from "buffer";
1183
1330
 
1184
1331
  // src/command-metadata-flow.ts
1185
1332
  var flowStateIdCommands = /* @__PURE__ */ new Set([
@@ -1570,20 +1717,15 @@ var typeScopedFlowCommands = /* @__PURE__ */ new Set([
1570
1717
  "FLOW.ATTRIBUTE_VALUES",
1571
1718
  "FLOW.ATTRIBUTES",
1572
1719
  "FLOW.BUDGET.LIST",
1573
- "FLOW.FAILURES",
1574
1720
  "FLOW.GOVERNANCE.OVERVIEW",
1575
1721
  "FLOW.INFO",
1576
1722
  "FLOW.LIMIT.LIST",
1577
- "FLOW.LIST",
1578
1723
  "FLOW.POLICY.GET",
1579
1724
  "FLOW.POLICY.SET",
1580
1725
  "FLOW.RETENTION_CLEANUP",
1581
1726
  "FLOW.SCHEDULE.FIRE_DUE",
1582
1727
  "FLOW.SCHEDULE.LIST",
1583
- "FLOW.SEARCH",
1584
- "FLOW.STATS",
1585
- "FLOW.STUCK",
1586
- "FLOW.TERMINALS"
1728
+ "FLOW.STATS"
1587
1729
  ]);
1588
1730
  var flowScheduleCommands = /* @__PURE__ */ new Set([
1589
1731
  "FLOW.SCHEDULE.CREATE",
@@ -1626,8 +1768,8 @@ var secondKeySubcommands = /* @__PURE__ */ new Map([
1626
1768
  ]);
1627
1769
  function commandToken(value) {
1628
1770
  if (typeof value === "string") return value.toUpperCase();
1629
- if (Buffer4.isBuffer(value) || value instanceof Uint8Array) {
1630
- return Buffer4.from(value).toString("utf8").toUpperCase();
1771
+ if (Buffer5.isBuffer(value) || value instanceof Uint8Array) {
1772
+ return Buffer5.from(value).toString("utf8").toUpperCase();
1631
1773
  }
1632
1774
  return void 0;
1633
1775
  }
@@ -1730,7 +1872,7 @@ function safeIntegerArgument(value) {
1730
1872
  if (typeof value === "bigint") {
1731
1873
  return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
1732
1874
  }
1733
- const source = typeof value === "string" ? value : Buffer4.isBuffer(value) || value instanceof Uint8Array ? Buffer4.from(value).toString("utf8") : void 0;
1875
+ const source = typeof value === "string" ? value : Buffer5.isBuffer(value) || value instanceof Uint8Array ? Buffer5.from(value).toString("utf8") : void 0;
1734
1876
  if (source == null || !/^[+-]?\d+$/u.test(source)) return void 0;
1735
1877
  const parsed = BigInt(source);
1736
1878
  return parsed >= BigInt(Number.MIN_SAFE_INTEGER) && parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : void 0;
@@ -1783,7 +1925,7 @@ function hasOwnCommandArgument(args, index, end, section) {
1783
1925
  }
1784
1926
 
1785
1927
  // src/protocol-core.ts
1786
- import { Buffer as Buffer8 } from "buffer";
1928
+ import { Buffer as Buffer9 } from "buffer";
1787
1929
 
1788
1930
  // src/protocol-constants.ts
1789
1931
  import "buffer";
@@ -1881,7 +2023,6 @@ var COMMAND_OPCODES = {
1881
2023
  "FLOW.VALUE.PUT": 523,
1882
2024
  "FLOW.VALUE.MGET": 524,
1883
2025
  "FLOW.SIGNAL": 525,
1884
- "FLOW.LIST": 526,
1885
2026
  "FLOW.CREATE_MANY": 527,
1886
2027
  "FLOW.COMPLETE_MANY": 528,
1887
2028
  "FLOW.TRANSITION_MANY": 529,
@@ -1890,13 +2031,7 @@ var COMMAND_OPCODES = {
1890
2031
  "FLOW.CANCEL_MANY": 532,
1891
2032
  "FLOW.RECLAIM": 533,
1892
2033
  "FLOW.REWIND": 534,
1893
- "FLOW.TERMINALS": 535,
1894
- "FLOW.FAILURES": 536,
1895
- "FLOW.BY_PARENT": 537,
1896
- "FLOW.BY_ROOT": 538,
1897
- "FLOW.BY_CORRELATION": 539,
1898
2034
  "FLOW.INFO": 540,
1899
- "FLOW.STUCK": 541,
1900
2035
  "FLOW.POLICY.SET": 542,
1901
2036
  "FLOW.POLICY.GET": 543,
1902
2037
  "FLOW.SPAWN_CHILDREN": 544,
@@ -1915,7 +2050,7 @@ var COMMAND_OPCODES = {
1915
2050
  "FLOW.STATS": 557,
1916
2051
  "FLOW.ATTRIBUTES": 558,
1917
2052
  "FLOW.ATTRIBUTE_VALUES": 559,
1918
- "FLOW.SEARCH": 560,
2053
+ "FLOW.QUERY": 561,
1919
2054
  "FLOW.EFFECT.RESERVE": 576,
1920
2055
  "FLOW.EFFECT.CONFIRM": 577,
1921
2056
  "FLOW.EFFECT.FAIL": 578,
@@ -1998,11 +2133,13 @@ var OPCODES = {
1998
2133
  flowRetryMany: COMMAND_OPCODES["FLOW.RETRY_MANY"],
1999
2134
  flowFailMany: COMMAND_OPCODES["FLOW.FAIL_MANY"],
2000
2135
  flowReclaim: COMMAND_OPCODES["FLOW.RECLAIM"],
2136
+ flowPolicySet: COMMAND_OPCODES["FLOW.POLICY.SET"],
2137
+ flowPolicyGet: COMMAND_OPCODES["FLOW.POLICY.GET"],
2001
2138
  flowSpawnChildren: COMMAND_OPCODES["FLOW.SPAWN_CHILDREN"],
2002
2139
  flowStepContinue: COMMAND_OPCODES["FLOW.STEP_CONTINUE"],
2003
2140
  flowStartAndClaim: COMMAND_OPCODES["FLOW.START_AND_CLAIM"],
2004
2141
  flowRunStepsMany: COMMAND_OPCODES["FLOW.RUN_STEPS_MANY"],
2005
- flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
2142
+ flowQuery: COMMAND_OPCODES["FLOW.QUERY"]
2006
2143
  };
2007
2144
  var COMPACT_FLOW_CLAIM_JOBS = 128;
2008
2145
  var COMPACT_OK_LIST = 129;
@@ -2029,11 +2166,12 @@ var COMPACT_FLOW_TRANSITION_MANY_REQUEST = 155;
2029
2166
  var COMPACT_FLOW_TRANSITION_MANY_OK_REQUEST = 156;
2030
2167
  var COMPACT_FLOW_VALUE_MGET_REQUEST = 157;
2031
2168
  var COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST = 158;
2032
- var COMPACT_FLOW_LIST_REQUEST = 159;
2169
+ var COMPACT_FLOW_QUERY_RESULT = 160;
2033
2170
  var COMPACT_PIPELINE_DECODED = /* @__PURE__ */ Symbol("ferricstore.compactPipelineDecoded");
2034
2171
  var NULL_U32 = 4294967295;
2035
- var MIN_I64 = -9223372036854775808n;
2036
- var MAX_I64 = 9223372036854775807n;
2172
+ var MIN_I642 = -9223372036854775808n;
2173
+ var MAX_I642 = 9223372036854775807n;
2174
+ var MAX_U64 = 18446744073709551615n;
2037
2175
  var MAX_SAFE_INTEGER_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
2038
2176
  var MIN_SAFE_INTEGER_BIGINT = BigInt(Number.MIN_SAFE_INTEGER);
2039
2177
  var FLOW_RECORD_FIELD_KEYS = [
@@ -2082,16 +2220,16 @@ var FLOW_RECORD_FIELD_KEYS = [
2082
2220
  ];
2083
2221
 
2084
2222
  // src/protocol-text.ts
2085
- import { Buffer as Buffer6 } from "buffer";
2223
+ import { Buffer as Buffer7 } from "buffer";
2086
2224
  function toBuffer(value) {
2087
- if (Buffer6.isBuffer(value)) return value;
2088
- if (value instanceof Uint8Array) return Buffer6.from(value);
2089
- if (typeof value === "string") return Buffer6.from(value);
2225
+ if (Buffer7.isBuffer(value)) return value;
2226
+ if (value instanceof Uint8Array) return Buffer7.from(value);
2227
+ if (typeof value === "string") return Buffer7.from(value);
2090
2228
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2091
- return Buffer6.from(String(value));
2229
+ return Buffer7.from(String(value));
2092
2230
  }
2093
- if (typeof value === "symbol") return Buffer6.from(value.description ?? value.toString());
2094
- if (value == null) return Buffer6.alloc(0);
2231
+ if (typeof value === "symbol") return Buffer7.from(value.description ?? value.toString());
2232
+ if (value == null) return Buffer7.alloc(0);
2095
2233
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2096
2234
  }
2097
2235
  function asText(value) {
@@ -2099,14 +2237,14 @@ function asText(value) {
2099
2237
  }
2100
2238
  function optionalText(value) {
2101
2239
  if (value == null || value === "") return void 0;
2102
- if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || Buffer6.isBuffer(value) || value instanceof Uint8Array) {
2240
+ if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2103
2241
  return asText(value);
2104
2242
  }
2105
2243
  return void 0;
2106
2244
  }
2107
2245
  function commandTokenIs(value, expected) {
2108
2246
  if (typeof value === "string") return value.toUpperCase() === expected;
2109
- if (Buffer6.isBuffer(value) || value instanceof Uint8Array) {
2247
+ if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2110
2248
  return asText(value).toUpperCase() === expected;
2111
2249
  }
2112
2250
  return false;
@@ -2120,7 +2258,7 @@ function commandNameIs(value, expected) {
2120
2258
  }
2121
2259
 
2122
2260
  // src/request-context.ts
2123
- import { Buffer as Buffer7 } from "buffer";
2261
+ import { Buffer as Buffer8 } from "buffer";
2124
2262
  var requestContextCommands = /* @__PURE__ */ new Set([
2125
2263
  "INVOCATION.CREATE",
2126
2264
  "INVOCATION.DEFINITION.GET",
@@ -2175,9 +2313,9 @@ function requestContextCommandToken(value) {
2175
2313
  const upper = value.toUpperCase();
2176
2314
  return isRequestContextCommand(upper) ? upper : void 0;
2177
2315
  }
2178
- if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2316
+ if (Buffer8.isBuffer(value) || value instanceof Uint8Array) {
2179
2317
  if (value[0] !== 73 && value[0] !== 105) return void 0;
2180
- const command = Buffer7.from(value).toString("utf8").toUpperCase();
2318
+ const command = Buffer8.from(value).toString("utf8").toUpperCase();
2181
2319
  return isRequestContextCommand(command) ? command : void 0;
2182
2320
  }
2183
2321
  return void 0;
@@ -2208,12 +2346,12 @@ function requestContextText(context, fieldName) {
2208
2346
  return value;
2209
2347
  }
2210
2348
  function isPlainObject(value) {
2211
- return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer7.isBuffer(value) && !(value instanceof Uint8Array);
2349
+ return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer8.isBuffer(value) && !(value instanceof Uint8Array);
2212
2350
  }
2213
2351
  function commandToken2(value) {
2214
2352
  if (typeof value === "string") return value.toUpperCase();
2215
- if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2216
- return Buffer7.from(value).toString("utf8").toUpperCase();
2353
+ if (Buffer8.isBuffer(value) || value instanceof Uint8Array) {
2354
+ return Buffer8.from(value).toString("utf8").toUpperCase();
2217
2355
  }
2218
2356
  return "";
2219
2357
  }
@@ -2303,17 +2441,17 @@ function requestFrameTooLarge(maxBytes) {
2303
2441
  );
2304
2442
  }
2305
2443
  function binaryValueByteLength(value) {
2306
- if (Buffer8.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2307
- if (typeof value === "string") return Buffer8.byteLength(value);
2444
+ if (Buffer9.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2445
+ if (typeof value === "string") return Buffer9.byteLength(value);
2308
2446
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2309
- return Buffer8.byteLength(String(value));
2447
+ return Buffer9.byteLength(String(value));
2310
2448
  }
2311
- if (typeof value === "symbol") return Buffer8.byteLength(value.description ?? value.toString());
2449
+ if (typeof value === "symbol") return Buffer9.byteLength(value.description ?? value.toString());
2312
2450
  if (value == null) return 0;
2313
2451
  return toBuffer(value).byteLength;
2314
2452
  }
2315
2453
  function writeCustomPayload(output, offset, value, knownByteLength) {
2316
- if (Buffer8.isBuffer(value)) {
2454
+ if (Buffer9.isBuffer(value)) {
2317
2455
  value.copy(output, offset);
2318
2456
  return;
2319
2457
  }
@@ -2332,7 +2470,7 @@ function writeCustomPayload(output, offset, value, knownByteLength) {
2332
2470
  } else {
2333
2471
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2334
2472
  }
2335
- output.write(text3, offset, knownByteLength ?? Buffer8.byteLength(text3), "utf8");
2473
+ output.write(text3, offset, knownByteLength ?? Buffer9.byteLength(text3), "utf8");
2336
2474
  }
2337
2475
  function compactBinaryEncodedLength(value) {
2338
2476
  return 4 + compactBinaryByteLength(value);
@@ -2345,10 +2483,10 @@ function compactBinaryByteLength(value) {
2345
2483
  return byteLength;
2346
2484
  }
2347
2485
  function isCompactBinaryArgument(value) {
2348
- return typeof value === "string" || Buffer8.isBuffer(value) || value instanceof Uint8Array;
2486
+ return typeof value === "string" || Buffer9.isBuffer(value) || value instanceof Uint8Array;
2349
2487
  }
2350
2488
  function isCompactBinaryScalar(value) {
2351
- return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" || Buffer8.isBuffer(value) || value instanceof Uint8Array;
2489
+ return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" || Buffer9.isBuffer(value) || value instanceof Uint8Array;
2352
2490
  }
2353
2491
  function compactOptionalBinaryEncodedLength(value) {
2354
2492
  return value == null ? 4 : compactBinaryEncodedLength(value);
@@ -2414,7 +2552,7 @@ function integerArg(value) {
2414
2552
  throw new FerricStoreError("integer command argument must be an integer");
2415
2553
  }
2416
2554
  const integer2 = BigInt(source);
2417
- if (integer2 < MIN_I64 || integer2 > MAX_I64) {
2555
+ if (integer2 < MIN_I642 || integer2 > MAX_I642) {
2418
2556
  throw new FerricStoreError("integer command argument exceeds the signed 64-bit range");
2419
2557
  }
2420
2558
  return integer2 >= MIN_SAFE_INTEGER_BIGINT && integer2 <= MAX_SAFE_INTEGER_BIGINT ? Number(integer2) : integer2;
@@ -2445,7 +2583,7 @@ function independentMode(value) {
2445
2583
  return 0;
2446
2584
  }
2447
2585
  function optionalI64(value) {
2448
- return typeof value === "number" ? BigInt(value) : MIN_I64;
2586
+ return typeof value === "number" ? BigInt(value) : MIN_I642;
2449
2587
  }
2450
2588
  function compactClaimReturnMode(value) {
2451
2589
  const mode = value == null ? "" : asText(value).toUpperCase();
@@ -2479,18 +2617,18 @@ function setOwnValue2(target, key, value) {
2479
2617
  }
2480
2618
 
2481
2619
  // src/protocol-flow-options.ts
2482
- import { Buffer as Buffer9 } from "buffer";
2620
+ import { Buffer as Buffer10 } from "buffer";
2483
2621
 
2484
2622
  // src/protocol-flow-option-value.ts
2485
- function setFlowOptionValue(payload, field2, value, repeat) {
2486
- if (!repeat || !Object.hasOwn(payload, field2)) {
2487
- setOwnValue2(payload, field2, value);
2623
+ function setFlowOptionValue(payload, field3, value, repeat) {
2624
+ if (!repeat || !Object.hasOwn(payload, field3)) {
2625
+ setOwnValue2(payload, field3, value);
2488
2626
  return;
2489
2627
  }
2490
- const previous = payload[field2];
2628
+ const previous = payload[field3];
2491
2629
  setOwnValue2(
2492
2630
  payload,
2493
- field2,
2631
+ field3,
2494
2632
  Array.isArray(previous) ? [...previous, value] : [previous, value]
2495
2633
  );
2496
2634
  }
@@ -2533,44 +2671,30 @@ function optionMap(args) {
2533
2671
  index += 3;
2534
2672
  continue;
2535
2673
  }
2536
- const field2 = OPTION_FIELDS[token] ?? token.toLowerCase();
2674
+ const field3 = OPTION_FIELDS[token] ?? token.toLowerCase();
2537
2675
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow options")) {
2538
2676
  throw new FerricStoreError(`${token} requires a value`);
2539
2677
  }
2540
2678
  const value = args[index + 1];
2541
- if (BOOL_OPTION_FIELDS.has(field2) && !isBoolToken(value)) {
2679
+ if (BOOL_OPTION_FIELDS.has(field3) && !isBoolToken(value)) {
2542
2680
  return void 0;
2543
2681
  }
2544
- setOwnValue2(payload, field2, BOOL_OPTION_FIELDS.has(field2) ? boolArg(value) : value);
2682
+ setOwnValue2(payload, field3, BOOL_OPTION_FIELDS.has(field3) ? boolArg(value) : value);
2545
2683
  index += 2;
2546
2684
  }
2547
2685
  return payload;
2548
2686
  }
2549
- function ensureObjectField(payload, field2) {
2550
- const value = payload[field2];
2687
+ function ensureObjectField(payload, field3) {
2688
+ const value = payload[field3];
2551
2689
  if (isPlainObject2(value)) {
2552
2690
  return value;
2553
2691
  }
2554
2692
  const next = {};
2555
- setOwnValue2(payload, field2, next);
2693
+ setOwnValue2(payload, field3, next);
2556
2694
  return next;
2557
2695
  }
2558
- function normalizeFlowSearchStateMeta(payload) {
2559
- const stateMeta = payload.state_meta;
2560
- if (!isPlainObject2(stateMeta) || Object.keys(stateMeta).length === 0) {
2561
- return;
2562
- }
2563
- if (Object.values(stateMeta).every(isPlainObject2)) {
2564
- return;
2565
- }
2566
- const state = payload.state;
2567
- if (state == null) {
2568
- throw new FerricStoreError("FLOW.SEARCH STATE_META filters require STATE or nested state metadata");
2569
- }
2570
- payload.state_meta = { [asText(state)]: stateMeta };
2571
- }
2572
2696
  function isPlainObject2(value) {
2573
- return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer9.isBuffer(value) && !(value instanceof Uint8Array);
2697
+ return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer10.isBuffer(value) && !(value instanceof Uint8Array);
2574
2698
  }
2575
2699
  function parseFlowOptions(args, start, end, config) {
2576
2700
  const payload = {};
@@ -2664,9 +2788,9 @@ function parseFlowOptions(args, start, end, config) {
2664
2788
  case "TRANSITION_TO":
2665
2789
  case "TO_EVENT":
2666
2790
  case "EXPECT_STATE": {
2667
- const field2 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2791
+ const field3 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2668
2792
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2669
- setFlowOptionValue(payload, field2, args[index + 1], token === "IF_STATE");
2793
+ setFlowOptionValue(payload, field3, args[index + 1], token === "IF_STATE");
2670
2794
  index += 2;
2671
2795
  break;
2672
2796
  }
@@ -2674,8 +2798,8 @@ function parseFlowOptions(args, start, end, config) {
2674
2798
  case "RESULT":
2675
2799
  case "ERROR":
2676
2800
  case "REASON": {
2677
- const field2 = token === "LEASE_TOKEN" ? "lease_token" : token.toLowerCase();
2678
- if (!putScalar(payload, field2, args, index + 1, end)) return void 0;
2801
+ const field3 = token === "LEASE_TOKEN" ? "lease_token" : token.toLowerCase();
2802
+ if (!putScalar(payload, field3, args, index + 1, end)) return void 0;
2679
2803
  index += 2;
2680
2804
  break;
2681
2805
  }
@@ -2697,8 +2821,8 @@ function parseFlowOptions(args, start, end, config) {
2697
2821
  case "VALUE_REF":
2698
2822
  case "STATE_META": {
2699
2823
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options") || !hasOwnCommandArgument(args, index + 2, end, "Flow options")) return void 0;
2700
- const field2 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "VALUE_REF" ? "value_refs" : "state_meta";
2701
- const values = ensureObjectField(payload, field2);
2824
+ const field3 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "VALUE_REF" ? "value_refs" : "state_meta";
2825
+ const values = ensureObjectField(payload, field3);
2702
2826
  setOwnValue2(values, asText(args[index + 1]), args[index + 2]);
2703
2827
  index += 3;
2704
2828
  break;
@@ -2707,8 +2831,8 @@ function parseFlowOptions(args, start, end, config) {
2707
2831
  case "OVERRIDE_VALUE":
2708
2832
  case "ATTRIBUTE_DELETE": {
2709
2833
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2710
- const field2 = token === "DROP_VALUE" ? "drop_values" : token === "OVERRIDE_VALUE" ? "override_values" : "attributes_delete";
2711
- const values = ensureArrayField(payload, field2);
2834
+ const field3 = token === "DROP_VALUE" ? "drop_values" : token === "OVERRIDE_VALUE" ? "override_values" : "attributes_delete";
2835
+ const values = ensureArrayField(payload, field3);
2712
2836
  values.push(args[index + 1]);
2713
2837
  index += 2;
2714
2838
  break;
@@ -2825,13 +2949,13 @@ function putScalar(payload, key, args, index, end) {
2825
2949
  setOwnValue2(payload, key, args[index]);
2826
2950
  return true;
2827
2951
  }
2828
- function ensureArrayField(payload, field2) {
2829
- const value = payload[field2];
2952
+ function ensureArrayField(payload, field3) {
2953
+ const value = payload[field3];
2830
2954
  if (Array.isArray(value)) {
2831
2955
  return value;
2832
2956
  }
2833
2957
  const next = [];
2834
- setOwnValue2(payload, field2, next);
2958
+ setOwnValue2(payload, field3, next);
2835
2959
  return next;
2836
2960
  }
2837
2961
  function putNumber(payload, key, args, index, end) {
@@ -3052,8 +3176,8 @@ function flowHistoryPayload(args) {
3052
3176
  case "CONSISTENT_PROJECTION":
3053
3177
  case "VALUES": {
3054
3178
  if (!isBoolToken(value)) return void 0;
3055
- const field2 = token === "REV" ? "rev" : token === "INCLUDE_COLD" ? "include_cold" : token === "CONSISTENT_PROJECTION" ? "consistent_projection" : "values";
3056
- payload[field2] = boolArg(value);
3179
+ const field3 = token === "REV" ? "rev" : token === "INCLUDE_COLD" ? "include_cold" : token === "CONSISTENT_PROJECTION" ? "consistent_projection" : "values";
3180
+ payload[field3] = boolArg(value);
3057
3181
  break;
3058
3182
  }
3059
3183
  default:
@@ -3065,9 +3189,9 @@ function flowHistoryPayload(args) {
3065
3189
  function flowAdminPayload(opcode, args, leadingFields = []) {
3066
3190
  if (args.length < leadingFields.length) return void 0;
3067
3191
  const payload = {};
3068
- for (const [index, field2] of leadingFields.entries()) {
3192
+ for (const [index, field3] of leadingFields.entries()) {
3069
3193
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
3070
- setOwnValue2(payload, field2, args[index]);
3194
+ setOwnValue2(payload, field3, args[index]);
3071
3195
  }
3072
3196
  for (let index = leadingFields.length; index < args.length; ) {
3073
3197
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
@@ -3075,15 +3199,15 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3075
3199
  if (token == null) return void 0;
3076
3200
  if (["ATTRIBUTE", "ATTRIBUTE_MERGE", "STATE_META", "VALUE", "VALUE_REF"].includes(token)) {
3077
3201
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments") || !hasOwnCommandArgument(args, index + 2, args.length, "Flow admin arguments")) return void 0;
3078
- const field3 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "STATE_META" ? "state_meta" : token === "VALUE" ? "values" : "value_refs";
3079
- setOwnValue2(ensureObjectField(payload, field3), asText(args[index + 1]), args[index + 2]);
3202
+ const field4 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "STATE_META" ? "state_meta" : token === "VALUE" ? "values" : "value_refs";
3203
+ setOwnValue2(ensureObjectField(payload, field4), asText(args[index + 1]), args[index + 2]);
3080
3204
  index += 3;
3081
3205
  continue;
3082
3206
  }
3083
3207
  if (token === "ATTRIBUTE_DELETE" || token === "DROP_VALUE" || token === "OVERRIDE_VALUE") {
3084
3208
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) return void 0;
3085
- const field3 = token === "ATTRIBUTE_DELETE" ? "attributes_delete" : token === "DROP_VALUE" ? "drop_values" : "override_values";
3086
- ensureArrayField(payload, field3).push(args[index + 1]);
3209
+ const field4 = token === "ATTRIBUTE_DELETE" ? "attributes_delete" : token === "DROP_VALUE" ? "drop_values" : "override_values";
3210
+ ensureArrayField(payload, field4).push(args[index + 1]);
3087
3211
  index += 2;
3088
3212
  continue;
3089
3213
  }
@@ -3102,13 +3226,13 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3102
3226
  index += 2 + count;
3103
3227
  continue;
3104
3228
  }
3105
- const field2 = FLOW_ADMIN_FIELDS[token];
3106
- if (field2 == null || !hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) {
3229
+ const field3 = FLOW_ADMIN_FIELDS[token];
3230
+ if (field3 == null || !hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) {
3107
3231
  return void 0;
3108
3232
  }
3109
3233
  const rawValue = args[index + 1];
3110
- if (FLOW_ADMIN_BOOLEAN_FIELDS.has(field2) && !isBoolToken(rawValue)) return void 0;
3111
- setOwnValue2(payload, field2, FLOW_ADMIN_BOOLEAN_FIELDS.has(field2) ? boolArg(rawValue) : rawValue);
3234
+ if (FLOW_ADMIN_BOOLEAN_FIELDS.has(field3) && !isBoolToken(rawValue)) return void 0;
3235
+ setOwnValue2(payload, field3, FLOW_ADMIN_BOOLEAN_FIELDS.has(field3) ? boolArg(rawValue) : rawValue);
3112
3236
  index += 2;
3113
3237
  }
3114
3238
  const serverBlockMs = opcode === COMMAND_OPCODES["FLOW.SCHEDULE.FIRE_DUE"] && payload.block_ms != null ? blockDurationMs(payload.block_ms, 1) : void 0;
@@ -3116,7 +3240,7 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3116
3240
  }
3117
3241
 
3118
3242
  // src/protocol-flow-compact.ts
3119
- import { Buffer as Buffer11 } from "buffer";
3243
+ import { Buffer as Buffer12 } from "buffer";
3120
3244
 
3121
3245
  // src/protocol-flow-compact-common.ts
3122
3246
  function compactManyRequestTag(value, regularTag, okOnSuccessTag) {
@@ -3225,7 +3349,7 @@ function parseNamedCountMap(values, start) {
3225
3349
  }
3226
3350
 
3227
3351
  // src/protocol-flow-compact-transition.ts
3228
- import { Buffer as Buffer10 } from "buffer";
3352
+ import { Buffer as Buffer11 } from "buffer";
3229
3353
  function compactFlowTransitionManyPayload(partition, fromState, toState, rawItems, mixed, options, maxBodyBytes) {
3230
3354
  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) {
3231
3355
  return void 0;
@@ -3277,7 +3401,7 @@ function compactFlowTransitionManyPayload(partition, fromState, toState, rawItem
3277
3401
  total += 4 + idLength + 4 + itemPartitionLength + 8 + 4 + leaseLength;
3278
3402
  }
3279
3403
  assertCompactPayloadFits(total, maxBodyBytes);
3280
- const out = Buffer10.allocUnsafe(total);
3404
+ const out = Buffer11.allocUnsafe(total);
3281
3405
  let offset = 0;
3282
3406
  out.writeUInt8(tag, offset);
3283
3407
  offset += 1;
@@ -3335,7 +3459,7 @@ function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options,
3335
3459
  }
3336
3460
  assertCompactPayloadFits(total, maxBodyBytes);
3337
3461
  const tag = mixed ? COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST : auto ? COMPACT_FLOW_CREATE_MANY_REQUEST : COMPACT_FLOW_CREATE_MANY_PARTITION_REQUEST;
3338
- const out = Buffer11.allocUnsafe(total);
3462
+ const out = Buffer12.allocUnsafe(total);
3339
3463
  let offset = 0;
3340
3464
  out.writeUInt8(tag, offset++);
3341
3465
  offset = writeBinary(out, offset, toBuffer(options.type));
@@ -3380,7 +3504,7 @@ function compactFlowClaimDuePayload(type, options, maxBodyBytes) {
3380
3504
  total += 1;
3381
3505
  }
3382
3506
  assertCompactPayloadFits(total, maxBodyBytes);
3383
- const out = Buffer11.allocUnsafe(total);
3507
+ const out = Buffer12.allocUnsafe(total);
3384
3508
  let offset = 0;
3385
3509
  out.writeUInt8(COMPACT_FLOW_CLAIM_DUE_REQUEST, offset++);
3386
3510
  offset = writeBinary(out, offset, toBuffer(type));
@@ -3434,7 +3558,7 @@ function compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto
3434
3558
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3435
3559
  }
3436
3560
  assertCompactPayloadFits(total, maxBodyBytes);
3437
- const out = Buffer11.allocUnsafe(total);
3561
+ const out = Buffer12.allocUnsafe(total);
3438
3562
  let offset = 0;
3439
3563
  out.writeUInt8(
3440
3564
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_COMPLETE_MANY_OK_REQUEST : COMPACT_FLOW_COMPLETE_MANY_REQUEST,
@@ -3481,7 +3605,7 @@ function compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options,
3481
3605
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3482
3606
  }
3483
3607
  assertCompactPayloadFits(total, maxBodyBytes);
3484
- const out = Buffer11.allocUnsafe(total);
3608
+ const out = Buffer12.allocUnsafe(total);
3485
3609
  let offset = 0;
3486
3610
  out.writeUInt8(
3487
3611
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_RETRY_MANY_OK_REQUEST : COMPACT_FLOW_RETRY_MANY_REQUEST,
@@ -3569,7 +3693,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3569
3693
  total += 4 + idLength + 4 + itemPartitionLength + 8;
3570
3694
  }
3571
3695
  assertCompactPayloadFits(total, maxBodyBytes);
3572
- const out = Buffer11.allocUnsafe(total);
3696
+ const out = Buffer12.allocUnsafe(total);
3573
3697
  let offset = 0;
3574
3698
  out.writeUInt8(tag, offset);
3575
3699
  offset += 1;
@@ -3592,6 +3716,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3592
3716
  offset += 8;
3593
3717
  }
3594
3718
  return {
3719
+ compactResponseItems: count,
3595
3720
  flags: FLAG_CUSTOM_PAYLOAD,
3596
3721
  opcode: COMMAND_OPCODES["FLOW.CANCEL_MANY"],
3597
3722
  payload: out
@@ -3605,7 +3730,7 @@ function isOptionalSafeIntegerNumber(value) {
3605
3730
  }
3606
3731
 
3607
3732
  // src/protocol-flow-compact-single.ts
3608
- import { Buffer as Buffer12 } from "buffer";
3733
+ import { Buffer as Buffer13 } from "buffer";
3609
3734
  function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3610
3735
  if (refs.length > 4294967295 || maxBytes != null && (typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 0)) return void 0;
3611
3736
  const minimum = 13 + refs.length * 4;
@@ -3622,7 +3747,7 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3622
3747
  total += 4 + byteLength;
3623
3748
  }
3624
3749
  assertCompactPayloadFits(total, maxBodyBytes);
3625
- const out = Buffer12.allocUnsafe(total);
3750
+ const out = Buffer13.allocUnsafe(total);
3626
3751
  let offset = 0;
3627
3752
  out.writeUInt8(COMPACT_FLOW_VALUE_MGET_REQUEST, offset);
3628
3753
  offset += 1;
@@ -3635,47 +3760,6 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3635
3760
  }
3636
3761
  return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.flowValueMGet, payload: out };
3637
3762
  }
3638
- function compactFlowListPayload(args, maxBodyBytes) {
3639
- const type = args[0];
3640
- if (!isCompactBinaryArgument(type)) return void 0;
3641
- let state;
3642
- let count = 100;
3643
- let returnMode = 0;
3644
- const seen = /* @__PURE__ */ new Set();
3645
- for (let index = 1; index < args.length; index += 2) {
3646
- if (index + 1 >= args.length) return void 0;
3647
- const token = asText(args[index]).toUpperCase();
3648
- if (seen.has(token)) return void 0;
3649
- seen.add(token);
3650
- if (token === "STATE") {
3651
- if (!isCompactBinaryArgument(args[index + 1])) return void 0;
3652
- state = args[index + 1];
3653
- } else if (token === "COUNT") {
3654
- const value = safeIntegerNumberArg(args[index + 1]);
3655
- if (value <= 0) return void 0;
3656
- count = value;
3657
- } else if (token === "RETURN") {
3658
- if (!commandTokenIs(args[index + 1], "META")) return void 0;
3659
- returnMode = 1;
3660
- } else {
3661
- return void 0;
3662
- }
3663
- }
3664
- const typeLength = compactBinaryByteLength(type);
3665
- const stateLength = state == null ? 0 : compactBinaryByteLength(state);
3666
- const total = 1 + 4 + typeLength + 4 + stateLength + 8 + 1;
3667
- assertCompactPayloadFits(total, maxBodyBytes);
3668
- const out = Buffer12.allocUnsafe(total);
3669
- let offset = 0;
3670
- out.writeUInt8(COMPACT_FLOW_LIST_REQUEST, offset);
3671
- offset += 1;
3672
- offset = writeBinaryValue(out, offset, type, typeLength);
3673
- offset = writeOptionalBinaryValue(out, offset, state, stateLength);
3674
- out.writeBigInt64BE(BigInt(count), offset);
3675
- offset += 8;
3676
- out.writeUInt8(returnMode, offset);
3677
- return { flags: FLAG_CUSTOM_PAYLOAD, opcode: COMMAND_OPCODES["FLOW.LIST"], payload: out };
3678
- }
3679
3763
 
3680
3764
  // src/protocol-flow-routing.ts
3681
3765
  function withFlowPartitionRouting(command, payload) {
@@ -3724,15 +3808,6 @@ function expandFlowClaimStates(args) {
3724
3808
  }
3725
3809
 
3726
3810
  // src/protocol-flow.ts
3727
- function hasFlowCommandOnlyOption(command, args) {
3728
- if (command !== "FLOW.SEARCH") return false;
3729
- for (let index = 1; index < args.length; ) {
3730
- const token = asText(args[index]).toUpperCase();
3731
- if (token === "INDEXED_STATE_META") return true;
3732
- index += token === "ATTRIBUTE" || token === "STATE_META" ? 3 : 2;
3733
- }
3734
- return false;
3735
- }
3736
3811
  function flowCreatePayload(args) {
3737
3812
  if (args.length < 7) return void 0;
3738
3813
  const id = args[0];
@@ -3789,9 +3864,9 @@ function flowValueMGetPayload(args, maxBodyBytes, allowCompact) {
3789
3864
  }
3790
3865
  if (allowCompact) {
3791
3866
  const compact = compactFlowValueMGetPayload(refs, payload.max_bytes, maxBodyBytes);
3792
- if (compact != null) return compact;
3867
+ if (compact != null) return { ...compact, compactResponseItems: refs.length };
3793
3868
  }
3794
- return { opcode: OPCODES.flowValueMGet, payload };
3869
+ return { compactResponseItems: refs.length, opcode: OPCODES.flowValueMGet, payload };
3795
3870
  }
3796
3871
  function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3797
3872
  if (args.length < 2) return void 0;
@@ -3827,7 +3902,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3827
3902
  if (items2 == null) return void 0;
3828
3903
  const payload2 = { ...options, items: items2 };
3829
3904
  if (!auto && !mixed) payload2.partition_key = partition;
3830
- return { opcode: OPCODES.flowCreateMany, payload: payload2 };
3905
+ return { compactResponseItems: items2.length, opcode: OPCODES.flowCreateMany, payload: payload2 };
3831
3906
  }
3832
3907
  const rawItems = denseCommandArgumentTail(args, itemsIndex + 1, "ITEMS");
3833
3908
  const width = mixed ? 3 : 2;
@@ -3841,7 +3916,9 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3841
3916
  options,
3842
3917
  maxBodyBytes
3843
3918
  );
3844
- if (compact != null) return compact;
3919
+ if (compact != null) {
3920
+ return { ...compact, compactResponseItems: rawItems.length / width };
3921
+ }
3845
3922
  }
3846
3923
  const items = [];
3847
3924
  for (let index = 0; index < rawItems.length; index += width) {
@@ -3853,7 +3930,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3853
3930
  }
3854
3931
  const payload = { ...options, items };
3855
3932
  if (!auto && !mixed) payload.partition_key = partition;
3856
- return { opcode: OPCODES.flowCreateMany, payload };
3933
+ return { compactResponseItems: items.length, opcode: OPCODES.flowCreateMany, payload };
3857
3934
  }
3858
3935
  function flowClaimDuePayload(args, maxBodyBytes, allowCompact) {
3859
3936
  if (args.length < 1) return void 0;
@@ -4016,7 +4093,9 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4016
4093
  if (rawItems.length === 0 || rawItems.length % width !== 0) return void 0;
4017
4094
  if (allowCompact) {
4018
4095
  const compact = command === "FLOW.RETRY_MANY" ? compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options, maxBodyBytes) : compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto, options, maxBodyBytes);
4019
- if (compact != null) return compact;
4096
+ if (compact != null) {
4097
+ return { ...compact, compactResponseItems: rawItems.length / width };
4098
+ }
4020
4099
  }
4021
4100
  const items = [];
4022
4101
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4028,7 +4107,7 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4028
4107
  }
4029
4108
  const payload = { ...options, items };
4030
4109
  if (!auto && !mixed) payload.partition_key = partition;
4031
- return { opcode, payload };
4110
+ return { compactResponseItems: items.length, opcode, payload };
4032
4111
  }
4033
4112
  function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4034
4113
  if (args.length < 4) return void 0;
@@ -4068,7 +4147,9 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4068
4147
  options,
4069
4148
  maxBodyBytes
4070
4149
  ) : void 0;
4071
- if (compact != null) return compact;
4150
+ if (compact != null) {
4151
+ return { ...compact, compactResponseItems: rawItems.length / width };
4152
+ }
4072
4153
  }
4073
4154
  const items = [];
4074
4155
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4088,7 +4169,11 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4088
4169
  items
4089
4170
  };
4090
4171
  if (!mixed) payload.partition_key = args[0];
4091
- return { opcode: OPCODES.flowTransitionMany, payload };
4172
+ return {
4173
+ compactResponseItems: items.length,
4174
+ opcode: OPCODES.flowTransitionMany,
4175
+ payload
4176
+ };
4092
4177
  }
4093
4178
  function flowSpawnChildrenPayload(args) {
4094
4179
  if (args.length < 2) return void 0;
@@ -4131,13 +4216,6 @@ function flowSpawnChildrenPayload(args) {
4131
4216
  payload: { id: args[0], ...options, children }
4132
4217
  };
4133
4218
  }
4134
- function flowSearchPayload(args) {
4135
- if (args.length < 1) return void 0;
4136
- const payload = optionMap(args.slice(1));
4137
- if (payload == null) return void 0;
4138
- normalizeFlowSearchStateMeta(payload);
4139
- return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
4140
- }
4141
4219
 
4142
4220
  // src/protocol-flow-signal.ts
4143
4221
  function flowSignalPayload(args) {
@@ -4162,6 +4240,162 @@ function flowSignalPayload(args) {
4162
4240
  return { opcode: OPCODES.flowSignal, payload: { id: args[0], ...options } };
4163
4241
  }
4164
4242
 
4243
+ // src/protocol-flow-policy.ts
4244
+ import { Buffer as Buffer14 } from "buffer";
4245
+ var BACKOFF_FIELDS = {
4246
+ BASE_MS: "base_ms",
4247
+ MAX_MS: "max_ms",
4248
+ JITTER_PCT: "jitter_pct"
4249
+ };
4250
+ var RETENTION_FIELDS = {
4251
+ RETENTION_TTL: "ttl_ms",
4252
+ RETENTION_TTL_MS: "ttl_ms",
4253
+ HISTORY_MAX_EVENTS: "history_max_events"
4254
+ };
4255
+ function flowPolicySetPayload(args) {
4256
+ if (!hasOwnCommandArgument(args, 0, args.length, "Flow policy arguments")) return void 0;
4257
+ if (!isBinaryArgument(args[0])) return void 0;
4258
+ const payload = { type: args[0] };
4259
+ const states = {};
4260
+ let target = payload;
4261
+ for (let index = 1; index < args.length; index += 2) {
4262
+ if (!hasOwnCommandArgument(args, index, args.length, "Flow policy arguments") || !hasOwnCommandArgument(args, index + 1, args.length, "Flow policy arguments")) return void 0;
4263
+ const token = optionalText(args[index])?.toUpperCase();
4264
+ const value = args[index + 1];
4265
+ if (token == null || value == null) return void 0;
4266
+ if (token === "STATE") {
4267
+ if (!isBinaryArgument(value)) return void 0;
4268
+ const state = asText(value);
4269
+ target = {};
4270
+ setOwnValue2(states, state, target);
4271
+ setOwnValue2(payload, "states", states);
4272
+ continue;
4273
+ }
4274
+ if (token === "MODE") {
4275
+ if (!isBinaryArgument(value)) return void 0;
4276
+ const mode = optionalText(value)?.toLowerCase();
4277
+ if (target === payload || mode !== "fifo" && mode !== "parallel") return void 0;
4278
+ setOwnValue2(target, "mode", mode);
4279
+ continue;
4280
+ }
4281
+ if (token === "EXPECTED_GENERATION") {
4282
+ if (target !== payload) return void 0;
4283
+ const generation = integerOption(value);
4284
+ if (generation == null || generation < 0) return void 0;
4285
+ setOwnValue2(payload, "expected_generation", generation);
4286
+ continue;
4287
+ }
4288
+ if (token === "REPLACE") {
4289
+ if (target !== payload || !isBoolToken(value)) return void 0;
4290
+ setOwnValue2(payload, "replace", boolArg(value));
4291
+ continue;
4292
+ }
4293
+ if (token === "MAX_ACTIVE_MS") {
4294
+ if (target !== payload) return void 0;
4295
+ const maxActiveMs = maxActiveOption(value);
4296
+ if (maxActiveMs == null) return void 0;
4297
+ setOwnValue2(payload, "max_active_ms", maxActiveMs);
4298
+ continue;
4299
+ }
4300
+ if (token === "INDEXED_STATE_META") {
4301
+ if (target !== payload || !isBinaryArgument(value)) return void 0;
4302
+ setOwnValue2(payload, "indexed_state_meta", value);
4303
+ continue;
4304
+ }
4305
+ if (token === "INDEXED_ATTRIBUTES") {
4306
+ if (target !== payload) return void 0;
4307
+ const names = indexedAttributes(value);
4308
+ if (names == null) return void 0;
4309
+ setOwnValue2(payload, "indexed_attributes", names);
4310
+ continue;
4311
+ }
4312
+ if (token === "MAX_RETRIES") {
4313
+ const parsed = integerOption(value);
4314
+ if (parsed == null) return void 0;
4315
+ setOwnValue2(objectField(target, "retry"), "max_retries", parsed);
4316
+ continue;
4317
+ }
4318
+ if (token === "EXHAUSTED_TO") {
4319
+ if (!isBinaryArgument(value)) return void 0;
4320
+ setOwnValue2(objectField(target, "retry"), "exhausted_to", value);
4321
+ continue;
4322
+ }
4323
+ const backoffField = BACKOFF_FIELDS[token];
4324
+ if (backoffField != null) {
4325
+ const parsed = integerOption(value);
4326
+ if (parsed == null) return void 0;
4327
+ setOwnValue2(objectField(objectField(target, "retry"), "backoff"), backoffField, parsed);
4328
+ continue;
4329
+ }
4330
+ if (token === "BACKOFF") {
4331
+ if (!isBinaryArgument(value)) return void 0;
4332
+ const kind = optionalText(value)?.toLowerCase();
4333
+ if (kind == null) return void 0;
4334
+ setOwnValue2(objectField(objectField(target, "retry"), "backoff"), "kind", kind);
4335
+ continue;
4336
+ }
4337
+ const retentionField = RETENTION_FIELDS[token];
4338
+ if (retentionField != null) {
4339
+ if (target === payload) return void 0;
4340
+ const parsed = integerOption(value);
4341
+ if (parsed == null) return void 0;
4342
+ setOwnValue2(objectField(target, "retention"), retentionField, parsed);
4343
+ continue;
4344
+ }
4345
+ return void 0;
4346
+ }
4347
+ return { opcode: OPCODES.flowPolicySet, payload };
4348
+ }
4349
+ function flowPolicyGetPayload(args) {
4350
+ if (!hasOwnCommandArgument(args, 0, args.length, "Flow policy arguments")) return void 0;
4351
+ if (!isBinaryArgument(args[0])) return void 0;
4352
+ if (args.length !== 1 && args.length !== 3) return void 0;
4353
+ const payload = { type: args[0] };
4354
+ if (args.length === 3) {
4355
+ 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;
4356
+ setOwnValue2(payload, "state", args[2]);
4357
+ }
4358
+ return { opcode: OPCODES.flowPolicyGet, payload };
4359
+ }
4360
+ function integerOption(value) {
4361
+ try {
4362
+ return safeIntegerNumberArg(value);
4363
+ } catch {
4364
+ return void 0;
4365
+ }
4366
+ }
4367
+ function maxActiveOption(value) {
4368
+ if (isBinaryArgument(value) && asText(value).toLowerCase() === "infinity") {
4369
+ return "infinity";
4370
+ }
4371
+ return integerOption(value);
4372
+ }
4373
+ function isBinaryArgument(value) {
4374
+ return typeof value === "string" || Buffer14.isBuffer(value) || value instanceof Uint8Array;
4375
+ }
4376
+ function objectField(target, name) {
4377
+ const existing = Object.hasOwn(target, name) ? target[name] : void 0;
4378
+ if (typeof existing === "object" && existing != null && !Array.isArray(existing)) {
4379
+ return existing;
4380
+ }
4381
+ const value = {};
4382
+ setOwnValue2(target, name, value);
4383
+ return value;
4384
+ }
4385
+ function indexedAttributes(value) {
4386
+ if (Array.isArray(value)) {
4387
+ return value.every((item) => typeof item === "string") ? value : void 0;
4388
+ }
4389
+ const source = optionalText(value);
4390
+ if (source == null) return void 0;
4391
+ try {
4392
+ const parsed = JSON.parse(source);
4393
+ return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : void 0;
4394
+ } catch {
4395
+ return void 0;
4396
+ }
4397
+ }
4398
+
4165
4399
  // src/protocol-connection-policy.ts
4166
4400
  function assertCommandDoesNotRequirePinnedConnection(args) {
4167
4401
  const outer = commandName(args[0]);
@@ -4209,7 +4443,7 @@ function commandRequiresOrderedPipelineExecution(args) {
4209
4443
  }
4210
4444
 
4211
4445
  // src/protocol-compact-request.ts
4212
- import { Buffer as Buffer13 } from "buffer";
4446
+ import { Buffer as Buffer15 } from "buffer";
4213
4447
  function compactMsetPayload(args, maxBodyBytes) {
4214
4448
  if (args.length % 2 !== 0) throw new FerricStoreError("MSET requires key/value pairs");
4215
4449
  const minimum = 6 + args.length * 4;
@@ -4228,7 +4462,7 @@ function compactMsetPayload(args, maxBodyBytes) {
4228
4462
  total += 4 + byteLength;
4229
4463
  }
4230
4464
  assertCompactPayloadFits(total, maxBodyBytes);
4231
- const out = Buffer13.allocUnsafe(total);
4465
+ const out = Buffer15.allocUnsafe(total);
4232
4466
  let offset = writeCompactPipelineHeader(out, 1, args.length / 2);
4233
4467
  for (let index = 0; index < args.length; index += 1) {
4234
4468
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4252,7 +4486,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4252
4486
  total += 4 + byteLength;
4253
4487
  }
4254
4488
  assertCompactPayloadFits(total, maxBodyBytes);
4255
- const out = Buffer13.allocUnsafe(total);
4489
+ const out = Buffer15.allocUnsafe(total);
4256
4490
  let offset = writeCompactPipelineHeader(out, mode, args.length);
4257
4491
  for (let index = 0; index < args.length; index += 1) {
4258
4492
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4262,7 +4496,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4262
4496
  function compactPipelinePayload(commands, maxBodyBytes) {
4263
4497
  if (commands.length === 0) {
4264
4498
  assertCompactPayloadFits(6, maxBodyBytes);
4265
- const out = Buffer13.allocUnsafe(6);
4499
+ const out = Buffer15.allocUnsafe(6);
4266
4500
  writeCompactPipelineHeader(out, 128 | 2, 0);
4267
4501
  return out;
4268
4502
  }
@@ -4304,7 +4538,7 @@ function compactSetPipelinePayload(commands, maxBodyBytes) {
4304
4538
  total += 8 + keyByteLength + valueByteLength;
4305
4539
  }
4306
4540
  assertCompactPayloadFits(total, maxBodyBytes);
4307
- const out = Buffer13.allocUnsafe(total);
4541
+ const out = Buffer15.allocUnsafe(total);
4308
4542
  let offset = writeCompactPipelineHeader(out, 128 | 1, commands.length);
4309
4543
  for (let index = 0; index < commands.length; index += 1) {
4310
4544
  offset = writeBinaryValue(out, offset, argumentValues[index * 2], argumentByteLengths[index * 2] ?? 0);
@@ -4339,7 +4573,7 @@ function compactGetPipelinePayload(commands, maxBodyBytes) {
4339
4573
  total += 4 + keyByteLength;
4340
4574
  }
4341
4575
  assertCompactPayloadFits(total, maxBodyBytes);
4342
- const out = Buffer13.allocUnsafe(total);
4576
+ const out = Buffer15.allocUnsafe(total);
4343
4577
  let offset = writeCompactPipelineHeader(out, 128 | 2, commands.length);
4344
4578
  for (let index = 0; index < commands.length; index += 1) {
4345
4579
  offset = writeBinaryValue(out, offset, keys[index], keyByteLengths[index] ?? 0);
@@ -4353,7 +4587,7 @@ function compactArgumentsEligible(args, sparseMessage) {
4353
4587
  }
4354
4588
  return true;
4355
4589
  }
4356
- function compactPipelineEligible(commands, commandName4, argumentCount) {
4590
+ function compactPipelineEligible(commands, commandName5, argumentCount) {
4357
4591
  for (let index = 0; index < commands.length; index += 1) {
4358
4592
  const command = commands[index];
4359
4593
  if (!Object.hasOwn(commands, index) || !Array.isArray(command)) {
@@ -4365,7 +4599,7 @@ function compactPipelineEligible(commands, commandName4, argumentCount) {
4365
4599
  throw new TypeError("pipeline command arguments must be dense");
4366
4600
  }
4367
4601
  }
4368
- if (!commandNameIs(command[0], commandName4)) return false;
4602
+ if (!commandNameIs(command[0], commandName5)) return false;
4369
4603
  for (let argumentIndex = 1; argumentIndex < argumentCount; argumentIndex += 1) {
4370
4604
  if (!isCompactBinaryScalar(command[argumentIndex])) return false;
4371
4605
  }
@@ -4380,7 +4614,7 @@ function writeCompactPipelineHeader(out, mode, count) {
4380
4614
  }
4381
4615
 
4382
4616
  // src/protocol-kv.ts
4383
- import { Buffer as Buffer14 } from "buffer";
4617
+ import { Buffer as Buffer16 } from "buffer";
4384
4618
  function collectionProtocolCommand(command, args) {
4385
4619
  switch (command) {
4386
4620
  case "CAS":
@@ -4451,8 +4685,8 @@ function stringSetPayload(args) {
4451
4685
  if (value == null || token === "EX" && value > Math.floor(Number.MAX_SAFE_INTEGER / 1e3)) {
4452
4686
  return void 0;
4453
4687
  }
4454
- const field2 = token === "EX" || token === "PX" ? "ttl" : token.toLowerCase();
4455
- setOwnValue2(payload, field2, token === "EX" ? value * 1e3 : value);
4688
+ const field3 = token === "EX" || token === "PX" ? "ttl" : token.toLowerCase();
4689
+ setOwnValue2(payload, field3, token === "EX" ? value * 1e3 : value);
4456
4690
  expirySeen = true;
4457
4691
  index += 2;
4458
4692
  } else if (token === "NX") {
@@ -4551,25 +4785,25 @@ function hashSetCommand(args) {
4551
4785
  if (!isBinaryCommandArgument(args[0]) || args.length < 3 || args.length % 2 !== 1) return void 0;
4552
4786
  const fields = /* @__PURE__ */ Object.create(null);
4553
4787
  for (let index = 1; index < args.length; index += 2) {
4554
- const field2 = args[index];
4788
+ const field3 = args[index];
4555
4789
  const value = args[index + 1];
4556
- if (typeof field2 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4557
- setOwnValue2(fields, field2, value);
4790
+ if (typeof field3 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4791
+ setOwnValue2(fields, field3, value);
4558
4792
  }
4559
4793
  return { opcode: COMMAND_OPCODES.HSET, payload: { fields, key: args[0] } };
4560
4794
  }
4561
4795
  function keyOnlyCommand(opcode, args) {
4562
4796
  return args.length === 1 && isBinaryCommandArgument(args[0]) ? { opcode, payload: { key: args[0] } } : void 0;
4563
4797
  }
4564
- function binaryFieldsCommand(opcode, args, field2, length) {
4798
+ function binaryFieldsCommand(opcode, args, field3, length) {
4565
4799
  if (args.length !== length || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1])) return void 0;
4566
- return { opcode, payload: { [field2]: args[1], key: args[0] } };
4800
+ return { opcode, payload: { [field3]: args[1], key: args[0] } };
4567
4801
  }
4568
- function binaryListCommand(opcode, args, field2) {
4802
+ function binaryListCommand(opcode, args, field3) {
4569
4803
  if (!isBinaryCommandArgument(args[0]) || args.length < 2) return void 0;
4570
4804
  const values = args.slice(1);
4571
4805
  if (!values.every(isBinaryCommandArgument)) return void 0;
4572
- return { opcode, payload: { [field2]: values, key: args[0] } };
4806
+ return { opcode, payload: { [field3]: values, key: args[0] } };
4573
4807
  }
4574
4808
  function listPopCommand(opcode, args) {
4575
4809
  if (!isBinaryCommandArgument(args[0]) || args.length !== 1 && args.length !== 2) return void 0;
@@ -4627,17 +4861,35 @@ function parsedNumber(value) {
4627
4861
  }
4628
4862
  }
4629
4863
  function isBinaryCommandArgument(value) {
4630
- return typeof value === "string" || Buffer14.isBuffer(value);
4864
+ return typeof value === "string" || Buffer16.isBuffer(value);
4631
4865
  }
4632
4866
  function isDirectKvValueArgument(value) {
4633
4867
  return isBinaryCommandArgument(value) || typeof value === "object" && value != null;
4634
4868
  }
4635
4869
  function binaryToken(value) {
4636
- return typeof value === "string" ? value.toUpperCase() : Buffer14.isBuffer(value) ? value.toString("utf8").toUpperCase() : void 0;
4870
+ return typeof value === "string" ? value.toUpperCase() : Buffer16.isBuffer(value) ? value.toString("utf8").toUpperCase() : void 0;
4871
+ }
4872
+
4873
+ // src/protocol-value.ts
4874
+ import { Buffer as Buffer17 } from "buffer";
4875
+
4876
+ // src/protocol-map-key.ts
4877
+ import { isUtf8 } from "buffer";
4878
+ function setProtocolMapEntry(target, encodedKey, value) {
4879
+ if (typeof encodedKey === "string" && !encodedKey.isWellFormed()) {
4880
+ throw new FerricStoreError("native protocol map key must be valid UTF-8");
4881
+ }
4882
+ if (typeof encodedKey !== "string" && !isUtf8(encodedKey)) {
4883
+ throw new FerricStoreError("native protocol map key must be valid UTF-8");
4884
+ }
4885
+ const key = typeof encodedKey === "string" ? encodedKey : encodedKey.toString("utf8");
4886
+ if (Object.hasOwn(target, key)) {
4887
+ throw new FerricStoreError(`native protocol response contains duplicate map key ${JSON.stringify(key)}`);
4888
+ }
4889
+ setOwnValue2(target, key, value);
4637
4890
  }
4638
4891
 
4639
4892
  // src/protocol-value.ts
4640
- import { Buffer as Buffer15 } from "buffer";
4641
4893
  function planValueWithLimit(value, maxBytes) {
4642
4894
  const budget = {
4643
4895
  maxBytes,
@@ -4692,7 +4944,7 @@ function planContainerValue(value, budget, ancestors, depth) {
4692
4944
  let byteLength = 5;
4693
4945
  let index = 0;
4694
4946
  for (const [key, item] of entries) {
4695
- const keyByteLength = Buffer15.byteLength(key);
4947
+ const keyByteLength = Buffer17.byteLength(key);
4696
4948
  consumeEncodeBytes(budget, 4 + keyByteLength);
4697
4949
  const valuePlan = planValueAt(item, budget, ancestors, depth + 1);
4698
4950
  entryPlans[index] = { key, keyByteLength, value: valuePlan };
@@ -4731,17 +4983,21 @@ function planScalarValue(value, budget) {
4731
4983
  return { byteLength: 9, tag: 3, value: BigInt(value) };
4732
4984
  }
4733
4985
  if (typeof value === "bigint") {
4734
- if (value < MIN_I64 || value > MAX_I64) {
4735
- throw new FerricStoreError("integer exceeds the signed 64-bit native range");
4986
+ if (value >= MIN_I642 && value <= MAX_I642) {
4987
+ consumeEncodeBytes(budget, 9);
4988
+ return { byteLength: 9, tag: 3, value };
4736
4989
  }
4737
- consumeEncodeBytes(budget, 9);
4738
- return { byteLength: 9, tag: 3, value };
4990
+ if (value > MAX_I642 && value <= MAX_U64) {
4991
+ consumeEncodeBytes(budget, 9);
4992
+ return { byteLength: 9, tag: 8, value };
4993
+ }
4994
+ throw new FerricStoreError("integer exceeds the signed or unsigned 64-bit native range");
4739
4995
  }
4740
4996
  if (typeof value === "number") {
4741
4997
  consumeEncodeBytes(budget, 9);
4742
4998
  return { byteLength: 9, tag: 7, value };
4743
4999
  }
4744
- if (typeof value === "string" || Buffer15.isBuffer(value) || value instanceof Uint8Array) {
5000
+ if (typeof value === "string" || Buffer17.isBuffer(value) || value instanceof Uint8Array) {
4745
5001
  const valueByteLength = binaryValueByteLength(value);
4746
5002
  const byteLength = 5 + valueByteLength;
4747
5003
  consumeEncodeBytes(budget, byteLength);
@@ -4765,7 +5021,7 @@ function writeValuePlan(output, start, plan) {
4765
5021
  offset += 4;
4766
5022
  if (typeof plan.value === "string") {
4767
5023
  output.write(plan.value, offset, plan.valueByteLength, "utf8");
4768
- } else if (Buffer15.isBuffer(plan.value)) {
5024
+ } else if (Buffer17.isBuffer(plan.value)) {
4769
5025
  plan.value.copy(output, offset);
4770
5026
  } else {
4771
5027
  output.set(plan.value, offset);
@@ -4790,6 +5046,9 @@ function writeValuePlan(output, start, plan) {
4790
5046
  case 7:
4791
5047
  output.writeDoubleBE(plan.value, offset);
4792
5048
  return offset + 8;
5049
+ case 8:
5050
+ output.writeBigUInt64BE(plan.value, offset);
5051
+ return offset + 8;
4793
5052
  }
4794
5053
  }
4795
5054
  function consumeEncodeBytes(budget, bytes2) {
@@ -4847,7 +5106,7 @@ function decodeValueAt(data, offset, limits, budget, depth) {
4847
5106
  const key = readBinary(data, offset);
4848
5107
  offset = key.offset;
4849
5108
  const item = decodeValueAt(data, offset, limits, budget, depth + 1);
4850
- setOwnValue2(value, key.value.toString("utf8"), item.value);
5109
+ setProtocolMapEntry(value, key.value, item.value);
4851
5110
  offset = item.offset;
4852
5111
  }
4853
5112
  return { value, offset };
@@ -4856,6 +5115,14 @@ function decodeValueAt(data, offset, limits, budget, depth) {
4856
5115
  requireAvailable(data, offset, 8);
4857
5116
  return { value: data.readDoubleBE(offset), offset: offset + 8 };
4858
5117
  }
5118
+ if (tag === 8) {
5119
+ requireAvailable(data, offset, 8);
5120
+ const integer2 = data.readBigUInt64BE(offset);
5121
+ return {
5122
+ value: integer2 <= MAX_SAFE_INTEGER_BIGINT ? Number(integer2) : integer2,
5123
+ offset: offset + 8
5124
+ };
5125
+ }
4859
5126
  throw new FerricStoreError(`unknown protocol value tag ${tag}`);
4860
5127
  }
4861
5128
  function decodeValueWithBudget(data, offset, budget) {
@@ -4899,20 +5166,20 @@ function requireAvailable(data, offset, size) {
4899
5166
  }
4900
5167
 
4901
5168
  // src/key-slot-validation.ts
4902
- import { Buffer as Buffer17 } from "buffer";
5169
+ import { Buffer as Buffer19 } from "buffer";
4903
5170
 
4904
5171
  // src/topology-utilities.ts
4905
- import { Buffer as Buffer16 } from "buffer";
5172
+ import { Buffer as Buffer18 } from "buffer";
4906
5173
  function isPlainObject3(value) {
4907
- return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer16.isBuffer(value);
5174
+ return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer18.isBuffer(value);
4908
5175
  }
4909
5176
  function getField(source, ...keys) {
4910
5177
  if (source instanceof Map) {
4911
5178
  for (const key of keys) {
4912
5179
  if (source.has(key)) return source.get(key);
4913
- const bufferKey = Buffer16.from(key);
5180
+ const bufferKey = Buffer18.from(key);
4914
5181
  for (const [itemKey, value] of source.entries()) {
4915
- if (Buffer16.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
5182
+ if (Buffer18.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
4916
5183
  }
4917
5184
  }
4918
5185
  return void 0;
@@ -4926,14 +5193,14 @@ function getField(source, ...keys) {
4926
5193
  }
4927
5194
  function textOrUndefined(value) {
4928
5195
  if (typeof value === "string") return value;
4929
- if (Buffer16.isBuffer(value)) return value.toString("utf8");
5196
+ if (Buffer18.isBuffer(value)) return value.toString("utf8");
4930
5197
  return void 0;
4931
5198
  }
4932
5199
  function numberOrUndefined(value) {
4933
5200
  return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
4934
5201
  }
4935
- function nativeEventName(event) {
4936
- return textOrUndefined(getField(event.value, "event"))?.toUpperCase();
5202
+ function nativeEventName(event2) {
5203
+ return textOrUndefined(getField(event2.value, "event"))?.toUpperCase();
4937
5204
  }
4938
5205
  function endpointFromRange(item) {
4939
5206
  const endpointValue = getField(item, "endpoint");
@@ -5101,7 +5368,7 @@ function stringHashRange(key) {
5101
5368
  var validatedCommands = /* @__PURE__ */ new WeakSet();
5102
5369
  function assertAtomicKeyValueCommandSharesSlot(args) {
5103
5370
  const value = args[0];
5104
- const command = (typeof value === "string" ? value : Buffer17.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5371
+ const command = (typeof value === "string" ? value : Buffer19.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5105
5372
  if (command === "MSET" || command === "MSETNX") {
5106
5373
  assertKeyValueCommandSharesSlot(args, command);
5107
5374
  }
@@ -5111,7 +5378,7 @@ function assertKeyValueCommandSharesSlot(args, command) {
5111
5378
  let expectedSlot;
5112
5379
  for (let index = 1; index < args.length; index += 2) {
5113
5380
  const key = args[index];
5114
- if (typeof key !== "string" && !Buffer17.isBuffer(key)) return;
5381
+ if (typeof key !== "string" && !Buffer19.isBuffer(key)) return;
5115
5382
  const slot = routingSlotForKey(key);
5116
5383
  expectedSlot ??= slot;
5117
5384
  if (slot !== expectedSlot) {
@@ -5122,62 +5389,202 @@ function assertKeyValueCommandSharesSlot(args, command) {
5122
5389
  }
5123
5390
 
5124
5391
  // src/protocol-response.ts
5125
- import { Buffer as Buffer21 } from "buffer";
5392
+ import { Buffer as Buffer26 } from "buffer";
5126
5393
 
5127
5394
  // src/protocol-compact-response.ts
5128
- import { Buffer as Buffer20 } from "buffer";
5395
+ import { Buffer as Buffer25 } from "buffer";
5129
5396
 
5130
5397
  // src/native-negotiation.ts
5131
- import { Buffer as Buffer18 } from "buffer";
5398
+ import { Buffer as Buffer20 } from "buffer";
5132
5399
  var EMPTY_COMPACT_RESPONSE_OPCODES = /* @__PURE__ */ new Map();
5133
5400
  function nativeNegotiation(value) {
5134
5401
  const capabilities = field(value, "capabilities") ?? value;
5135
5402
  const limits = field(capabilities, "limits");
5136
- const responseCodecs = field(capabilities, "response_codecs");
5403
+ const rawResponseCodecs = field(capabilities, "response_codecs");
5404
+ const responseCodecs = rawResponseCodecs == null ? void 0 : requiredMap(rawResponseCodecs, "HELLO response_codecs");
5405
+ const schemas = requiredMap(field(capabilities, "schemas"), "HELLO schemas");
5137
5406
  const maxResponseBytes = positiveSafeInteger3(field(limits, "max_response_bytes"));
5138
5407
  return {
5139
5408
  compactResponseOpcodes: parseCompactResponseOpcodes(
5140
5409
  field(responseCodecs, "compact_response_opcodes")
5141
5410
  ),
5411
+ flowQuery: parseFlowQueryNegotiation(capabilities, schemas),
5142
5412
  ...maxResponseBytes == null ? {} : { maxResponseBytes }
5143
5413
  };
5144
5414
  }
5415
+ var REQUIRED_FLOW_QUERY_CAPABILITIES = /* @__PURE__ */ new Set([
5416
+ "flow_query_v1",
5417
+ "flow_query_result_projection_v1",
5418
+ "flow_explain_v1",
5419
+ "flow_explain_analyze_v1",
5420
+ "flow_composite_index_v1",
5421
+ "flow_query_index_status_v1"
5422
+ ]);
5423
+ var REQUIRED_FLOW_QUERY_SHAPES = /* @__PURE__ */ new Set([
5424
+ "runs_by_run_id_record",
5425
+ "runs_by_partition_and_run_id_record",
5426
+ "runs_by_partition_predicates_ordered_records",
5427
+ "runs_by_partition_type_state_ordered_records",
5428
+ "runs_by_partition_type_terminals_ordered_records",
5429
+ "runs_by_partition_metadata_ordered_records",
5430
+ "runs_by_partition_type_running_lease_deadline_ordered_records",
5431
+ "runs_by_partition_parent_ordered_records",
5432
+ "runs_by_partition_root_ordered_records",
5433
+ "runs_by_partition_correlation_ordered_records",
5434
+ "runs_by_partition_predicates_count",
5435
+ "events_by_run_id_ordered_records"
5436
+ ]);
5437
+ function parseFlowQueryNegotiation(capabilities, schemas) {
5438
+ const manifest = requiredMap(field(capabilities, "flow_query"), "HELLO flow_query");
5439
+ const requestContract = requiredBoundedText(manifest, "request_contract");
5440
+ const resultContract = requiredBoundedText(manifest, "result_contract");
5441
+ const explainContract = requiredBoundedText(manifest, "explain_contract");
5442
+ const indexStatusContract = requiredBoundedText(manifest, "index_status_contract");
5443
+ requireEqual(requestContract, "ferric.flow.query.request/v1", "flow_query request_contract");
5444
+ requireEqual(resultContract, "ferric.flow.query.result/v1", "flow_query result_contract");
5445
+ requireEqual(explainContract, "ferric.flow.explain/v1", "flow_query explain_contract");
5446
+ requireEqual(
5447
+ indexStatusContract,
5448
+ "ferric.flow.query.indexes/v1",
5449
+ "flow_query index_status_contract"
5450
+ );
5451
+ const queryCapabilities = boundedTextSet(manifest, "capabilities", 64);
5452
+ const languageVersions = boundedTextSet(manifest, "language_versions", 16);
5453
+ const shapes = boundedTextSet(manifest, "shapes", 128);
5454
+ requireMembers(queryCapabilities, REQUIRED_FLOW_QUERY_CAPABILITIES, "flow_query capability");
5455
+ requireMembers(languageVersions, /* @__PURE__ */ new Set(["FQL1"]), "flow_query language");
5456
+ requireMembers(shapes, REQUIRED_FLOW_QUERY_SHAPES, "flow_query shape");
5457
+ const schema = requiredMap(field(schemas, "FLOW.QUERY"), "HELLO FLOW.QUERY schema");
5458
+ const fields = boundedTextSet(schema, "fields", 64);
5459
+ requireMembers(
5460
+ fields,
5461
+ /* @__PURE__ */ new Set(["version", "query", "params", "deadline_ms"]),
5462
+ "FLOW.QUERY schema field"
5463
+ );
5464
+ const required = boundedTextSet(schema, "required", 16);
5465
+ if (required.size !== 2 || !required.has("version") || !required.has("query")) {
5466
+ throw incompatibleServer("FLOW.QUERY schema must require exactly version and query");
5467
+ }
5468
+ return {
5469
+ requestContract: "ferric.flow.query.request/v1",
5470
+ resultContract: "ferric.flow.query.result/v1",
5471
+ explainContract: "ferric.flow.explain/v1",
5472
+ indexStatusContract: "ferric.flow.query.indexes/v1",
5473
+ capabilities: queryCapabilities,
5474
+ languageVersions,
5475
+ shapes
5476
+ };
5477
+ }
5478
+ function requiredMap(value, context) {
5479
+ if (value instanceof Map) return value;
5480
+ if (typeof value === "object" && value != null && !Array.isArray(value) && !Buffer20.isBuffer(value) && !(value instanceof Uint8Array)) {
5481
+ return value;
5482
+ }
5483
+ throw incompatibleServer(`${context} is missing or invalid`);
5484
+ }
5485
+ function requiredBoundedText(mapping, name) {
5486
+ const value = strictText(field(mapping, name));
5487
+ if (value == null || value.length === 0 || Buffer20.byteLength(value) > 256) {
5488
+ throw incompatibleServer(`HELLO flow_query ${name} must be bounded non-empty text`);
5489
+ }
5490
+ return value;
5491
+ }
5492
+ function boundedTextSet(mapping, name, maximum) {
5493
+ const raw = field(mapping, name);
5494
+ if (!Array.isArray(raw) || raw.length < 1 || raw.length > maximum) {
5495
+ throw incompatibleServer(`HELLO ${name} must contain 1..${maximum} entries`);
5496
+ }
5497
+ const result = /* @__PURE__ */ new Set();
5498
+ for (let index = 0; index < raw.length; index += 1) {
5499
+ if (!Object.hasOwn(raw, index)) throw incompatibleServer(`HELLO ${name} must be dense`);
5500
+ const item = strictText(raw[index]);
5501
+ if (item == null || item.length === 0 || Buffer20.byteLength(item) > 256) {
5502
+ throw incompatibleServer(`HELLO ${name} contains invalid text`);
5503
+ }
5504
+ if (result.has(item)) throw incompatibleServer(`HELLO ${name} contains duplicate ${item}`);
5505
+ result.add(item);
5506
+ }
5507
+ return result;
5508
+ }
5509
+ function requireMembers(actual, required, context) {
5510
+ for (const item of required) {
5511
+ if (!actual.has(item)) throw incompatibleServer(`missing ${context} ${JSON.stringify(item)}`);
5512
+ }
5513
+ }
5514
+ function requireEqual(actual, expected, context) {
5515
+ if (actual !== expected) throw incompatibleServer(`${context} must be ${JSON.stringify(expected)}`);
5516
+ }
5517
+ function strictText(value) {
5518
+ if (typeof value === "string") return value;
5519
+ if (Buffer20.isBuffer(value) || value instanceof Uint8Array) {
5520
+ try {
5521
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
5522
+ } catch {
5523
+ return void 0;
5524
+ }
5525
+ }
5526
+ return void 0;
5527
+ }
5528
+ function incompatibleServer(message) {
5529
+ return new FerricStoreError(`incompatible FerricStore server: ${message}`);
5530
+ }
5145
5531
  function compactResponseOpcodeSupports(capabilities, codec, opcode) {
5146
5532
  return capabilities?.get(codec)?.has(opcode) === true;
5147
5533
  }
5148
5534
  function parseCompactResponseOpcodes(value) {
5535
+ if (value == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
5149
5536
  const entries = mapEntries(value);
5150
- if (entries == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
5537
+ if (entries == null) {
5538
+ throw incompatibleServer("HELLO compact_response_opcodes must be a map");
5539
+ }
5540
+ if (entries.length > 32) {
5541
+ throw incompatibleServer("HELLO compact_response_opcodes supports at most 32 codecs");
5542
+ }
5151
5543
  const result = /* @__PURE__ */ new Map();
5544
+ let totalOpcodes = 0;
5152
5545
  for (const [rawName, rawOpcodes] of entries) {
5153
- const name = text2(rawName);
5154
- if (name == null || name.length === 0 || !Array.isArray(rawOpcodes)) continue;
5546
+ const name = strictText(rawName);
5547
+ if (name == null || name.length === 0 || Buffer20.byteLength(name) > 128) {
5548
+ throw incompatibleServer("HELLO compact_response_opcodes contains an invalid codec name");
5549
+ }
5550
+ if (result.has(name)) {
5551
+ throw incompatibleServer(`HELLO compact_response_opcodes contains duplicate codec ${name}`);
5552
+ }
5553
+ if (!Array.isArray(rawOpcodes)) {
5554
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} must be an array`);
5555
+ }
5556
+ totalOpcodes += rawOpcodes.length;
5557
+ if (totalOpcodes > 1024) {
5558
+ throw incompatibleServer("HELLO compact_response_opcodes supports at most 1024 opcodes");
5559
+ }
5155
5560
  const opcodes = /* @__PURE__ */ new Set();
5156
- let valid = true;
5157
5561
  for (let index = 0; index < rawOpcodes.length; index += 1) {
5158
5562
  if (!Object.hasOwn(rawOpcodes, index)) {
5159
- valid = false;
5160
- break;
5563
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} must be dense`);
5161
5564
  }
5162
- const opcode = unsigned16(rawOpcodes[index]);
5565
+ const opcode = strictUnsigned16(rawOpcodes[index]);
5163
5566
  if (opcode == null) {
5164
- valid = false;
5165
- break;
5567
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} has invalid opcode`);
5568
+ }
5569
+ if (opcodes.has(opcode)) {
5570
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} has duplicate opcode`);
5166
5571
  }
5167
5572
  opcodes.add(opcode);
5168
5573
  }
5169
- if (valid) result.set(name, opcodes);
5574
+ result.set(name, opcodes);
5170
5575
  }
5171
5576
  return result;
5172
5577
  }
5173
5578
  function mapEntries(value) {
5174
5579
  if (value instanceof Map) return [...value.entries()];
5175
- if (typeof value !== "object" || value == null || Array.isArray(value)) return void 0;
5580
+ if (typeof value !== "object" || value == null || Array.isArray(value) || Buffer20.isBuffer(value) || value instanceof Uint8Array) return void 0;
5176
5581
  return Object.entries(value);
5177
5582
  }
5178
- function unsigned16(value) {
5179
- const parsed = nonNegativeSafeInteger2(value);
5180
- return parsed != null && parsed <= 65535 ? parsed : void 0;
5583
+ function strictUnsigned16(value) {
5584
+ if (typeof value === "bigint") {
5585
+ return value >= 0n && value <= 0xffffn ? Number(value) : void 0;
5586
+ }
5587
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 65535 ? value : void 0;
5181
5588
  }
5182
5589
  function positiveSafeInteger3(value) {
5183
5590
  const parsed = nonNegativeSafeInteger2(value);
@@ -5196,8 +5603,8 @@ function nonNegativeSafeInteger2(value) {
5196
5603
  }
5197
5604
  function text2(value) {
5198
5605
  if (typeof value === "string") return value;
5199
- if (Buffer18.isBuffer(value) || value instanceof Uint8Array) {
5200
- return Buffer18.from(value).toString("utf8");
5606
+ if (Buffer20.isBuffer(value) || value instanceof Uint8Array) {
5607
+ return Buffer20.from(value).toString("utf8");
5201
5608
  }
5202
5609
  return void 0;
5203
5610
  }
@@ -5268,7 +5675,7 @@ function readCompactBinaryMap(data, offset, budget) {
5268
5675
  for (let index = 0; index < count; index += 1) {
5269
5676
  const key = readBinary(data, offset);
5270
5677
  const value = readBinary(data, key.offset);
5271
- setOwnValue2(values, key.value.toString("utf8"), value.value);
5678
+ setProtocolMapEntry(values, key.value, value.value);
5272
5679
  offset = value.offset;
5273
5680
  }
5274
5681
  return { value: values, offset };
@@ -5284,11 +5691,246 @@ function requireCompactContainer(count, budget) {
5284
5691
  consumeDecodeItems(count, budget);
5285
5692
  }
5286
5693
 
5287
- // src/protocol-compact-response.ts
5288
- function tryDecodeCompactResponse(opcode, body, hints) {
5694
+ // src/protocol-error-message.ts
5695
+ import { Buffer as Buffer22 } from "buffer";
5696
+ var MAX_ERROR_MESSAGE_CHARS = 4096;
5697
+ var MAX_ERROR_TEXT_BYTES = MAX_ERROR_MESSAGE_CHARS * 4;
5698
+ function protocolErrorMessage(status, value) {
5699
+ const direct = errorText(value);
5700
+ if (direct != null) return truncate(direct);
5701
+ return truncate(`ERR native request failed status=${status}: ${errorDescription(value)}`);
5702
+ }
5703
+ function errorText(value) {
5704
+ if (typeof value === "string") return value;
5705
+ if (Buffer22.isBuffer(value) || value instanceof Uint8Array) {
5706
+ return boundedBinaryText(value);
5707
+ }
5708
+ if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5709
+ const message = value.message;
5710
+ if (typeof message === "string") return message;
5711
+ if (Buffer22.isBuffer(message) || message instanceof Uint8Array) {
5712
+ return boundedBinaryText(message);
5713
+ }
5714
+ if (message == null || typeof message !== "object") return String(message);
5715
+ }
5716
+ return void 0;
5717
+ }
5718
+ function boundedBinaryText(value) {
5719
+ const bytes2 = Buffer22.isBuffer(value) ? value : Buffer22.from(value.buffer, value.byteOffset, value.byteLength);
5720
+ return bytes2.subarray(0, MAX_ERROR_TEXT_BYTES).toString("utf8");
5721
+ }
5722
+ function errorDescription(value) {
5723
+ if (Array.isArray(value)) return `[array length=${value.length}]`;
5724
+ if (value instanceof Map) return `[map size=${value.size}]`;
5725
+ if (typeof value === "object" && value != null) return "[object]";
5726
+ return String(value);
5727
+ }
5728
+ function truncate(value) {
5729
+ return value.length <= MAX_ERROR_MESSAGE_CHARS ? value : `${value.slice(0, MAX_ERROR_MESSAGE_CHARS - 1)}\u2026`;
5730
+ }
5731
+
5732
+ // src/protocol-flow-query-result.ts
5733
+ import { Buffer as Buffer24 } from "buffer";
5734
+
5735
+ // src/protocol-binary-detacher.ts
5736
+ import { Buffer as Buffer23 } from "buffer";
5737
+ var MIN_PINNED_BACKING_BYTES = 64;
5738
+ function detachDecodedBinary(value, backingBytes) {
5739
+ if (Buffer23.isBuffer(value)) return detachBuffer(value, backingBytes);
5740
+ if (Array.isArray(value)) {
5741
+ for (let index = 0; index < value.length; index += 1) {
5742
+ value[index] = detachDecodedBinary(value[index], backingBytes);
5743
+ }
5744
+ return value;
5745
+ }
5746
+ if (!isDecodedRecord(value)) return value;
5747
+ for (const key of Object.keys(value)) {
5748
+ setOwnValue2(value, key, detachDecodedBinary(value[key], backingBytes));
5749
+ }
5750
+ return value;
5751
+ }
5752
+ function detachBuffer(value, backingBytes) {
5753
+ if (backingBytes <= Math.max(MIN_PINNED_BACKING_BYTES, value.byteLength * 2)) {
5754
+ return value;
5755
+ }
5756
+ if (value.byteLength === 0) return Buffer23.alloc(0);
5757
+ const detached = Buffer23.allocUnsafeSlow(value.byteLength);
5758
+ value.copy(detached);
5759
+ return detached;
5760
+ }
5761
+ function isDecodedRecord(value) {
5762
+ if (typeof value !== "object" || value == null) return false;
5763
+ const prototype = Object.getPrototypeOf(value);
5764
+ return prototype === Object.prototype || prototype === null;
5765
+ }
5766
+
5767
+ // src/protocol-flow-query-result.ts
5768
+ var CONTRACT = "ferric.flow.query.result/v1";
5769
+ var MAX_RECORDS = 100;
5770
+ var MAX_CURSOR_BYTES = 4096;
5771
+ var RECORD_FIELDS = [
5772
+ "id",
5773
+ "type",
5774
+ "state",
5775
+ "version",
5776
+ "priority",
5777
+ "partition_key",
5778
+ "created_at_ms",
5779
+ "updated_at_ms",
5780
+ "next_run_at_ms",
5781
+ "lease_deadline_ms",
5782
+ "attempts",
5783
+ "run_state",
5784
+ "max_active_ms",
5785
+ "parent_flow_id",
5786
+ "root_flow_id",
5787
+ "correlation_id",
5788
+ "attributes",
5789
+ "state_meta",
5790
+ "event_id",
5791
+ "fields"
5792
+ ];
5793
+ var RECORD_FIELD_MASK = (1 << RECORD_FIELDS.length) - 1;
5794
+ var QUALITY_VALUES = [
5795
+ ["authoritative", "projected_exact", "exact", "not_applicable"],
5796
+ ["current", "projection_watermark", "not_applicable"],
5797
+ ["complete", "unavailable"],
5798
+ ["none", "complete", "authenticated_seek", "live_seek"]
5799
+ ];
5800
+ var QUALITY_FIELDS = ["exactness", "freshness", "coverage", "pagination"];
5801
+ var USAGE_FIELDS = [
5802
+ "range_seeks",
5803
+ "range_pages",
5804
+ "scanned_entries",
5805
+ "scanned_bytes",
5806
+ "hydrated_records",
5807
+ "residual_checks",
5808
+ "duplicate_entries",
5809
+ "result_records",
5810
+ "response_bytes",
5811
+ "memory_high_water_bytes",
5812
+ "wall_time_us"
5813
+ ];
5814
+ function decodeCompactFlowQueryResult(data, budget) {
5815
+ requireAvailable(data, 0, 2 + QUALITY_FIELDS.length + USAGE_FIELDS.length * 8);
5816
+ if (data.readUInt8(0) !== COMPACT_FLOW_QUERY_RESULT) {
5817
+ throw new FerricStoreError("expected compact FLOW.QUERY result");
5818
+ }
5819
+ const kind = data.readUInt8(1);
5820
+ let offset = 2;
5821
+ const quality = {};
5822
+ for (let index = 0; index < QUALITY_FIELDS.length; index += 1) {
5823
+ const field3 = QUALITY_FIELDS[index];
5824
+ const values = QUALITY_VALUES[index];
5825
+ if (field3 == null || values == null) throw new FerricStoreError("invalid compact FLOW.QUERY quality schema");
5826
+ const value = values[data.readUInt8(offset)];
5827
+ if (value == null) throw new FerricStoreError("invalid compact FLOW.QUERY quality code");
5828
+ quality[field3] = Buffer24.from(value);
5829
+ offset += 1;
5830
+ }
5831
+ const usage = {};
5832
+ for (const field3 of USAGE_FIELDS) {
5833
+ const read = readU64(data, offset);
5834
+ usage[field3] = read.value;
5835
+ offset = read.offset;
5836
+ }
5837
+ let result;
5838
+ if (kind === 0) {
5839
+ const page = readPage(data, offset);
5840
+ offset = page.offset;
5841
+ requireAvailable(data, offset, 4);
5842
+ const count = data.readUInt32BE(offset);
5843
+ offset += 4;
5844
+ if (count > MAX_RECORDS) throw new FerricStoreError("compact FLOW.QUERY page exceeds 100 records");
5845
+ consumeDecodeItems(count, budget);
5846
+ const records = new Array(count);
5847
+ for (let index = 0; index < count; index += 1) {
5848
+ const read = readRecord(data, offset, budget);
5849
+ records[index] = read.value;
5850
+ offset = read.offset;
5851
+ }
5852
+ result = { version: Buffer24.from(CONTRACT), records, page: page.value, quality, usage };
5853
+ } else if (kind === 1) {
5854
+ const count = readU64(data, offset);
5855
+ offset = count.offset;
5856
+ result = {
5857
+ version: Buffer24.from(CONTRACT),
5858
+ result: { kind: Buffer24.from("count"), value: count.value },
5859
+ quality,
5860
+ usage
5861
+ };
5862
+ } else {
5863
+ throw new FerricStoreError(`unsupported compact FLOW.QUERY result kind ${kind}`);
5864
+ }
5865
+ if (offset !== data.byteLength) throw new FerricStoreError("trailing compact FLOW.QUERY result bytes");
5866
+ if (BigInt(usage.response_bytes) !== BigInt(data.byteLength)) {
5867
+ throw new FerricStoreError("compact FLOW.QUERY response_bytes does not match its payload");
5868
+ }
5869
+ return result;
5870
+ }
5871
+ function readPage(data, offset) {
5872
+ requireAvailable(data, offset, 5);
5873
+ const hasMoreCode = data.readUInt8(offset);
5874
+ const size = data.readUInt32BE(offset + 1);
5875
+ offset += 5;
5876
+ if (hasMoreCode === 0 && size === NULL_U32) {
5877
+ return { value: { has_more: false, cursor: null }, offset };
5878
+ }
5879
+ if (hasMoreCode !== 1 || size === 0 || size === NULL_U32 || size > MAX_CURSOR_BYTES) {
5880
+ throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
5881
+ }
5882
+ requireAvailable(data, offset, size);
5883
+ return {
5884
+ value: {
5885
+ has_more: true,
5886
+ cursor: detachDecodedBinary(data.subarray(offset, offset + size), data.byteLength)
5887
+ },
5888
+ offset: offset + size
5889
+ };
5890
+ }
5891
+ function readRecord(data, offset, budget) {
5892
+ requireAvailable(data, offset, 4);
5893
+ const bitmap = data.readUInt32BE(offset);
5894
+ offset += 4;
5895
+ if ((bitmap & ~RECORD_FIELD_MASK) !== 0) {
5896
+ throw new FerricStoreError("compact FLOW.QUERY record contains reserved fields");
5897
+ }
5898
+ consumeDecodeItems(populationCount(bitmap), budget);
5899
+ const record = {};
5900
+ for (let index = 0; index < RECORD_FIELDS.length; index += 1) {
5901
+ if ((bitmap & 1 << index) === 0) continue;
5902
+ const field3 = RECORD_FIELDS[index];
5903
+ if (field3 == null) throw new FerricStoreError("invalid compact FLOW.QUERY record schema");
5904
+ const read = decodeValueWithBudget(data, offset, budget);
5905
+ setOwnValue2(record, field3, detachDecodedBinary(read.value, data.byteLength));
5906
+ offset = read.offset;
5907
+ }
5908
+ return { value: record, offset };
5909
+ }
5910
+ function readU64(data, offset) {
5911
+ requireAvailable(data, offset, 8);
5912
+ const value = data.readBigUInt64BE(offset);
5913
+ return {
5914
+ value: value <= MAX_SAFE_INTEGER_BIGINT ? Number(value) : value,
5915
+ offset: offset + 8
5916
+ };
5917
+ }
5918
+ function populationCount(value) {
5919
+ let remaining = value >>> 0;
5920
+ let count = 0;
5921
+ while (remaining !== 0) {
5922
+ remaining &= remaining - 1;
5923
+ count += 1;
5924
+ }
5925
+ return count;
5926
+ }
5927
+
5928
+ // src/protocol-compact-response.ts
5929
+ function tryDecodeCompactResponse(opcode, body, hints) {
5289
5930
  if (body.byteLength === 0) return { found: false, value: void 0 };
5290
5931
  const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
5291
5932
  const tag = body.readUInt8(0);
5933
+ validateCompactResponseItems(tag, opcode, body, hints);
5292
5934
  const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
5293
5935
  if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
5294
5936
  const values = decodeCompactOkList(body, budget);
@@ -5339,6 +5981,9 @@ function tryDecodeCompactResponse(opcode, body, hints) {
5339
5981
  value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(read.value) : read.value
5340
5982
  };
5341
5983
  }
5984
+ if (tag === COMPACT_FLOW_QUERY_RESULT && supports(hints, "flow_query_result_v1", opcode)) {
5985
+ return { found: true, value: decodeCompactFlowQueryResult(body, budget) };
5986
+ }
5342
5987
  return { found: false, value: void 0 };
5343
5988
  }
5344
5989
  function supports(hints, codec, opcode) {
@@ -5349,7 +5994,7 @@ function decodeCompactOkList(data, budget) {
5349
5994
  const count = data.readUInt32BE(1);
5350
5995
  requireCompactContainer2(count, budget);
5351
5996
  if (data.byteLength !== 5) throw new FerricStoreError("invalid compact OK list response");
5352
- return Array.from({ length: count }, () => Buffer20.from("OK"));
5997
+ return Array.from({ length: count }, () => Buffer25.from("OK"));
5353
5998
  }
5354
5999
  function decodeCompactKvGet(data) {
5355
6000
  requireAvailable(data, 0, 2);
@@ -5395,7 +6040,7 @@ function decodeCompactMgetFixed(data, budget) {
5395
6040
  if (size === NULL_U32 || data.byteLength !== expected) {
5396
6041
  throw new FerricStoreError("invalid compact fixed MGET response");
5397
6042
  }
5398
- if (size === 0) return new Array(count).fill(Buffer20.alloc(0));
6043
+ if (size === 0) return new Array(count).fill(Buffer25.alloc(0));
5399
6044
  const values = new Array(count);
5400
6045
  for (let index = 0, offset = 9; index < count; index += 1, offset += size) {
5401
6046
  values[index] = data.subarray(offset, offset + size);
@@ -5456,7 +6101,7 @@ function decodeCompactPipeline(data, budget, claimModes) {
5456
6101
  const read = readBinary(data, offset);
5457
6102
  const errorStatus = status === 1 ? "busy" : "error";
5458
6103
  values[index] = classifyServerError(
5459
- errorMessage(status === 1 ? 4 : 1, read.value),
6104
+ protocolErrorMessage(status === 1 ? 4 : 1, read.value),
5460
6105
  read.value,
5461
6106
  void 0,
5462
6107
  errorStatus
@@ -5566,13 +6211,13 @@ function readCompactFlowRecord(data, offset, budget = { remainingItems: DEFAULT_
5566
6211
  let key;
5567
6212
  if (keyId === 0) {
5568
6213
  const read2 = readBinary(data, offset);
5569
- key = read2.value.toString("utf8");
6214
+ key = read2.value;
5570
6215
  offset = read2.offset;
5571
6216
  } else {
5572
6217
  key = FLOW_RECORD_FIELD_KEYS[keyId] ?? `field_${keyId}`;
5573
6218
  }
5574
6219
  const read = decodeValueWithBudget(data, offset, budget);
5575
- setOwnValue2(record, key, read.value);
6220
+ setProtocolMapEntry(record, key, read.value);
5576
6221
  offset = read.offset;
5577
6222
  }
5578
6223
  return { value: record, offset };
@@ -5608,15 +6253,29 @@ function requireCompactContainer2(count, budget) {
5608
6253
  }
5609
6254
  consumeDecodeItems(count, budget);
5610
6255
  }
5611
- function errorMessage(status, value) {
5612
- if (typeof value === "string") return value;
5613
- if (Buffer20.isBuffer(value)) return value.toString("utf8");
5614
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5615
- const message = value.message;
5616
- return typeof message === "string" ? message : String(message);
6256
+ function validateCompactResponseItems(tag, opcode, data, hints) {
6257
+ const scalarItems = opcode === OPCODES.set || opcode === OPCODES.mset ? 1 : void 0;
6258
+ const expected = scalarItems ?? hints.compactResponseItems;
6259
+ if (expected == null || !COUNTED_COMPACT_TAGS.has(tag)) return;
6260
+ requireAvailable(data, 0, 5);
6261
+ const actual = data.readUInt32BE(1);
6262
+ if (actual !== expected) {
6263
+ throw new FerricStoreError(
6264
+ `compact response returned ${actual} items; expected ${expected} items`
6265
+ );
5617
6266
  }
5618
- return `ERR native request failed status=${status}: ${String(value)}`;
5619
6267
  }
6268
+ var COUNTED_COMPACT_TAGS = /* @__PURE__ */ new Set([
6269
+ COMPACT_FLOW_CLAIM_JOBS,
6270
+ COMPACT_OK_LIST,
6271
+ COMPACT_KV_MGET,
6272
+ COMPACT_FLOW_RECORD_LIST,
6273
+ COMPACT_BINARY_LIST_LIST,
6274
+ COMPACT_BINARY_MAP_LIST,
6275
+ COMPACT_INTEGER_LIST,
6276
+ COMPACT_KV_MGET_FIXED,
6277
+ COMPACT_PIPELINE_RESPONSE
6278
+ ]);
5620
6279
 
5621
6280
  // src/protocol-response.ts
5622
6281
  function decodeResponse(frame, expectedOpcode, hints = {}) {
@@ -5634,9 +6293,16 @@ function decodeResponse(frame, expectedOpcode, hints = {}) {
5634
6293
  }
5635
6294
  const status = frame.body.readUInt16BE(0);
5636
6295
  const body = frame.body.subarray(2);
5637
- const value = decodeResponseValue(frame.opcode, body, hints);
6296
+ const customPayload = (frame.flags & FLAG_CUSTOM_PAYLOAD) !== 0;
6297
+ const value = decodeResponseValue(
6298
+ frame.opcode,
6299
+ body,
6300
+ hints,
6301
+ status === STATUS_OK,
6302
+ customPayload
6303
+ );
5638
6304
  if (status === STATUS_OK) return value;
5639
- const message = errorMessage2(status, value);
6305
+ const message = protocolErrorMessage(status, value);
5640
6306
  throw classifyServerError(message, value, void 0, status);
5641
6307
  }
5642
6308
  function unwrapPipelineResponse(value, options = {}, expectedItems) {
@@ -5675,7 +6341,7 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5675
6341
  continue;
5676
6342
  }
5677
6343
  const error = classifyServerError(
5678
- errorMessage2(status === "busy" ? 4 : 1, payload),
6344
+ protocolErrorMessage(status === "busy" ? 4 : 1, payload),
5679
6345
  payload,
5680
6346
  void 0,
5681
6347
  status
@@ -5690,28 +6356,24 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5690
6356
  return out;
5691
6357
  }
5692
6358
  function pipelineStatus(value) {
5693
- if (typeof value !== "string" && !Buffer21.isBuffer(value) && !(value instanceof Uint8Array)) return null;
6359
+ if (typeof value !== "string" && !Buffer26.isBuffer(value) && !(value instanceof Uint8Array)) return null;
5694
6360
  const status = asText(value).toLowerCase();
5695
6361
  return status === "ok" || status === "busy" || status === "error" ? status : null;
5696
6362
  }
5697
- function decodeResponseValue(opcode, body, hints) {
5698
- const compact = tryDecodeCompactResponse(opcode, body, hints);
5699
- if (compact.found) return compact.value;
6363
+ function decodeResponseValue(opcode, body, hints, allowCompact, customPayload) {
6364
+ if (customPayload && allowCompact) {
6365
+ const compact = tryDecodeCompactResponse(opcode, body, hints);
6366
+ if (compact.found) return compact.value;
6367
+ }
6368
+ if (customPayload) {
6369
+ throw new FerricStoreError("unsupported or malformed custom protocol response", { raw: body });
6370
+ }
5700
6371
  const decoded = decodeValue(body);
5701
6372
  if (decoded.offset !== body.byteLength) {
5702
6373
  throw new FerricStoreError("native protocol response has trailing bytes", { raw: body });
5703
6374
  }
5704
6375
  return decoded.value;
5705
6376
  }
5706
- function errorMessage2(status, value) {
5707
- if (typeof value === "string") return value;
5708
- if (Buffer21.isBuffer(value)) return value.toString("utf8");
5709
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5710
- const message = value.message;
5711
- return typeof message === "string" ? message : String(message);
5712
- }
5713
- return `ERR native request failed status=${status}: ${String(value)}`;
5714
- }
5715
6377
 
5716
6378
  // src/protocol.ts
5717
6379
  function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
@@ -5721,7 +6383,7 @@ function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGE
5721
6383
  const bodyLength = customPayload ? binaryValueByteLength(command.payload) : plan?.byteLength ?? 0;
5722
6384
  if (bodyLength > bodyLimit) throw requestFrameTooLarge(bodyLimit);
5723
6385
  const flags = command.flags ?? 0;
5724
- const frame = Buffer22.allocUnsafe(HEADER_SIZE + bodyLength);
6386
+ const frame = Buffer27.allocUnsafe(HEADER_SIZE + bodyLength);
5725
6387
  frame.write(MAGIC, 0, "ascii");
5726
6388
  frame.writeUInt8(REQUEST_VERSION, 4);
5727
6389
  frame.writeUInt8(flags, 5);
@@ -5822,18 +6484,18 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5822
6484
  }
5823
6485
  if (command === "SET" && commandArgs2.length >= 2) {
5824
6486
  const payload = stringSetPayload(commandArgs2);
5825
- return payload == null ? commandExec(args) : { opcode: OPCODES.set, payload };
6487
+ return payload == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.set, payload };
5826
6488
  }
5827
6489
  if (command === "MGET" && commandArgs2.length > 0) {
5828
6490
  const compact = allowCustomPayload ? compactKeyPipelinePayload(OPCODES.mget, commandArgs2, 2, maxBodyBytes) : void 0;
5829
- if (compact != null) return compact;
5830
- return commandArgs2.every(isBinaryCommandArgument) ? { opcode: OPCODES.mget, payload: { keys: commandArgs2 } } : commandExec(args);
6491
+ if (compact != null) return { ...compact, compactResponseItems: commandArgs2.length };
6492
+ return commandArgs2.every(isBinaryCommandArgument) ? { compactResponseItems: commandArgs2.length, opcode: OPCODES.mget, payload: { keys: commandArgs2 } } : commandExec(args);
5831
6493
  }
5832
6494
  if (command === "MSET" && commandArgs2.length >= 2 && commandArgs2.length % 2 === 0) {
5833
6495
  const compact = allowCustomPayload ? compactMsetPayload(commandArgs2, maxBodyBytes) : void 0;
5834
- if (compact != null) return compact;
6496
+ if (compact != null) return { ...compact, compactResponseItems: 1 };
5835
6497
  const pairs = typedKeyValuePairs(commandArgs2);
5836
- return pairs == null ? commandExec(args) : { opcode: OPCODES.mset, payload: { pairs } };
6498
+ return pairs == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.mset, payload: { pairs } };
5837
6499
  }
5838
6500
  if (command === "DEL" && commandArgs2.length > 0) {
5839
6501
  return commandArgs2.every(isBinaryCommandArgument) ? { opcode: OPCODES.del, payload: { keys: commandArgs2 } } : commandExec(args);
@@ -5843,8 +6505,14 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5843
6505
  if (command === "FLOW.HISTORY") {
5844
6506
  return flowHistoryPayload(commandArgs2) ?? commandExec(args);
5845
6507
  }
5846
- if (command === "FLOW.LIST") {
5847
- return (allowCustomPayload ? compactFlowListPayload(commandArgs2, maxBodyBytes) : void 0) ?? commandExec(args);
6508
+ if (command === "FLOW.QUERY") {
6509
+ return { opcode: OPCODES.flowQuery, payload: flowQueryPayload(commandArgs2) };
6510
+ }
6511
+ if (command === "FLOW.POLICY.SET") {
6512
+ return flowPolicySetPayload(commandArgs2) ?? commandExec(args);
6513
+ }
6514
+ if (command === "FLOW.POLICY.GET") {
6515
+ return flowPolicyGetPayload(commandArgs2) ?? commandExec(args);
5848
6516
  }
5849
6517
  const flowAdmin = FLOW_ADMIN_COMMANDS[command];
5850
6518
  if (flowAdmin != null) {
@@ -5997,24 +6665,17 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5997
6665
  if (command === "FLOW.RUN_STEPS_MANY") {
5998
6666
  return flowAdminPayload(OPCODES.flowRunStepsMany, commandArgs2) ?? commandExec(args);
5999
6667
  }
6000
- if (command === "FLOW.SEARCH") {
6001
- if (hasFlowCommandOnlyOption(command, commandArgs2)) {
6002
- const fallback = commandExec(args);
6003
- try {
6004
- const parsed = flowSearchPayload(commandArgs2);
6005
- return parsed == null ? fallback : withFlowPartitionRouting(fallback, parsed.payload);
6006
- } catch {
6007
- return fallback;
6008
- }
6009
- }
6010
- return flowSearchPayload(commandArgs2) ?? commandExec(args);
6011
- }
6012
6668
  return commandExec(args);
6013
6669
  }
6014
6670
  function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6015
6671
  const compact = compactPipelinePayload(commands, maxBodyBytes);
6016
6672
  if (compact != null) {
6017
- return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.pipeline, payload: compact };
6673
+ return {
6674
+ compactResponseItems: commands.length,
6675
+ flags: FLAG_CUSTOM_PAYLOAD,
6676
+ opcode: OPCODES.pipeline,
6677
+ payload: compact
6678
+ };
6018
6679
  }
6019
6680
  const protocols = new Array(commands.length);
6020
6681
  for (let index = 0; index < commands.length; index += 1) {
@@ -6053,6 +6714,7 @@ function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6053
6714
  const pipelineClaimModes = pipelineProtocols.map((protocol) => protocol.compactClaimMode);
6054
6715
  const hasPipelineClaimMode = pipelineClaimModes.some((mode) => mode != null);
6055
6716
  return {
6717
+ compactResponseItems: commands.length,
6056
6718
  opcode: OPCODES.pipeline,
6057
6719
  payload: {
6058
6720
  atomicity: "none",
@@ -6101,7 +6763,7 @@ import "net";
6101
6763
  import "tls";
6102
6764
 
6103
6765
  // src/client-native-options.ts
6104
- import { Buffer as Buffer23 } from "buffer";
6766
+ import { Buffer as Buffer28 } from "buffer";
6105
6767
 
6106
6768
  // src/string-array-snapshot.ts
6107
6769
  function snapshotOwnStringArray(values, name) {
@@ -6184,7 +6846,7 @@ function snapshotTlsOptions(options) {
6184
6846
  return Object.freeze(snapshot);
6185
6847
  }
6186
6848
  function snapshotTlsValue(value, name) {
6187
- if (Buffer23.isBuffer(value)) return Buffer23.from(value);
6849
+ if (Buffer28.isBuffer(value)) return Buffer28.from(value);
6188
6850
  if (value instanceof Uint8Array) return value.slice();
6189
6851
  if (Array.isArray(value)) {
6190
6852
  const snapshot = new Array(value.length);
@@ -7039,7 +7701,7 @@ var NativeResponseHandler = class {
7039
7701
  compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
7040
7702
  });
7041
7703
  if (frame.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
7042
- const event = {
7704
+ const event2 = {
7043
7705
  flags: frame.flags,
7044
7706
  laneId: frame.laneId,
7045
7707
  opcode: frame.opcode,
@@ -7047,7 +7709,7 @@ var NativeResponseHandler = class {
7047
7709
  };
7048
7710
  if (frame.opcode === OPCODES.goaway) this.options.beginDraining();
7049
7711
  try {
7050
- const callback = this.options.onEvent?.(event);
7712
+ const callback = this.options.onEvent?.(event2);
7051
7713
  if (callback != null) void Promise.resolve(callback).catch(() => void 0);
7052
7714
  } catch {
7053
7715
  }
@@ -7211,12 +7873,14 @@ var NativeConnectionCapabilities = class {
7211
7873
  }
7212
7874
  configuredRequestFrameBytes;
7213
7875
  compactResponseOpcodes = EMPTY_COMPACT_RESPONSE_OPCODES;
7876
+ flowQuery;
7214
7877
  requestFrameBytes;
7215
7878
  negotiatedRequestFrameBytes;
7216
7879
  apply(value) {
7217
7880
  const limits = startupLimits(value);
7218
7881
  const negotiation = nativeNegotiation(value);
7219
7882
  this.compactResponseOpcodes = negotiation.compactResponseOpcodes;
7883
+ this.flowQuery = negotiation.flowQuery;
7220
7884
  if (limits.frameBytes != null) {
7221
7885
  this.negotiatedRequestFrameBytes = Math.min(
7222
7886
  this.configuredRequestFrameBytes,
@@ -7236,6 +7900,19 @@ var NativeConnectionCapabilities = class {
7236
7900
  }
7237
7901
  };
7238
7902
 
7903
+ // src/native-startup-payload.ts
7904
+ function nativeStartupPayload(clientName, events) {
7905
+ const name = clientName ?? "ferricstore-typescript";
7906
+ return {
7907
+ client_name: name,
7908
+ compact_flow_responses: true,
7909
+ compact_response_codecs: ["flow_query_result_v1"],
7910
+ compression: "none",
7911
+ driver_name: name,
7912
+ ...events == null || events.length === 0 ? {} : { events: [...events] }
7913
+ };
7914
+ }
7915
+
7239
7916
  // src/native-adapter.ts
7240
7917
  var NativeAdapter = class _NativeAdapter {
7241
7918
  socket;
@@ -7394,13 +8071,7 @@ var NativeAdapter = class _NativeAdapter {
7394
8071
  const response = await this.request({
7395
8072
  laneId: 0,
7396
8073
  opcode: OPCODES.startup,
7397
- payload: {
7398
- client_name: clientName ?? "ferricstore-typescript",
7399
- compact_flow_responses: true,
7400
- compression: "none",
7401
- driver_name: clientName ?? "ferricstore-typescript",
7402
- ...events == null || events.length === 0 ? {} : { events: [...events] }
7403
- }
8074
+ payload: nativeStartupPayload(clientName, events)
7404
8075
  });
7405
8076
  this.applyStartupLimits(response);
7406
8077
  const authRequired = field(response, "auth_required");
@@ -7460,6 +8131,7 @@ var NativeAdapter = class _NativeAdapter {
7460
8131
  if (!hasFlowControlCredit) this.pendingControlRequests += 1;
7461
8132
  this.pending.set(requestId, {
7462
8133
  ...command.compactClaimMode == null ? {} : { compactClaimMode: command.compactClaimMode },
8134
+ ...command.compactResponseItems == null ? {} : { compactResponseItems: command.compactResponseItems },
7463
8135
  hasFlowControlCredit,
7464
8136
  indefinite: timeoutMs == null,
7465
8137
  laneId,
@@ -7592,6 +8264,29 @@ function executeCommandArgs(executor, args) {
7592
8264
 
7593
8265
  // src/reconnecting-executor.ts
7594
8266
  import "buffer";
8267
+
8268
+ // src/command-retry-policy.ts
8269
+ import { Buffer as Buffer32 } from "buffer";
8270
+ function isCasMutation(args) {
8271
+ const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
8272
+ const name = commandName2(args[offset]);
8273
+ if (name === "CAS") return true;
8274
+ if (name !== "FLOW.POLICY.SET") return false;
8275
+ for (let index = offset + 2; index < args.length; index += 2) {
8276
+ if (!Object.hasOwn(args, index)) return false;
8277
+ if (commandName2(args[index]) === "EXPECTED_GENERATION") return true;
8278
+ }
8279
+ return false;
8280
+ }
8281
+ function commandName2(value) {
8282
+ if (typeof value === "string") return value.toUpperCase();
8283
+ if (Buffer32.isBuffer(value) || value instanceof Uint8Array) {
8284
+ return Buffer32.from(value).toString("utf8").toUpperCase();
8285
+ }
8286
+ return void 0;
8287
+ }
8288
+
8289
+ // src/reconnecting-executor.ts
7595
8290
  var ReconnectingExecutor = class {
7596
8291
  constructor(createExecutor, options = {}) {
7597
8292
  this.createExecutor = createExecutor;
@@ -7622,7 +8317,12 @@ var ReconnectingExecutor = class {
7622
8317
  async executeCommandArgs(args) {
7623
8318
  const snapshot = snapshotCommandArguments(args);
7624
8319
  assertCommandHasStableConnectionState(snapshot);
7625
- return await this.withReconnect((executor) => executeCommandArgs(executor, snapshot));
8320
+ const casMutation = isCasMutation(snapshot);
8321
+ return await this.withReconnect(
8322
+ (executor) => executeCommandArgs(executor, snapshot),
8323
+ casMutation ? isClosedConnectionError : isReconnectableClosedConnectionError,
8324
+ !casMutation
8325
+ );
7626
8326
  }
7627
8327
  async ready() {
7628
8328
  await this.executorPromise;
@@ -7707,7 +8407,7 @@ var ReconnectingExecutor = class {
7707
8407
  })();
7708
8408
  await this.closePromise;
7709
8409
  }
7710
- async withReconnect(operation, reconnectable = isReconnectableClosedConnectionError) {
8410
+ async withReconnect(operation, reconnectable = isReconnectableClosedConnectionError, replayAllowed = true) {
7711
8411
  let executor = await this.executorPromise;
7712
8412
  let retries = 0;
7713
8413
  for (; ; ) {
@@ -7716,6 +8416,10 @@ var ReconnectingExecutor = class {
7716
8416
  return await operation(executor);
7717
8417
  } catch (error) {
7718
8418
  if (this.closed || retries >= this.maxRetries || !reconnectable(error)) throw error;
8419
+ if (!replayAllowed) {
8420
+ await this.reconnect(executor).catch(() => void 0);
8421
+ throw error;
8422
+ }
7719
8423
  for (; ; ) {
7720
8424
  retries += 1;
7721
8425
  try {
@@ -7768,6 +8472,9 @@ var ReconnectingExecutor = class {
7768
8472
  function isReconnectableClosedConnectionError(error) {
7769
8473
  return error instanceof ConnectionClosedError && error.requestDisposition === "unsent";
7770
8474
  }
8475
+ function isClosedConnectionError(error) {
8476
+ return error instanceof ConnectionClosedError;
8477
+ }
7771
8478
  function isReadOnlyReconnectableClosedConnectionError(error) {
7772
8479
  const pending = [error];
7773
8480
  const seen = /* @__PURE__ */ new Set();
@@ -7789,16 +8496,88 @@ function normalizeNonNegativeInteger2(value, fallback) {
7789
8496
  import "buffer";
7790
8497
 
7791
8498
  // src/topology-routing.ts
7792
- import { Buffer as Buffer28 } from "buffer";
8499
+ import { Buffer as Buffer35 } from "buffer";
8500
+
8501
+ // src/flow-partition-route-cache.ts
8502
+ import { Buffer as Buffer34 } from "buffer";
7793
8503
  import { createHash } from "crypto";
7794
- var FLOW_PARTITION_ROUTE_CACHE_MAX = 1024;
7795
- var flowPartitionRouteCache = /* @__PURE__ */ new Map();
8504
+ var AUTO_PREFIX = Buffer34.from("__flow_auto__:", "ascii");
8505
+ var MAX_CACHEABLE_PARTITION_BYTES = 4 * 1024;
8506
+ var MAX_CACHE_BYTES = 1 * 1024 * 1024;
8507
+ var MAX_CACHE_ENTRIES = 1024;
8508
+ var CACHE_ENTRY_OVERHEAD_BYTES = 96;
8509
+ var routeCache = /* @__PURE__ */ new Map();
8510
+ var cacheBytes = 0;
8511
+ var cacheHits = 0;
8512
+ var cacheMisses = 0;
8513
+ function flowLogicalPartitionRoutingKey(value) {
8514
+ if (typeof value !== "string" && !Buffer34.isBuffer(value)) return void 0;
8515
+ const autoBucket = flowAutoBucket(value);
8516
+ if (autoBucket != null) return `{fa:${autoBucket}}`;
8517
+ const bytes2 = Buffer34.isBuffer(value) ? value : Buffer34.from(value);
8518
+ if (bytes2.byteLength > MAX_CACHEABLE_PARTITION_BYTES) return hashRoute(bytes2);
8519
+ const cacheKey = bytes2.toString("base64");
8520
+ const cached = routeCache.get(cacheKey);
8521
+ if (cached != null) {
8522
+ cacheHits += 1;
8523
+ routeCache.delete(cacheKey);
8524
+ routeCache.set(cacheKey, cached);
8525
+ return cached.routeKey;
8526
+ }
8527
+ cacheMisses += 1;
8528
+ const routeKey = hashRoute(bytes2);
8529
+ const entryBytes = estimatedEntryBytes(cacheKey, routeKey);
8530
+ while (routeCache.size >= MAX_CACHE_ENTRIES || routeCache.size > 0 && cacheBytes + entryBytes > MAX_CACHE_BYTES) {
8531
+ evictOldest();
8532
+ }
8533
+ if (entryBytes <= MAX_CACHE_BYTES) {
8534
+ routeCache.set(cacheKey, { bytes: entryBytes, routeKey });
8535
+ cacheBytes += entryBytes;
8536
+ }
8537
+ return routeKey;
8538
+ }
8539
+ function flowAutoBucket(value) {
8540
+ if (typeof value === "string") {
8541
+ const match = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(value);
8542
+ if (match?.[1] == null) return void 0;
8543
+ const bucket2 = Number(match[1]);
8544
+ return bucket2 < 256 ? bucket2 : void 0;
8545
+ }
8546
+ const digitCount = value.byteLength - AUTO_PREFIX.byteLength;
8547
+ if (digitCount < 1 || digitCount > 3) return void 0;
8548
+ for (let index = 0; index < AUTO_PREFIX.byteLength; index += 1) {
8549
+ if (value[index] !== AUTO_PREFIX[index]) return void 0;
8550
+ }
8551
+ if (digitCount > 1 && value[AUTO_PREFIX.byteLength] === 48) return void 0;
8552
+ let bucket = 0;
8553
+ for (let index = AUTO_PREFIX.byteLength; index < value.byteLength; index += 1) {
8554
+ const digit = value[index];
8555
+ if (digit == null || digit < 48 || digit > 57) return void 0;
8556
+ bucket = bucket * 10 + digit - 48;
8557
+ }
8558
+ return bucket < 256 ? bucket : void 0;
8559
+ }
8560
+ function hashRoute(value) {
8561
+ const digest = createHash("sha256").update(value).digest("base64url");
8562
+ return `{f:${digest}}`;
8563
+ }
8564
+ function estimatedEntryBytes(cacheKey, routeKey) {
8565
+ return CACHE_ENTRY_OVERHEAD_BYTES + 2 * (cacheKey.length + routeKey.length);
8566
+ }
8567
+ function evictOldest() {
8568
+ const oldest = routeCache.entries().next().value;
8569
+ if (oldest == null) return;
8570
+ routeCache.delete(oldest[0]);
8571
+ cacheBytes -= oldest[1].bytes;
8572
+ }
8573
+
8574
+ // src/topology-routing.ts
7796
8575
  function routingKeyFromProtocolPayload(name, command) {
7797
8576
  if (command.opcode < 256 || name === "CLUSTER.KEYSLOT" || name === "SHARDS" || name === "ROUTE") {
7798
8577
  return void 0;
7799
8578
  }
7800
8579
  if (isPlainObject3(command.payload)) {
7801
- for (const field2 of [
8580
+ for (const field3 of [
7802
8581
  "key",
7803
8582
  "partition_key",
7804
8583
  "id",
@@ -7808,8 +8587,8 @@ function routingKeyFromProtocolPayload(name, command) {
7808
8587
  "correlation_id",
7809
8588
  "scope"
7810
8589
  ]) {
7811
- const value = getField(command.payload, field2);
7812
- if (typeof value === "string" || Buffer28.isBuffer(value)) {
8590
+ const value = getField(command.payload, field3);
8591
+ if (typeof value === "string" || Buffer35.isBuffer(value)) {
7813
8592
  return value;
7814
8593
  }
7815
8594
  }
@@ -7843,6 +8622,7 @@ function flowRoutingData(name, args) {
7843
8622
  if (flowScheduleCommands.has(name)) {
7844
8623
  return void 0;
7845
8624
  }
8625
+ if (name === "FLOW.QUERY") return void 0;
7846
8626
  if (flowApprovalIdCommands.has(name)) {
7847
8627
  const id = flowArgs[0];
7848
8628
  return flowRoutingResult(flowLogicalPartitionRoutingKey(id));
@@ -7856,7 +8636,7 @@ function flowRoutingData(name, args) {
7856
8636
  if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
7857
8637
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
7858
8638
  }
7859
- if (Buffer28.isBuffer(partition)) {
8639
+ if (Buffer35.isBuffer(partition)) {
7860
8640
  const text3 = partition.toString("utf8").toUpperCase();
7861
8641
  if (text3 !== "AUTO" && text3 !== "MIXED") {
7862
8642
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
@@ -7947,46 +8727,17 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
7947
8727
  return { handled: false };
7948
8728
  }
7949
8729
  function isRoutingKey(value) {
7950
- return typeof value === "string" || Buffer28.isBuffer(value);
7951
- }
7952
- function flowLogicalPartitionRoutingKey(value) {
7953
- if (typeof value !== "string" && !Buffer28.isBuffer(value)) {
7954
- return void 0;
7955
- }
7956
- const bytes2 = Buffer28.isBuffer(value) ? value : Buffer28.from(value);
7957
- const text3 = bytes2.toString("utf8");
7958
- const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(text3);
7959
- if (autoMatch != null) {
7960
- const bucket = Number(autoMatch[1]);
7961
- if (bucket < 256) {
7962
- return `{fa:${bucket}}`;
7963
- }
7964
- }
7965
- const cacheKey = `${Buffer28.isBuffer(value) ? "b" : "s"}:${bytes2.toString("base64")}`;
7966
- const cached = flowPartitionRouteCache.get(cacheKey);
7967
- if (cached != null) {
7968
- flowPartitionRouteCache.delete(cacheKey);
7969
- flowPartitionRouteCache.set(cacheKey, cached);
7970
- return cached;
7971
- }
7972
- const digest = createHash("sha256").update(bytes2).digest("base64url");
7973
- const routeKey = `{f:${digest}}`;
7974
- if (flowPartitionRouteCache.size >= FLOW_PARTITION_ROUTE_CACHE_MAX) {
7975
- const oldest = flowPartitionRouteCache.keys().next().value;
7976
- if (oldest != null) flowPartitionRouteCache.delete(oldest);
7977
- }
7978
- flowPartitionRouteCache.set(cacheKey, routeKey);
7979
- return routeKey;
8730
+ return typeof value === "string" || Buffer35.isBuffer(value);
7980
8731
  }
7981
8732
  function flowAutoIdRoutingKey(value) {
7982
- if (typeof value !== "string" && !Buffer28.isBuffer(value)) {
8733
+ if (typeof value !== "string" && !Buffer35.isBuffer(value)) {
7983
8734
  return void 0;
7984
8735
  }
7985
- const bucket = (Buffer28.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
8736
+ const bucket = (Buffer35.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
7986
8737
  return `{fa:${bucket}}`;
7987
8738
  }
7988
8739
  function flowClaimLogicalPartitionRoutingKey(value) {
7989
- if (typeof value !== "string" && !Buffer28.isBuffer(value)) return void 0;
8740
+ if (typeof value !== "string" && !Buffer35.isBuffer(value)) return void 0;
7990
8741
  const selector = commandPart(value);
7991
8742
  if (selector === "AUTO" || selector === "ANY") return void 0;
7992
8743
  if (selector === "GLOBAL") return "{f}";
@@ -8001,7 +8752,7 @@ function singleShardFlowClaimPartitionKey(values) {
8001
8752
  return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
8002
8753
  }
8003
8754
  function singleShardKey(keys) {
8004
- if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer28.isBuffer(key))) {
8755
+ if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer35.isBuffer(key))) {
8005
8756
  return void 0;
8006
8757
  }
8007
8758
  const usable = keys;
@@ -8012,7 +8763,7 @@ function singleShardKey(keys) {
8012
8763
  const firstSlot = routingSlotForKey(first);
8013
8764
  return usable.every((key) => routingSlotForKey(key) === firstSlot) ? first : void 0;
8014
8765
  }
8015
- function commandName2(args) {
8766
+ function commandName3(args) {
8016
8767
  return commandView(args).name;
8017
8768
  }
8018
8769
  var commandPart = commandToken;
@@ -8034,7 +8785,7 @@ function routedKeyGroups(keys, routeKey) {
8034
8785
  const groups = /* @__PURE__ */ new Map();
8035
8786
  for (let index = 0; index < keys.length; index += 1) {
8036
8787
  const key = keys[index];
8037
- if (typeof key !== "string" && !Buffer28.isBuffer(key)) return void 0;
8788
+ if (typeof key !== "string" && !Buffer35.isBuffer(key)) return void 0;
8038
8789
  const route = routeKey(key);
8039
8790
  const groupKey = `${route.endpointKey}\0${route.laneId}`;
8040
8791
  const group = groups.get(groupKey);
@@ -8426,7 +9177,7 @@ var TopologyPipelineExecutor = class {
8426
9177
  commands.forEach((command, index) => {
8427
9178
  const routed = this.context.routeData(command);
8428
9179
  if (routed == null) {
8429
- if (decomposableCommandNames.has(commandName2(command) ?? "")) standalone.push({ command, index });
9180
+ if (decomposableCommandNames.has(commandName3(command) ?? "")) standalone.push({ command, index });
8430
9181
  else {
8431
9182
  controlCommands.push(command);
8432
9183
  controlIndices.push(index);
@@ -8642,7 +9393,7 @@ function topologyRouteIsCurrent(topology, route) {
8642
9393
  // src/topology-route-planner.ts
8643
9394
  function topologyRouteData(args, route) {
8644
9395
  if (args.length === 0) return void 0;
8645
- const name = commandName2(args);
9396
+ const name = commandName3(args);
8646
9397
  if (name?.startsWith("FLOW.") === true) {
8647
9398
  const routed = flowRoutingData(name, args);
8648
9399
  return routed == null ? void 0 : {
@@ -8671,7 +9422,7 @@ var TopologyScatterExecutor = class {
8671
9422
  }
8672
9423
  dependencies;
8673
9424
  async execute(args) {
8674
- const name = commandName2(args);
9425
+ const name = commandName3(args);
8675
9426
  if (name === "MGET") {
8676
9427
  const value = await this.scatterArray(name, args.slice(1));
8677
9428
  return value == null ? { handled: false } : { handled: true, value };
@@ -8753,6 +9504,18 @@ var TopologyScatterExecutor = class {
8753
9504
  }
8754
9505
  };
8755
9506
 
9507
+ // src/topology-reroute-retry.ts
9508
+ async function canRetrySafeReroute(error, attempt, retryAllowed, refresh, assertOpen) {
9509
+ if (attempt !== 0 || !isRetryableRouteError(error)) return false;
9510
+ const refreshed = await refresh().then(
9511
+ () => true,
9512
+ () => false
9513
+ );
9514
+ if (!refreshed || !retryAllowed || !await waitForExplicitlySafeReroute(error)) return false;
9515
+ assertOpen();
9516
+ return true;
9517
+ }
9518
+
8756
9519
  // src/topology.ts
8757
9520
  var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8758
9521
  adapterOptions;
@@ -8794,15 +9557,15 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8794
9557
  this.adapterOptions = {
8795
9558
  ...adapterOptions,
8796
9559
  events: [.../* @__PURE__ */ new Set([...adapterOptions.events ?? [], "TOPOLOGY_CHANGED"])],
8797
- onEvent: (event) => {
9560
+ onEvent: (event2) => {
8798
9561
  try {
8799
- const callback = userOnEvent?.(event);
9562
+ const callback = userOnEvent?.(event2);
8800
9563
  if (callback != null) {
8801
9564
  void Promise.resolve(callback).catch(() => void 0);
8802
9565
  }
8803
9566
  } catch {
8804
9567
  }
8805
- if (!this.closed && nativeEventName(event) === "TOPOLOGY_CHANGED") {
9568
+ if (!this.closed && nativeEventName(event2) === "TOPOLOGY_CHANGED") {
8806
9569
  this.requestTopologyRefresh();
8807
9570
  }
8808
9571
  }
@@ -8938,6 +9701,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8938
9701
  this.assertOpen();
8939
9702
  const snapshot = snapshotCommandArguments(args);
8940
9703
  assertCommandHasStableConnectionState(snapshot);
9704
+ const casMutation = isCasMutation(snapshot);
8941
9705
  let rerouteAttempt = 0;
8942
9706
  for (let planningAttempt = 0; planningAttempt < MAX_TOPOLOGY_PLANNING_ATTEMPTS; planningAttempt += 1) {
8943
9707
  const routed = this.routeData(snapshot);
@@ -8953,7 +9717,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8953
9717
  try {
8954
9718
  return routed.command == null ? await adapter.executeCommandOnLane(snapshot, routed.route.laneId) : await adapter.executeProtocolCommand(routed.command, routed.route.laneId);
8955
9719
  } catch (error) {
8956
- if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt)) {
9720
+ if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt, !casMutation)) {
8957
9721
  rerouteAttempt += 1;
8958
9722
  continue;
8959
9723
  }
@@ -8995,6 +9759,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8995
9759
  assertCommandHasStableConnectionState(command);
8996
9760
  }
8997
9761
  let rerouteAttempt = 0;
9762
+ const containsCasMutation = snapshot.some(isCasMutation);
8998
9763
  for (let planningAttempt = 0; planningAttempt < MAX_TOPOLOGY_PLANNING_ATTEMPTS; planningAttempt += 1) {
8999
9764
  const route = singleRouteForCommands(snapshot, (command) => this.routeData(command));
9000
9765
  if (route == null) return void 0;
@@ -9003,7 +9768,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9003
9768
  try {
9004
9769
  return await adapter.executeFusedPipelineOnLane(snapshot, route.laneId, snapshotOptions);
9005
9770
  } catch (error) {
9006
- if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt)) {
9771
+ if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt, !containsCasMutation)) {
9007
9772
  rerouteAttempt += 1;
9008
9773
  continue;
9009
9774
  }
@@ -9012,15 +9777,14 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9012
9777
  }
9013
9778
  throw new StaleTopologyRouteError();
9014
9779
  }
9015
- async refreshAndCanRetrySafeReroute(error, attempt) {
9016
- if (attempt !== 0 || !isRetryableRouteError(error)) return false;
9017
- const refreshed = await this.refreshTopology().then(
9018
- () => true,
9019
- () => false
9780
+ async refreshAndCanRetrySafeReroute(error, attempt, retryAllowed = true) {
9781
+ return await canRetrySafeReroute(
9782
+ error,
9783
+ attempt,
9784
+ retryAllowed,
9785
+ async () => await this.refreshTopology(),
9786
+ () => this.assertOpen()
9020
9787
  );
9021
- if (!refreshed || !await waitForExplicitlySafeReroute(error)) return false;
9022
- this.assertOpen();
9023
- return true;
9024
9788
  }
9025
9789
  async executePipelineOnRoute(commands, route, options) {
9026
9790
  const adapter = await this.adapterForCurrentRoute(route);
@@ -9110,7 +9874,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9110
9874
  };
9111
9875
 
9112
9876
  // src/response-map-preservation.ts
9113
- import { Buffer as Buffer30 } from "buffer";
9877
+ import { Buffer as Buffer37 } from "buffer";
9114
9878
  function toStringKeyMapPreservingValues(value) {
9115
9879
  if (value == null) return void 0;
9116
9880
  const result = {};
@@ -9120,7 +9884,7 @@ function toStringKeyMapPreservingValues(value) {
9120
9884
  }
9121
9885
  return result;
9122
9886
  }
9123
- if (typeof value === "object" && !Array.isArray(value) && !Buffer30.isBuffer(value) && !(value instanceof Uint8Array)) {
9887
+ if (typeof value === "object" && !Array.isArray(value) && !Buffer37.isBuffer(value) && !(value instanceof Uint8Array)) {
9124
9888
  for (const [key, item] of Object.entries(value)) {
9125
9889
  setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
9126
9890
  }
@@ -9129,7 +9893,7 @@ function toStringKeyMapPreservingValues(value) {
9129
9893
  return void 0;
9130
9894
  }
9131
9895
  function normalizeMapStructurePreservingBytes(value) {
9132
- if (Buffer30.isBuffer(value) || value instanceof Uint8Array) return value;
9896
+ if (Buffer37.isBuffer(value) || value instanceof Uint8Array) return value;
9133
9897
  if (value instanceof Map) {
9134
9898
  const result = {};
9135
9899
  for (const [key, item] of value.entries()) {
@@ -9151,7 +9915,7 @@ function normalizeMapStructurePreservingBytes(value) {
9151
9915
  }
9152
9916
 
9153
9917
  // src/native-kv-responses.ts
9154
- import { Buffer as Buffer31 } from "buffer";
9918
+ import { Buffer as Buffer38 } from "buffer";
9155
9919
  function rateLimitResultFromResp(value) {
9156
9920
  if (!Array.isArray(value) || value.length !== 4) {
9157
9921
  throw new TypeError("RATELIMIT.ADD returned an unexpected response");
@@ -9208,13 +9972,13 @@ function fetchOrComputeResultFromResp(value, codec) {
9208
9972
  }
9209
9973
  function decodePayload(codec, value) {
9210
9974
  if (value == null) return null;
9211
- if (Buffer31.isBuffer(value)) return codec.decode(value);
9212
- if (value instanceof Uint8Array) return codec.decode(Buffer31.from(value));
9213
- if (typeof value === "string") return codec.decode(Buffer31.from(value));
9975
+ if (Buffer38.isBuffer(value)) return codec.decode(value);
9976
+ if (value instanceof Uint8Array) return codec.decode(Buffer38.from(value));
9977
+ if (typeof value === "string") return codec.decode(Buffer38.from(value));
9214
9978
  return normalizeRefMeta(value);
9215
9979
  }
9216
9980
  function requiredResponseString(value, context) {
9217
- if (typeof value !== "string" && !Buffer31.isBuffer(value) && !(value instanceof Uint8Array)) {
9981
+ if (typeof value !== "string" && !Buffer38.isBuffer(value) && !(value instanceof Uint8Array)) {
9218
9982
  throw new TypeError(`${context} returned an unexpected response`);
9219
9983
  }
9220
9984
  const result = text(value);
@@ -9231,7 +9995,7 @@ function requiredNonNegativeInteger(value, context) {
9231
9995
  return result;
9232
9996
  }
9233
9997
  function responseBytes(value, context) {
9234
- if (typeof value !== "string" && !Buffer31.isBuffer(value) && !(value instanceof Uint8Array)) {
9998
+ if (typeof value !== "string" && !Buffer38.isBuffer(value) && !(value instanceof Uint8Array)) {
9235
9999
  throw new TypeError(`${context} returned an unexpected response`);
9236
10000
  }
9237
10001
  return bytes(value);
@@ -9554,17 +10318,6 @@ function finiteNonNegativeInteger(value, fallback) {
9554
10318
  function finiteNonNegativeNumber(value, fallback) {
9555
10319
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, value);
9556
10320
  }
9557
- function appendReadOptions(args, options) {
9558
- append(args, "COUNT", options.count);
9559
- append(args, "PARTITION", options.partitionKey);
9560
- append(args, "FROM_MS", options.fromMs);
9561
- append(args, "TO_MS", options.toMs);
9562
- appendBool(args, "REV", options.rev);
9563
- append(args, "STATE", options.state);
9564
- appendBool(args, "TERMINAL_ONLY", options.terminalOnly);
9565
- appendBool(args, "INCLUDE_COLD", options.includeCold);
9566
- appendBool(args, "CONSISTENT_PROJECTION", options.consistentProjection);
9567
- }
9568
10321
  function appendAttributeQueryOptions(args, options) {
9569
10322
  append(args, "STATE", options.state);
9570
10323
  append(args, "PARTITION", options.partitionKey);
@@ -9618,22 +10371,6 @@ function appendAttributes(args, attributes) {
9618
10371
  args.push("ATTRIBUTE", name, value);
9619
10372
  }
9620
10373
  }
9621
- function appendSearchStateMeta(args, state, stateMeta) {
9622
- const entries = Object.entries(stateMeta ?? {});
9623
- if (entries.length === 0) {
9624
- return;
9625
- }
9626
- if (entries.every(([, value]) => isPlainObject5(value))) {
9627
- for (const [metaState, values] of entries) {
9628
- args.push("STATE_META", metaState, values);
9629
- }
9630
- return;
9631
- }
9632
- if (state == null) {
9633
- throw new Error("search stateMeta filters require state or nested state metadata");
9634
- }
9635
- args.push("STATE_META", state, stateMeta);
9636
- }
9637
10374
  function normalizeAdminResponse(value) {
9638
10375
  return normalizeRefMeta(value);
9639
10376
  }
@@ -9941,7 +10678,7 @@ function groupAutoPartitionItems(items) {
9941
10678
  }
9942
10679
 
9943
10680
  // src/client-values.ts
9944
- import { Buffer as Buffer32 } from "buffer";
10681
+ import { Buffer as Buffer39 } from "buffer";
9945
10682
  async function valueMGetEntries(client, refs, options = {}) {
9946
10683
  const refCount = refs.length;
9947
10684
  if (refCount === 0) {
@@ -9976,12 +10713,12 @@ async function valueMGetEntries(client, refs, options = {}) {
9976
10713
  const item = response[index];
9977
10714
  if (item == null) {
9978
10715
  entries[index] = { found: false };
9979
- } else if (Buffer32.isBuffer(item)) {
10716
+ } else if (Buffer39.isBuffer(item)) {
9980
10717
  entries[index] = { found: true, value: client.codec.decode(item) };
9981
10718
  } else if (item instanceof Uint8Array) {
9982
- entries[index] = { found: true, value: client.codec.decode(Buffer32.from(item)) };
10719
+ entries[index] = { found: true, value: client.codec.decode(Buffer39.from(item)) };
9983
10720
  } else if (typeof item === "string") {
9984
- entries[index] = { found: true, value: client.codec.decode(Buffer32.from(item)) };
10721
+ entries[index] = { found: true, value: client.codec.decode(Buffer39.from(item)) };
9985
10722
  } else {
9986
10723
  entries[index] = { found: true, value: item };
9987
10724
  }
@@ -9993,7 +10730,7 @@ async function valueMGetEntries(client, refs, options = {}) {
9993
10730
  import "buffer";
9994
10731
 
9995
10732
  // src/auto-batch-ordering.ts
9996
- import { Buffer as Buffer33 } from "buffer";
10733
+ import { Buffer as Buffer40 } from "buffer";
9997
10734
  function autoBatchOrderingPlan(batch) {
9998
10735
  const accesses = /* @__PURE__ */ new Map();
9999
10736
  const fallbackDependencies = [];
@@ -10108,13 +10845,13 @@ function flowManyAutoBatchIds(command, name) {
10108
10845
  return fixedFlowItemIds(
10109
10846
  command,
10110
10847
  mixed ? 4 : 3,
10111
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && Buffer33.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
10848
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && Buffer40.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
10112
10849
  );
10113
10850
  }
10114
10851
  return fixedFlowItemIds(
10115
10852
  command,
10116
10853
  mixed ? 4 : 3,
10117
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer33.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
10854
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer40.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
10118
10855
  );
10119
10856
  }
10120
10857
  function createManyAutoBatchIds(command) {
@@ -10127,7 +10864,7 @@ function createManyAutoBatchIds(command) {
10127
10864
  const ids = fixedFlowItemIds(
10128
10865
  command,
10129
10866
  width,
10130
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer33.isBuffer(command[itemIndex + width - 1]),
10867
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer40.isBuffer(command[itemIndex + width - 1]),
10131
10868
  markerIndex
10132
10869
  );
10133
10870
  if (ids != null) return ids;
@@ -10145,7 +10882,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
10145
10882
  let cursor = markerIndex + 2;
10146
10883
  for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
10147
10884
  const id = command[cursor];
10148
- if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer33.isBuffer(command[cursor + 2])) return void 0;
10885
+ if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer40.isBuffer(command[cursor + 2])) return void 0;
10149
10886
  ids.push(id);
10150
10887
  cursor += 3;
10151
10888
  const afterValues = skipExtendedNamedItems(command, cursor, true);
@@ -10164,7 +10901,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
10164
10901
  for (let index = 0; index < count; index += 1) {
10165
10902
  const name = command[firstItem + index * 2];
10166
10903
  const value = command[firstItem + index * 2 + 1];
10167
- if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer33.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
10904
+ if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer40.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
10168
10905
  }
10169
10906
  return firstItem + count * 2;
10170
10907
  }
@@ -10179,7 +10916,7 @@ function runStepsManyAutoBatchIds(command) {
10179
10916
  ids.push(item);
10180
10917
  continue;
10181
10918
  }
10182
- if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer33.isBuffer(item)) return void 0;
10919
+ if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer40.isBuffer(item)) return void 0;
10183
10920
  const id = item.id;
10184
10921
  if (!isAutoBatchResourceValue(id)) return void 0;
10185
10922
  ids.push(id);
@@ -10220,7 +10957,7 @@ function flowValuePutOwner(command, start) {
10220
10957
  }
10221
10958
  var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
10222
10959
  function isAutoBatchResourceValue(value) {
10223
- return typeof value === "string" || Buffer33.isBuffer(value);
10960
+ return typeof value === "string" || Buffer40.isBuffer(value);
10224
10961
  }
10225
10962
  function isFencingToken(value) {
10226
10963
  return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
@@ -10229,7 +10966,7 @@ function nonNegativeItemCount(value) {
10229
10966
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
10230
10967
  }
10231
10968
  function autoBatchResourceKey(namespace, value) {
10232
- return `${namespace}:${Buffer33.from(value).toString("base64")}`;
10969
+ return `${namespace}:${Buffer40.from(value).toString("base64")}`;
10233
10970
  }
10234
10971
  function autoBatchCommandName(command) {
10235
10972
  return commandView(command).name ?? null;
@@ -10605,7 +11342,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10605
11342
  const results = new Array(claimed.length);
10606
11343
  let cursor = 0;
10607
11344
  let failure;
10608
- const run = async () => {
11345
+ const run2 = async () => {
10609
11346
  while (failure == null) {
10610
11347
  const index = cursor;
10611
11348
  cursor += 1;
@@ -10618,7 +11355,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10618
11355
  }
10619
11356
  }
10620
11357
  };
10621
- await Promise.all(Array.from({ length: Math.min(concurrency, claimed.length) }, run));
11358
+ await Promise.all(Array.from({ length: Math.min(concurrency, claimed.length) }, run2));
10622
11359
  if (failure != null) {
10623
11360
  const hydratedItems = [];
10624
11361
  for (let index = 0; index < results.length; index += 1) {
@@ -10640,70 +11377,1038 @@ function claimFailure(error) {
10640
11377
  // src/client-flow-support.ts
10641
11378
  import "buffer";
10642
11379
 
10643
- // src/client-core.ts
10644
- import "buffer";
11380
+ // src/flow-query-builder.ts
11381
+ import { Buffer as Buffer43 } from "buffer";
10645
11382
 
10646
- // src/client-core-helpers.ts
10647
- import { Buffer as Buffer35 } from "buffer";
10648
- function bgsaveResponse(response) {
10649
- if ((typeof response === "string" || Buffer35.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
10650
- return true;
11383
+ // src/flow-query-metadata.ts
11384
+ import { Buffer as Buffer42 } from "buffer";
11385
+ var MAX_FLOW_QUERY_METADATA_KEY_BYTES = 64;
11386
+ function normalizeStateMeta(value, state) {
11387
+ if (value == null) return {};
11388
+ const entries = objectEntries(value, "stateMeta");
11389
+ if (entries.length === 0) return {};
11390
+ const nested = entries.map(([, item]) => isPlainRecord(item));
11391
+ if (nested.every(Boolean)) {
11392
+ return value;
10651
11393
  }
10652
- return okResponse(response);
10653
- }
10654
- function clientNameResponse(response) {
10655
- return response == null ? null : textResponse(response, "CLIENT GETNAME");
10656
- }
10657
- function fetchOrComputeCompletionToken(options) {
10658
- if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
11394
+ if (nested.some(Boolean)) {
10659
11395
  throw new TypeError(
10660
- "fetch-or-compute completion requires computeToken"
11396
+ "stateMeta must be entirely flat or entirely nested by state"
10661
11397
  );
10662
11398
  }
10663
- if (!Buffer35.isBuffer(options.computeToken)) {
10664
- throw new TypeError("fetch-or-compute computeToken must be a Buffer");
11399
+ if (state == null || state === "" || state === "any") {
11400
+ throw new TypeError(
11401
+ "FLOW.QUERY stateMeta filters require state; a concrete state is required"
11402
+ );
10665
11403
  }
10666
- return options.computeToken;
11404
+ return { [state]: value };
10667
11405
  }
10668
- function concatCommandArgs(prefix, suffix) {
10669
- const args = new Array(prefix.length + suffix.length);
10670
- for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
10671
- for (let index = 0; index < suffix.length; index += 1) {
10672
- args[prefix.length + index] = suffix[index];
11406
+ function metadataEntries(value, context) {
11407
+ const entries = objectEntries(value ?? {}, context).map(([rawName, item]) => {
11408
+ const name = rawName.trim();
11409
+ const size = Buffer42.byteLength(name, "utf8");
11410
+ if (size === 0 || size > MAX_FLOW_QUERY_METADATA_KEY_BYTES || name.startsWith("__")) {
11411
+ throw new TypeError(`${context} key is invalid or reserved`);
11412
+ }
11413
+ return [name, item];
11414
+ });
11415
+ entries.sort(([left], [right]) => compareUnicodeScalars(left, right));
11416
+ for (let index = 1; index < entries.length; index += 1) {
11417
+ if (entries[index - 1]?.[0] === entries[index]?.[0]) {
11418
+ throw new TypeError(`${context} key is duplicated after normalization`);
11419
+ }
10673
11420
  }
10674
- return args;
11421
+ return entries;
10675
11422
  }
10676
- function unsupportedClientTracking() {
10677
- throw new InvalidCommandError(
10678
- "CLIENT TRACKING is not supported by the FerricStore native protocol; use native event subscriptions"
10679
- );
11423
+ function objectEntries(value, context) {
11424
+ if (!isPlainRecord(value))
11425
+ throw new TypeError(`${context} must be a plain object`);
11426
+ const keys = Reflect.ownKeys(value);
11427
+ if (keys.some((key) => typeof key !== "string")) {
11428
+ throw new TypeError(`${context} keys must be strings`);
11429
+ }
11430
+ return keys.map((key) => [key, value[key]]);
10680
11431
  }
10681
- function unsupportedClientCaching() {
10682
- throw new InvalidCommandError("CLIENT CACHING is not supported by the FerricStore native protocol");
11432
+ function isPlainRecord(value) {
11433
+ if (typeof value !== "object" || value == null || Array.isArray(value) || Buffer42.isBuffer(value)) {
11434
+ return false;
11435
+ }
11436
+ const prototype = Object.getPrototypeOf(value);
11437
+ return prototype === null || prototype === Object.prototype;
10683
11438
  }
10684
-
10685
- // src/client-base.ts
10686
- import "buffer";
10687
-
10688
- // src/client-executor.ts
10689
- import "buffer";
10690
- var ErrorMappingExecutor = class {
10691
- constructor(executor) {
10692
- this.executor = executor;
11439
+ function metadataSelector(root, ...names) {
11440
+ return root + names.map((name) => `['${name.replaceAll("'", "''")}']`).join("");
11441
+ }
11442
+ function compareUnicodeScalars(left, right) {
11443
+ let leftOffset = 0;
11444
+ let rightOffset = 0;
11445
+ while (leftOffset < left.length && rightOffset < right.length) {
11446
+ const leftCodePoint = left.codePointAt(leftOffset);
11447
+ const rightCodePoint = right.codePointAt(rightOffset);
11448
+ if (leftCodePoint == null || rightCodePoint == null) break;
11449
+ if (leftCodePoint !== rightCodePoint)
11450
+ return leftCodePoint < rightCodePoint ? -1 : 1;
11451
+ leftOffset += leftCodePoint > 65535 ? 2 : 1;
11452
+ rightOffset += rightCodePoint > 65535 ? 2 : 1;
10693
11453
  }
10694
- executor;
10695
- async executeCommand(...args) {
10696
- return await this.executeCommandArgs(args);
11454
+ return left.length === right.length ? 0 : leftOffset === left.length ? -1 : 1;
11455
+ }
11456
+
11457
+ // src/flow-query-builder.ts
11458
+ var MAX_FLOW_QUERY_RESULTS = 100;
11459
+ var MAX_FLOW_QUERY_PARTITION_BYTES = 65535;
11460
+ var MAX_FLOW_QUERY_TIME = Number.MAX_SAFE_INTEGER;
11461
+ var MAX_FLOW_QUERY_STATE_BYTES = 64;
11462
+ var FlowCollectionQuery = class {
11463
+ constructor(partitionKey, limit, reverse) {
11464
+ this.limit = limit;
11465
+ this.reverse = reverse;
11466
+ this.params.partition_key = partitionKey;
10697
11467
  }
10698
- async executeCommandArgs(args) {
10699
- try {
10700
- return await executeCommandArgs(this.executor, args);
10701
- } catch (error) {
10702
- throwMapped(error);
11468
+ limit;
11469
+ reverse;
11470
+ params = /* @__PURE__ */ Object.create(null);
11471
+ predicates = ["partition_key = @partition_key"];
11472
+ orderField = "updated_at_ms";
11473
+ equality(selector, parameter, value) {
11474
+ this.params[parameter] = queryParameter(value, parameter);
11475
+ this.predicates.push(`${selector} = @${parameter}`);
11476
+ }
11477
+ window(fromMs, toMs) {
11478
+ if (fromMs == null && toMs == null) return;
11479
+ const lower = fromMs == null ? 0 : boundedTime(fromMs, "fromMs");
11480
+ const upper = toMs == null ? MAX_FLOW_QUERY_TIME : boundedTime(toMs, "toMs");
11481
+ if (lower > upper) throw new TypeError("fromMs must not exceed toMs");
11482
+ this.predicates.push("updated_at_ms BETWEEN @from_ms AND @to_ms");
11483
+ this.params.from_ms = lower;
11484
+ this.params.to_ms = upper;
11485
+ }
11486
+ metadata(root, values) {
11487
+ const entries = metadataEntries(values, root);
11488
+ for (let index = 0; index < entries.length; index += 1) {
11489
+ const entry = entries[index];
11490
+ if (entry == null) throw new TypeError("metadata entries must be dense");
11491
+ this.equality(
11492
+ metadataSelector(root, entry[0]),
11493
+ `${root}_${index}`,
11494
+ entry[1]
11495
+ );
10703
11496
  }
10704
11497
  }
10705
- async executePipeline(commands, options) {
10706
- let results;
11498
+ stateMetadata(values) {
11499
+ const entries = [];
11500
+ const states = /* @__PURE__ */ new Set();
11501
+ for (const [rawState, metadata] of objectEntries(values, "stateMeta")) {
11502
+ const state = requiredText(rawState, "stateMeta state").trim();
11503
+ const stateBytes = Buffer43.byteLength(state, "utf8");
11504
+ if (stateBytes === 0 || stateBytes > MAX_FLOW_QUERY_STATE_BYTES) {
11505
+ throw new TypeError(
11506
+ `stateMeta state names must be 1..${MAX_FLOW_QUERY_STATE_BYTES} bytes`
11507
+ );
11508
+ }
11509
+ if (states.has(state)) {
11510
+ throw new TypeError(
11511
+ "stateMeta state is duplicated after normalization"
11512
+ );
11513
+ }
11514
+ states.add(state);
11515
+ if (!isPlainRecord(metadata))
11516
+ throw new TypeError("stateMeta values must be metadata maps");
11517
+ for (const [name, value] of metadataEntries(metadata, "stateMeta")) {
11518
+ entries.push([state, name, value]);
11519
+ }
11520
+ }
11521
+ entries.sort(
11522
+ ([leftState, leftName], [rightState, rightName]) => compareUnicodeScalars(leftState, rightState) || compareUnicodeScalars(leftName, rightName)
11523
+ );
11524
+ for (let index = 0; index < entries.length; index += 1) {
11525
+ const entry = entries[index];
11526
+ if (entry == null) throw new TypeError("stateMeta entries must be dense");
11527
+ this.equality(
11528
+ metadataSelector("state_meta", entry[0], entry[1]),
11529
+ `state_meta_${index}`,
11530
+ entry[2]
11531
+ );
11532
+ }
11533
+ }
11534
+ build() {
11535
+ if (this.predicates.length > 12) {
11536
+ throw new TypeError("FLOW.QUERY accepts at most 12 predicates");
11537
+ }
11538
+ const direction = this.reverse ? "DESC" : "ASC";
11539
+ const query = `FROM runs WHERE ${this.predicates.join(" AND ")} ORDER BY ${this.orderField} ${direction} LIMIT ${this.limit} RETURN RECORDS`;
11540
+ validateFlowQueryText(query);
11541
+ return { query, params: this.params };
11542
+ }
11543
+ };
11544
+ function buildFlowListQuery(type, options) {
11545
+ const attributeCount = Object.keys(options.attributes ?? {}).length;
11546
+ if (type === "any" && attributeCount === 0) {
11547
+ throw new TypeError(
11548
+ "FLOW.QUERY list requires a concrete flow type or an attribute predicate"
11549
+ );
11550
+ }
11551
+ if (options.terminalOnly !== true && options.state === "any" && attributeCount === 0) {
11552
+ throw new TypeError(
11553
+ "FLOW.QUERY list state any requires an attribute predicate"
11554
+ );
11555
+ }
11556
+ const builder = queryBuilder(options);
11557
+ addType(builder, type);
11558
+ if (options.terminalOnly === true) {
11559
+ addTerminalState(builder, options.state);
11560
+ } else if (options.state == null || options.state === "") {
11561
+ builder.equality("state", "state", "queued");
11562
+ } else if (options.state !== "any") {
11563
+ builder.equality("state", "state", requiredText(options.state, "state"));
11564
+ }
11565
+ builder.metadata("attribute", options.attributes);
11566
+ builder.window(options.fromMs, options.toMs);
11567
+ return builder.build();
11568
+ }
11569
+ function buildFlowSearchQuery(type, options) {
11570
+ const stateMeta = normalizeStateMeta(options.stateMeta, options.state);
11571
+ if (Object.keys(options.attributes ?? {}).length === 0 && Object.keys(stateMeta).length === 0) {
11572
+ throw new TypeError(
11573
+ "FLOW.QUERY search requires an attribute or stateMeta predicate"
11574
+ );
11575
+ }
11576
+ if ((type === "" || type === "any") && Object.keys(stateMeta).length > 0) {
11577
+ throw new TypeError(
11578
+ "FLOW.QUERY stateMeta predicates require a concrete flow type"
11579
+ );
11580
+ }
11581
+ const builder = queryBuilder(options);
11582
+ if (type !== "" && type !== "any")
11583
+ builder.equality("type", "type", requiredText(type, "type"));
11584
+ if (options.terminalOnly === true) {
11585
+ addTerminalState(builder, options.state);
11586
+ } else if (options.state != null && options.state !== "" && options.state !== "any") {
11587
+ builder.equality("state", "state", requiredText(options.state, "state"));
11588
+ }
11589
+ builder.metadata("attribute", options.attributes);
11590
+ builder.stateMetadata(stateMeta);
11591
+ builder.window(options.fromMs, options.toMs);
11592
+ return builder.build();
11593
+ }
11594
+ function buildFlowTerminalQuery(type, options) {
11595
+ if (requiredText(type, "type") === "any") {
11596
+ throw new TypeError("FLOW.QUERY terminals require a concrete flow type");
11597
+ }
11598
+ if (metadataEntries(options.attributes, "attribute").length > 0) {
11599
+ throw new TypeError(
11600
+ "FLOW.QUERY terminals do not support attribute predicates"
11601
+ );
11602
+ }
11603
+ const builder = queryBuilder(options);
11604
+ addType(builder, type);
11605
+ addTerminalState(builder, options.state);
11606
+ builder.window(options.fromMs, options.toMs);
11607
+ return builder.build();
11608
+ }
11609
+ function buildFlowFailureQuery(type, options) {
11610
+ if (options.state != null && options.state !== "" && options.state !== "any" && options.state !== "failed") {
11611
+ throw new TypeError("FLOW failures state must be failed or any");
11612
+ }
11613
+ return buildFlowListQuery(type, {
11614
+ ...options,
11615
+ state: "failed",
11616
+ terminalOnly: false
11617
+ });
11618
+ }
11619
+ function buildFlowLineageQuery(selector, id, options) {
11620
+ if (options.terminalOnly === true) {
11621
+ throw new TypeError("terminalOnly cannot be combined with a lineage query");
11622
+ }
11623
+ if (metadataEntries(options.attributes, "attribute").length > 0) {
11624
+ throw new TypeError(
11625
+ "FLOW.QUERY lineage does not support attribute predicates"
11626
+ );
11627
+ }
11628
+ const builder = queryBuilder(options);
11629
+ builder.equality(selector, "lineage_id", requiredText(id, "lineage id"));
11630
+ if (options.state != null && options.state !== "" && options.state !== "any") {
11631
+ builder.equality("state", "state", requiredText(options.state, "state"));
11632
+ }
11633
+ builder.metadata("attribute", options.attributes);
11634
+ builder.window(options.fromMs, options.toMs);
11635
+ return builder.build();
11636
+ }
11637
+ function buildFlowStuckQuery(type, options) {
11638
+ const concreteType = requiredText(type, "type");
11639
+ if (concreteType === "any") {
11640
+ throw new TypeError("FLOW.QUERY stuck requires a concrete flow type");
11641
+ }
11642
+ const now = options.nowMs == null ? Date.now() : boundedTime(options.nowMs, "nowMs");
11643
+ const older = options.olderThanMs == null ? 0 : boundedTime(options.olderThanMs, "olderThanMs");
11644
+ const cutoff = now - older;
11645
+ if (cutoff < 0) throw new TypeError("olderThanMs must not exceed nowMs");
11646
+ const builder = new FlowCollectionQuery(
11647
+ requiredPartition(options.partitionKey),
11648
+ boundedCount(options.count),
11649
+ false
11650
+ );
11651
+ builder.orderField = "lease_deadline_ms";
11652
+ builder.equality("type", "type", concreteType);
11653
+ builder.equality("state", "state", "running");
11654
+ builder.predicates.push(
11655
+ "lease_deadline_ms BETWEEN @lease_from_ms AND @lease_to_ms"
11656
+ );
11657
+ builder.params.lease_from_ms = 0;
11658
+ builder.params.lease_to_ms = cutoff;
11659
+ return builder.build();
11660
+ }
11661
+ function queryBuilder(options) {
11662
+ if (options.includeCold === true)
11663
+ throw new TypeError("FLOW.QUERY does not expose includeCold");
11664
+ if (options.consistentProjection === true) {
11665
+ throw new TypeError("FLOW.QUERY does not expose consistentProjection");
11666
+ }
11667
+ if (options.rev != null && typeof options.rev !== "boolean") {
11668
+ throw new TypeError("rev must be boolean");
11669
+ }
11670
+ return new FlowCollectionQuery(
11671
+ requiredPartition(options.partitionKey),
11672
+ boundedCount(options.count),
11673
+ options.rev !== false
11674
+ );
11675
+ }
11676
+ function requiredPartition(value) {
11677
+ if (typeof value !== "string") {
11678
+ throw new TypeError(
11679
+ "FLOW.QUERY convenience methods require a partition key"
11680
+ );
11681
+ }
11682
+ const size = Buffer43.byteLength(value, "utf8");
11683
+ if (size === 0 || size > MAX_FLOW_QUERY_PARTITION_BYTES) {
11684
+ throw new TypeError(
11685
+ `FLOW.QUERY partition key must be 1..${MAX_FLOW_QUERY_PARTITION_BYTES} bytes`
11686
+ );
11687
+ }
11688
+ return value;
11689
+ }
11690
+ function boundedCount(value) {
11691
+ if (value == null) return MAX_FLOW_QUERY_RESULTS;
11692
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_FLOW_QUERY_RESULTS) {
11693
+ throw new TypeError(
11694
+ `FLOW.QUERY limit must be between 1 and ${MAX_FLOW_QUERY_RESULTS}`
11695
+ );
11696
+ }
11697
+ return value;
11698
+ }
11699
+ function boundedTime(value, name) {
11700
+ if (!Number.isSafeInteger(value) || value < 0 || value > MAX_FLOW_QUERY_TIME) {
11701
+ throw new TypeError(`${name} must be a non-negative safe integer`);
11702
+ }
11703
+ return value;
11704
+ }
11705
+ function addType(builder, type) {
11706
+ const normalized = requiredText(type, "type");
11707
+ if (normalized !== "any") builder.equality("type", "type", normalized);
11708
+ }
11709
+ function addTerminalState(builder, state) {
11710
+ if (state == null || state === "" || state === "any") {
11711
+ builder.predicates.push("state IN (@terminal_0, @terminal_1, @terminal_2)");
11712
+ builder.params.terminal_0 = "completed";
11713
+ builder.params.terminal_1 = "failed";
11714
+ builder.params.terminal_2 = "cancelled";
11715
+ } else if (state === "completed" || state === "failed" || state === "cancelled") {
11716
+ builder.equality("state", "state", state);
11717
+ } else {
11718
+ throw new TypeError(
11719
+ "terminal state must be completed, failed, cancelled, or any"
11720
+ );
11721
+ }
11722
+ }
11723
+ function requiredText(value, context) {
11724
+ if (typeof value !== "string" || value.length === 0) {
11725
+ throw new TypeError(`${context} must be non-empty text`);
11726
+ }
11727
+ return value;
11728
+ }
11729
+ function queryParameter(value, context) {
11730
+ if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" || Buffer43.isBuffer(value)) {
11731
+ return value;
11732
+ }
11733
+ throw new TypeError(`${context} must be a scalar FLOW.QUERY parameter`);
11734
+ }
11735
+
11736
+ // src/flow-query-response.ts
11737
+ import { Buffer as Buffer45 } from "buffer";
11738
+
11739
+ // src/flow-query-response-validation.ts
11740
+ import { Buffer as Buffer44 } from "buffer";
11741
+ function requiredMap2(value, context) {
11742
+ if (value instanceof Map) return value;
11743
+ if (typeof value !== "object" || value == null || Array.isArray(value) || Buffer44.isBuffer(value) || value instanceof Uint8Array) {
11744
+ throw decodeError(`${context} must be a map`, value);
11745
+ }
11746
+ return value;
11747
+ }
11748
+ function freezeMap(value) {
11749
+ const output = /* @__PURE__ */ Object.create(null);
11750
+ const entries = value instanceof Map ? value.entries() : Object.entries(value);
11751
+ for (const [rawKey, item] of entries) {
11752
+ const key = strictText2(rawKey);
11753
+ if (key == null || Object.hasOwn(output, key)) {
11754
+ throw decodeError(
11755
+ "server response map contains an invalid or duplicate key",
11756
+ value
11757
+ );
11758
+ }
11759
+ output[key] = item;
11760
+ }
11761
+ return Object.freeze(output);
11762
+ }
11763
+ function freezeMetadataMap(value, context) {
11764
+ return normalizeMetadataMap(
11765
+ value,
11766
+ context,
11767
+ { remaining: DEFAULT_MAX_VALUE_ITEMS },
11768
+ /* @__PURE__ */ new Set(),
11769
+ 0
11770
+ );
11771
+ }
11772
+ function normalizeMetadataMap(value, context, budget, ancestors, depth) {
11773
+ enterMetadataContainer(value, context, budget, ancestors, depth);
11774
+ try {
11775
+ const output = /* @__PURE__ */ Object.create(null);
11776
+ const entries = value instanceof Map ? value.entries() : Object.entries(value);
11777
+ for (const [rawKey, item] of entries) {
11778
+ const key = strictText2(rawKey);
11779
+ if (key == null || Object.hasOwn(output, key)) {
11780
+ throw decodeError(`${context} contains an invalid or duplicate key`, value);
11781
+ }
11782
+ output[key] = normalizeMetadataValue(
11783
+ item,
11784
+ `${context}.${key}`,
11785
+ budget,
11786
+ ancestors,
11787
+ depth + 1
11788
+ );
11789
+ }
11790
+ return Object.freeze(output);
11791
+ } finally {
11792
+ ancestors.delete(value);
11793
+ }
11794
+ }
11795
+ function normalizeMetadataValue(value, context, budget, ancestors, depth) {
11796
+ if (typeof value === "string") {
11797
+ if (!value.isWellFormed()) throw decodeError(`${context} contains invalid text`, value);
11798
+ return value;
11799
+ }
11800
+ if (Buffer44.isBuffer(value) || value instanceof Uint8Array) {
11801
+ const decoded = strictText2(value);
11802
+ if (decoded == null) throw decodeError(`${context} contains invalid UTF-8`, value);
11803
+ return decoded;
11804
+ }
11805
+ if (value == null || typeof value === "boolean" || typeof value === "number" || typeof value === "bigint") {
11806
+ return value;
11807
+ }
11808
+ if (Array.isArray(value)) {
11809
+ enterMetadataContainer(value, context, budget, ancestors, depth);
11810
+ try {
11811
+ const output = new Array(value.length);
11812
+ for (let index = 0; index < value.length; index += 1) {
11813
+ if (!Object.hasOwn(value, index)) {
11814
+ throw decodeError(`${context} must be a dense array`, value);
11815
+ }
11816
+ output[index] = normalizeMetadataValue(
11817
+ value[index],
11818
+ `${context}[${index}]`,
11819
+ budget,
11820
+ ancestors,
11821
+ depth + 1
11822
+ );
11823
+ }
11824
+ return Object.freeze(output);
11825
+ } finally {
11826
+ ancestors.delete(value);
11827
+ }
11828
+ }
11829
+ if (value instanceof Map) {
11830
+ return normalizeMetadataMap(value, context, budget, ancestors, depth);
11831
+ }
11832
+ if (isPlainObject6(value)) {
11833
+ return normalizeMetadataMap(value, context, budget, ancestors, depth);
11834
+ }
11835
+ throw decodeError(`${context} contains an unsupported value`, value);
11836
+ }
11837
+ function enterMetadataContainer(value, context, budget, ancestors, depth) {
11838
+ if (depth >= DEFAULT_MAX_VALUE_DEPTH) {
11839
+ throw decodeError(`${context} exceeds the maximum metadata depth`, value);
11840
+ }
11841
+ if (ancestors.has(value)) throw decodeError(`${context} contains a cycle`, value);
11842
+ const size = Array.isArray(value) ? value.length : value instanceof Map ? value.size : Object.keys(value).length;
11843
+ if (size > budget.remaining) {
11844
+ throw decodeError(`${context} exceeds the maximum metadata items`, value);
11845
+ }
11846
+ budget.remaining -= size;
11847
+ ancestors.add(value);
11848
+ }
11849
+ function isPlainObject6(value) {
11850
+ const prototype = Object.getPrototypeOf(value);
11851
+ return prototype === Object.prototype || prototype === null;
11852
+ }
11853
+ function requireContract(mapping, name, expected, context) {
11854
+ const actual = requiredText2(mapping, name, context);
11855
+ if (actual !== expected) {
11856
+ throw decodeError(
11857
+ `${context} has unsupported contract ${JSON.stringify(actual)}`,
11858
+ mapping
11859
+ );
11860
+ }
11861
+ }
11862
+ function requiredText2(mapping, name, context) {
11863
+ const value = strictText2(field(mapping, name));
11864
+ if (value == null || value.length === 0) {
11865
+ throw decodeError(`${context} ${name} must be non-empty text`, mapping);
11866
+ }
11867
+ return value;
11868
+ }
11869
+ function optionalText2(mapping, name, context) {
11870
+ const raw = field(mapping, name);
11871
+ if (raw == null) return void 0;
11872
+ const value = strictText2(raw);
11873
+ if (value == null)
11874
+ throw decodeError(`${context} ${name} must be text`, mapping);
11875
+ return value;
11876
+ }
11877
+ function requiredBoundedText2(mapping, name, context, maximumBytes) {
11878
+ const value = requiredText2(mapping, name, context);
11879
+ if (Buffer44.byteLength(value, "utf8") > maximumBytes) {
11880
+ throw decodeError(
11881
+ `${context} ${name} exceeds ${maximumBytes} bytes`,
11882
+ mapping
11883
+ );
11884
+ }
11885
+ return value;
11886
+ }
11887
+ function boundedText(value, context, maximumBytes) {
11888
+ const decoded = strictText2(value);
11889
+ if (decoded == null || decoded.length === 0) {
11890
+ throw decodeError(`${context} must be non-empty text`, value);
11891
+ }
11892
+ if (Buffer44.byteLength(decoded, "utf8") > maximumBytes) {
11893
+ throw decodeError(`${context} exceeds ${maximumBytes} bytes`, value);
11894
+ }
11895
+ return decoded;
11896
+ }
11897
+ function requiredBoolean(mapping, name, context) {
11898
+ const value = field(mapping, name);
11899
+ if (typeof value !== "boolean") {
11900
+ throw decodeError(`${context} ${name} must be boolean`, mapping);
11901
+ }
11902
+ return value;
11903
+ }
11904
+ function nonNegativeInteger(value, context) {
11905
+ if (typeof value === "bigint") {
11906
+ if (value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER))
11907
+ return Number(value);
11908
+ } else if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
11909
+ return value;
11910
+ }
11911
+ throw decodeError(`${context} must be a non-negative safe integer`, value);
11912
+ }
11913
+ function positiveInteger(value, context) {
11914
+ const parsed = nonNegativeInteger(value, context);
11915
+ if (parsed === 0) throw decodeError(`${context} must be positive`, value);
11916
+ return parsed;
11917
+ }
11918
+ function boundedInteger(value, maximum, context) {
11919
+ let parsed;
11920
+ if (typeof value === "bigint") {
11921
+ parsed = value;
11922
+ } else if (typeof value === "number" && Number.isSafeInteger(value)) {
11923
+ parsed = BigInt(value);
11924
+ } else {
11925
+ throw decodeError(
11926
+ `${context} must be a lossless non-negative integer`,
11927
+ value
11928
+ );
11929
+ }
11930
+ if (parsed < 0n || parsed > maximum) {
11931
+ throw decodeError(
11932
+ `${context} is outside its supported integer range`,
11933
+ value
11934
+ );
11935
+ }
11936
+ return parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : parsed;
11937
+ }
11938
+ function positiveBoundedInteger(value, maximum, context) {
11939
+ const parsed = boundedInteger(value, maximum, context);
11940
+ if (parsed === 0) throw decodeError(`${context} must be positive`, value);
11941
+ return parsed;
11942
+ }
11943
+ function hasKey(mapping, name) {
11944
+ if (!(mapping instanceof Map)) return Object.hasOwn(mapping, name);
11945
+ if (mapping.has(name)) return true;
11946
+ const binaryName = Buffer44.from(name);
11947
+ for (const key of mapping.keys()) {
11948
+ if (Buffer44.isBuffer(key) && key.equals(binaryName)) return true;
11949
+ if (key instanceof Uint8Array && Buffer44.from(key).equals(binaryName))
11950
+ return true;
11951
+ }
11952
+ return false;
11953
+ }
11954
+ function decodeError(message, raw) {
11955
+ return new FerricStoreError(`invalid server response: ${message}`, { raw });
11956
+ }
11957
+ function strictText2(value) {
11958
+ if (typeof value === "string")
11959
+ return value.isWellFormed() ? value : void 0;
11960
+ if (Buffer44.isBuffer(value) || value instanceof Uint8Array) {
11961
+ try {
11962
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
11963
+ } catch {
11964
+ return void 0;
11965
+ }
11966
+ }
11967
+ return void 0;
11968
+ }
11969
+
11970
+ // src/flow-query-types.ts
11971
+ var FlowQueryError = class extends FerricStoreError {
11972
+ code;
11973
+ detail;
11974
+ hint;
11975
+ position;
11976
+ context;
11977
+ constructor(options) {
11978
+ super(options.message, {
11979
+ cause: options.cause,
11980
+ raw: options.raw,
11981
+ retryable: options.retryable,
11982
+ safeToRetry: options.safeToRetry,
11983
+ retryAfterMs: options.retryAfterMs
11984
+ });
11985
+ this.code = options.code;
11986
+ this.detail = options.detail;
11987
+ this.hint = options.hint;
11988
+ this.position = options.position;
11989
+ this.context = options.context;
11990
+ }
11991
+ };
11992
+
11993
+ // src/flow-query-response.ts
11994
+ var FLOW_QUERY_RESULT_CONTRACT = "ferric.flow.query.result/v1";
11995
+ var FLOW_EXPLAIN_CONTRACT = "ferric.flow.explain/v1";
11996
+ var FLOW_QUERY_INDEXES_CONTRACT = "ferric.flow.query.indexes/v1";
11997
+ var USAGE_FIELDS2 = [
11998
+ ["range_seeks", "rangeSeeks"],
11999
+ ["range_pages", "rangePages"],
12000
+ ["scanned_entries", "scannedEntries"],
12001
+ ["scanned_bytes", "scannedBytes"],
12002
+ ["hydrated_records", "hydratedRecords"],
12003
+ ["residual_checks", "residualChecks"],
12004
+ ["duplicate_entries", "duplicateEntries"],
12005
+ ["result_records", "resultRecords"],
12006
+ ["response_bytes", "responseBytes"],
12007
+ ["memory_high_water_bytes", "memoryHighWaterBytes"],
12008
+ ["wall_time_us", "wallTimeUs"]
12009
+ ];
12010
+ var MAX_SIGNED_64 = (1n << 63n) - 1n;
12011
+ var MAX_UNSIGNED_64 = (1n << 64n) - 1n;
12012
+ function decodeFlowQueryResult(value) {
12013
+ const result = decodeFlowQueryResponse(value, (mapping) => freezeMap(mapping));
12014
+ if (result.kind === "records") {
12015
+ return Object.freeze({
12016
+ kind: "records",
12017
+ version: FLOW_QUERY_RESULT_CONTRACT,
12018
+ records: Object.freeze(result.records),
12019
+ page: result.page,
12020
+ quality: result.quality,
12021
+ usage: result.usage,
12022
+ raw: result.raw
12023
+ });
12024
+ }
12025
+ return Object.freeze({
12026
+ kind: "count",
12027
+ version: FLOW_QUERY_RESULT_CONTRACT,
12028
+ count: result.count,
12029
+ quality: result.quality,
12030
+ usage: result.usage,
12031
+ raw: result.raw
12032
+ });
12033
+ }
12034
+ function decodeFlowQueryRecords(value, decodeRecord) {
12035
+ const result = decodeFlowQueryResponse(
12036
+ value,
12037
+ (mapping, index) => decodeRecord(mapping instanceof Map ? freezeMap(mapping) : mapping, index)
12038
+ );
12039
+ if (result.kind === "count") {
12040
+ throw new FerricStoreError("Flow record convenience query returned a count result", {
12041
+ raw: result.raw
12042
+ });
12043
+ }
12044
+ return result.records;
12045
+ }
12046
+ function decodeFlowQueryResponse(value, decodeRecord) {
12047
+ const mapping = requiredMap2(value, "FLOW.QUERY result");
12048
+ requireContract(mapping, "version", FLOW_QUERY_RESULT_CONTRACT, "FLOW.QUERY result");
12049
+ const quality = decodeQuality(field(mapping, "quality"));
12050
+ const usage = decodeUsage(field(mapping, "usage"));
12051
+ const hasRecords = hasKey(mapping, "records");
12052
+ const hasCount = hasKey(mapping, "result");
12053
+ if (hasRecords === hasCount) {
12054
+ throw decodeError("FLOW.QUERY result must contain exactly one records or count shape", value);
12055
+ }
12056
+ const raw = freezeMap(mapping);
12057
+ if (hasRecords) {
12058
+ const rawRecords = field(mapping, "records");
12059
+ if (!Array.isArray(rawRecords) || rawRecords.length > 100) {
12060
+ throw decodeError("FLOW.QUERY records must be an array of at most 100 maps", value);
12061
+ }
12062
+ const records = new Array(rawRecords.length);
12063
+ for (let index = 0; index < rawRecords.length; index += 1) {
12064
+ if (!Object.hasOwn(rawRecords, index)) {
12065
+ throw decodeError("FLOW.QUERY records must be a dense array", value);
12066
+ }
12067
+ records[index] = decodeRecord(
12068
+ requiredMap2(rawRecords[index], `FLOW.QUERY record ${index}`),
12069
+ index
12070
+ );
12071
+ }
12072
+ if (usage.resultRecords !== records.length) {
12073
+ throw decodeError("FLOW.QUERY usage result_records does not match records", value);
12074
+ }
12075
+ return {
12076
+ kind: "records",
12077
+ records,
12078
+ page: decodePage(field(mapping, "page")),
12079
+ quality,
12080
+ usage,
12081
+ raw
12082
+ };
12083
+ }
12084
+ if (hasKey(mapping, "page")) {
12085
+ throw decodeError("FLOW.QUERY count result contains an unexpected page", value);
12086
+ }
12087
+ const countResult = requiredMap2(field(mapping, "result"), "FLOW.QUERY count result");
12088
+ if (requiredText2(countResult, "kind", "FLOW.QUERY count result") !== "count") {
12089
+ throw decodeError("FLOW.QUERY count result kind must be count", value);
12090
+ }
12091
+ const count = boundedInteger(
12092
+ field(countResult, "value"),
12093
+ MAX_SIGNED_64,
12094
+ "FLOW.QUERY count value"
12095
+ );
12096
+ if (usage.resultRecords !== 1) {
12097
+ throw decodeError("FLOW.QUERY count usage result_records must be 1", value);
12098
+ }
12099
+ return {
12100
+ kind: "count",
12101
+ count,
12102
+ quality,
12103
+ usage,
12104
+ raw
12105
+ };
12106
+ }
12107
+ function decodeFlowExplainResult(value) {
12108
+ const mapping = requiredMap2(value, "FLOW.QUERY explain");
12109
+ requireContract(mapping, "version", FLOW_EXPLAIN_CONTRACT, "FLOW.QUERY explain");
12110
+ const queryFingerprint = requiredText2(mapping, "query_fingerprint", "FLOW.QUERY explain");
12111
+ if (!/^[0-9a-f]{64}$/iu.test(queryFingerprint)) {
12112
+ throw decodeError("FLOW.QUERY explain query_fingerprint is invalid", value);
12113
+ }
12114
+ const status = requiredText2(mapping, "status", "FLOW.QUERY explain");
12115
+ if (status !== "planned" && status !== "rejected" && status !== "executed") {
12116
+ throw decodeError(`FLOW.QUERY explain status ${JSON.stringify(status)} is unsupported`, value);
12117
+ }
12118
+ const plan = freezeMetadataMap(
12119
+ requiredMap2(field(mapping, "plan"), "FLOW.QUERY explain plan"),
12120
+ "FLOW.QUERY explain plan"
12121
+ );
12122
+ const estimate = freezeMetadataMap(
12123
+ requiredMap2(field(mapping, "estimate"), "FLOW.QUERY explain estimate"),
12124
+ "FLOW.QUERY explain estimate"
12125
+ );
12126
+ const bounds = freezeMetadataMap(
12127
+ requiredMap2(field(mapping, "bounds"), "FLOW.QUERY explain bounds"),
12128
+ "FLOW.QUERY explain bounds"
12129
+ );
12130
+ const actualValue = field(mapping, "actual");
12131
+ let actual;
12132
+ if (status === "executed") {
12133
+ if (actualValue == null) {
12134
+ throw decodeError("FLOW.QUERY executed explain is missing actual usage", value);
12135
+ }
12136
+ actual = decodeUsage(actualValue);
12137
+ } else if (actualValue != null) {
12138
+ throw decodeError("FLOW.QUERY non-executed explain contains actual usage", value);
12139
+ }
12140
+ const diagnosticValue = field(mapping, "diagnostic");
12141
+ let diagnostic;
12142
+ if (status === "rejected") {
12143
+ diagnostic = tryDecodeFlowQueryError(diagnosticValue);
12144
+ if (diagnostic == null) {
12145
+ throw decodeError("FLOW.QUERY rejected explain has an invalid diagnostic", value);
12146
+ }
12147
+ } else if (diagnosticValue != null) {
12148
+ throw decodeError("FLOW.QUERY non-rejected explain contains a diagnostic", value);
12149
+ }
12150
+ return Object.freeze({
12151
+ version: FLOW_EXPLAIN_CONTRACT,
12152
+ queryFingerprint,
12153
+ status,
12154
+ plan,
12155
+ estimate,
12156
+ bounds,
12157
+ actual,
12158
+ diagnostic,
12159
+ raw: freezeMap(mapping)
12160
+ });
12161
+ }
12162
+ function tryDecodeFlowQueryError(value, cause) {
12163
+ try {
12164
+ const mapping = requiredMap2(value, "FLOW.QUERY diagnostic");
12165
+ const contextValue = field(mapping, "context");
12166
+ const context = contextValue == null ? void 0 : freezeMetadataMap(
12167
+ requiredMap2(contextValue, "FLOW.QUERY diagnostic context"),
12168
+ "FLOW.QUERY diagnostic context"
12169
+ );
12170
+ const position = decodePosition(field(mapping, "position"));
12171
+ return new FlowQueryError({
12172
+ code: requiredText2(mapping, "code", "FLOW.QUERY diagnostic"),
12173
+ message: requiredText2(mapping, "message", "FLOW.QUERY diagnostic"),
12174
+ detail: optionalText2(mapping, "detail", "FLOW.QUERY diagnostic"),
12175
+ hint: optionalText2(mapping, "hint", "FLOW.QUERY diagnostic"),
12176
+ retryable: requiredBoolean(mapping, "retryable", "FLOW.QUERY diagnostic"),
12177
+ safeToRetry: requiredBoolean(mapping, "safe_to_retry", "FLOW.QUERY diagnostic"),
12178
+ retryAfterMs: nonNegativeInteger(
12179
+ field(mapping, "retry_after_ms"),
12180
+ "FLOW.QUERY diagnostic retry_after_ms"
12181
+ ),
12182
+ position,
12183
+ context,
12184
+ raw: value,
12185
+ cause
12186
+ });
12187
+ } catch (error) {
12188
+ if (error instanceof FerricStoreError) return void 0;
12189
+ throw error;
12190
+ }
12191
+ }
12192
+ function decodeFlowQueryIndexStatus(value) {
12193
+ const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES");
12194
+ requireContract(
12195
+ mapping,
12196
+ "contract_version",
12197
+ FLOW_QUERY_INDEXES_CONTRACT,
12198
+ "FLOW.QUERY.INDEXES"
12199
+ );
12200
+ const registry = requiredMap2(field(mapping, "registry"), "FLOW.QUERY.INDEXES registry");
12201
+ const services = freezeMetadataMap(
12202
+ requiredMap2(field(mapping, "services"), "FLOW.QUERY.INDEXES services"),
12203
+ "FLOW.QUERY.INDEXES services"
12204
+ );
12205
+ const rawIndexes = field(mapping, "indexes");
12206
+ if (!Array.isArray(rawIndexes) || rawIndexes.length > 32) {
12207
+ throw decodeError("FLOW.QUERY.INDEXES indexes must contain at most 32 entries", value);
12208
+ }
12209
+ const indexes = new Array(rawIndexes.length);
12210
+ for (let index = 0; index < rawIndexes.length; index += 1) {
12211
+ if (!Object.hasOwn(rawIndexes, index)) {
12212
+ throw decodeError("FLOW.QUERY.INDEXES indexes must be a dense array", value);
12213
+ }
12214
+ indexes[index] = decodeIndex(rawIndexes[index], index);
12215
+ }
12216
+ return Object.freeze({
12217
+ contractVersion: FLOW_QUERY_INDEXES_CONTRACT,
12218
+ observedAtMs: nonNegativeInteger(
12219
+ field(mapping, "observed_at_ms"),
12220
+ "FLOW.QUERY.INDEXES observed_at_ms"
12221
+ ),
12222
+ statisticsMaxAgeMs: nonNegativeInteger(
12223
+ field(mapping, "statistics_max_age_ms"),
12224
+ "FLOW.QUERY.INDEXES statistics_max_age_ms"
12225
+ ),
12226
+ registry: Object.freeze({
12227
+ epoch: boundedInteger(
12228
+ field(registry, "epoch"),
12229
+ MAX_UNSIGNED_64,
12230
+ "FLOW.QUERY.INDEXES epoch"
12231
+ ),
12232
+ catalogVersion: positiveBoundedInteger(
12233
+ field(registry, "catalog_version"),
12234
+ MAX_UNSIGNED_64,
12235
+ "FLOW.QUERY.INDEXES catalog_version"
12236
+ )
12237
+ }),
12238
+ services,
12239
+ indexes: Object.freeze(indexes),
12240
+ raw: freezeMap(mapping)
12241
+ });
12242
+ }
12243
+ function decodeIndex(value, index) {
12244
+ const mapping = requiredMap2(value, `FLOW.QUERY.INDEXES index ${index}`);
12245
+ return Object.freeze({
12246
+ id: requiredText2(mapping, "id", "FLOW.QUERY.INDEXES index"),
12247
+ version: positiveBoundedInteger(
12248
+ field(mapping, "version"),
12249
+ MAX_UNSIGNED_64,
12250
+ "FLOW.QUERY.INDEXES index version"
12251
+ ),
12252
+ buildId: requiredText2(mapping, "build_id", "FLOW.QUERY.INDEXES index"),
12253
+ state: requiredText2(mapping, "state", "FLOW.QUERY.INDEXES index"),
12254
+ queryable: requiredBoolean(mapping, "queryable", "FLOW.QUERY.INDEXES index"),
12255
+ coveringFields: decodeCoveringFields(mapping),
12256
+ format: decodeIndexFormat(mapping),
12257
+ raw: freezeMap(mapping)
12258
+ });
12259
+ }
12260
+ function decodeCoveringFields(mapping) {
12261
+ const raw = field(mapping, "covering_fields");
12262
+ if (!Array.isArray(raw) || raw.length > 32) {
12263
+ throw decodeError(
12264
+ "FLOW.QUERY.INDEXES index covering_fields must contain at most 32 entries",
12265
+ raw
12266
+ );
12267
+ }
12268
+ const fields = new Array(raw.length);
12269
+ const seen = /* @__PURE__ */ new Set();
12270
+ for (let index = 0; index < raw.length; index += 1) {
12271
+ if (!Object.hasOwn(raw, index)) {
12272
+ throw decodeError("FLOW.QUERY.INDEXES index covering_fields must be dense", raw);
12273
+ }
12274
+ const value = boundedText(
12275
+ raw[index],
12276
+ `FLOW.QUERY.INDEXES index covering_fields entry ${index}`,
12277
+ 512
12278
+ );
12279
+ if (seen.has(value)) {
12280
+ throw decodeError("FLOW.QUERY.INDEXES index covering_fields contains duplicates", raw);
12281
+ }
12282
+ seen.add(value);
12283
+ fields[index] = value;
12284
+ }
12285
+ return Object.freeze(fields);
12286
+ }
12287
+ function decodeIndexFormat(mapping) {
12288
+ const raw = requiredMap2(field(mapping, "format"), "FLOW.QUERY.INDEXES index format");
12289
+ if (!hasKey(raw, "counter")) {
12290
+ throw decodeError("FLOW.QUERY.INDEXES index format counter is missing", raw);
12291
+ }
12292
+ const counterValue = field(raw, "counter");
12293
+ const counter = counterValue === null ? void 0 : boundedText(counterValue, "FLOW.QUERY.INDEXES index format counter", 128);
12294
+ return Object.freeze({
12295
+ queryRow: requiredBoundedText2(raw, "query_row", "FLOW.QUERY.INDEXES index format", 128),
12296
+ key: requiredBoundedText2(raw, "key", "FLOW.QUERY.INDEXES index format", 128),
12297
+ entry: requiredBoundedText2(raw, "entry", "FLOW.QUERY.INDEXES index format", 128),
12298
+ reverse: requiredBoundedText2(raw, "reverse", "FLOW.QUERY.INDEXES index format", 128),
12299
+ counter,
12300
+ raw: freezeMap(raw)
12301
+ });
12302
+ }
12303
+ function decodeQuality(value) {
12304
+ const mapping = requiredMap2(value, "FLOW.QUERY quality");
12305
+ return Object.freeze({
12306
+ exactness: requiredBoundedText2(mapping, "exactness", "FLOW.QUERY quality", 64),
12307
+ freshness: requiredBoundedText2(mapping, "freshness", "FLOW.QUERY quality", 64),
12308
+ coverage: requiredBoundedText2(mapping, "coverage", "FLOW.QUERY quality", 64),
12309
+ pagination: requiredBoundedText2(mapping, "pagination", "FLOW.QUERY quality", 64)
12310
+ });
12311
+ }
12312
+ function decodeUsage(value) {
12313
+ const mapping = requiredMap2(value, "FLOW.QUERY usage");
12314
+ const usage = /* @__PURE__ */ Object.create(null);
12315
+ for (const [wireName, property] of USAGE_FIELDS2) {
12316
+ usage[property] = nonNegativeInteger(
12317
+ field(mapping, wireName),
12318
+ `FLOW.QUERY usage ${wireName}`
12319
+ );
12320
+ }
12321
+ return Object.freeze(usage);
12322
+ }
12323
+ function decodePage(value) {
12324
+ const mapping = requiredMap2(value, "FLOW.QUERY page");
12325
+ const hasMore = requiredBoolean(mapping, "has_more", "FLOW.QUERY page");
12326
+ const cursor = optionalText2(mapping, "cursor", "FLOW.QUERY page");
12327
+ if (cursor != null && (!cursor.startsWith("fqc1_") || Buffer45.byteLength(cursor) > 4096)) {
12328
+ throw decodeError("FLOW.QUERY page cursor is invalid", value);
12329
+ }
12330
+ if (hasMore !== (cursor != null)) {
12331
+ throw decodeError("FLOW.QUERY page has_more and cursor are inconsistent", value);
12332
+ }
12333
+ return Object.freeze({ hasMore, ...cursor == null ? {} : { cursor } });
12334
+ }
12335
+ function decodePosition(value) {
12336
+ if (value == null) return void 0;
12337
+ const mapping = requiredMap2(value, "FLOW.QUERY diagnostic position");
12338
+ return Object.freeze({
12339
+ byte: positiveInteger(field(mapping, "byte"), "FLOW.QUERY diagnostic position byte"),
12340
+ line: positiveInteger(field(mapping, "line"), "FLOW.QUERY diagnostic position line"),
12341
+ column: positiveInteger(
12342
+ field(mapping, "column"),
12343
+ "FLOW.QUERY diagnostic position column"
12344
+ )
12345
+ });
12346
+ }
12347
+
12348
+ // src/client-core.ts
12349
+ import "buffer";
12350
+
12351
+ // src/client-core-helpers.ts
12352
+ import { Buffer as Buffer46 } from "buffer";
12353
+ function bgsaveResponse(response) {
12354
+ if ((typeof response === "string" || Buffer46.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
12355
+ return true;
12356
+ }
12357
+ return okResponse(response);
12358
+ }
12359
+ function clientNameResponse(response) {
12360
+ return response == null ? null : textResponse(response, "CLIENT GETNAME");
12361
+ }
12362
+ function fetchOrComputeCompletionToken(options) {
12363
+ if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
12364
+ throw new TypeError(
12365
+ "fetch-or-compute completion requires computeToken"
12366
+ );
12367
+ }
12368
+ if (!Buffer46.isBuffer(options.computeToken)) {
12369
+ throw new TypeError("fetch-or-compute computeToken must be a Buffer");
12370
+ }
12371
+ return options.computeToken;
12372
+ }
12373
+ function concatCommandArgs(prefix, suffix) {
12374
+ const args = new Array(prefix.length + suffix.length);
12375
+ for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
12376
+ for (let index = 0; index < suffix.length; index += 1) {
12377
+ args[prefix.length + index] = suffix[index];
12378
+ }
12379
+ return args;
12380
+ }
12381
+ function unsupportedClientTracking() {
12382
+ throw new InvalidCommandError(
12383
+ "CLIENT TRACKING is not supported by the FerricStore native protocol; use native event subscriptions"
12384
+ );
12385
+ }
12386
+ function unsupportedClientCaching() {
12387
+ throw new InvalidCommandError("CLIENT CACHING is not supported by the FerricStore native protocol");
12388
+ }
12389
+
12390
+ // src/client-base.ts
12391
+ import "buffer";
12392
+
12393
+ // src/client-executor.ts
12394
+ import "buffer";
12395
+ var ErrorMappingExecutor = class {
12396
+ constructor(executor) {
12397
+ this.executor = executor;
12398
+ }
12399
+ executor;
12400
+ async executeCommand(...args) {
12401
+ return await this.executeCommandArgs(args);
12402
+ }
12403
+ async executeCommandArgs(args) {
12404
+ try {
12405
+ return await executeCommandArgs(this.executor, args);
12406
+ } catch (error) {
12407
+ throwMapped(error);
12408
+ }
12409
+ }
12410
+ async executePipeline(commands, options) {
12411
+ let results;
10707
12412
  try {
10708
12413
  if (this.executor.executePipeline != null) {
10709
12414
  results = await this.executor.executePipeline(commands, options);
@@ -11020,14 +12725,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
11020
12725
  };
11021
12726
 
11022
12727
  // src/store-utilities.ts
11023
- import { Buffer as Buffer38 } from "buffer";
12728
+ import { Buffer as Buffer49 } from "buffer";
11024
12729
  function encode(codec, value) {
11025
12730
  return codec.encode(value);
11026
12731
  }
11027
12732
  function decode(codec, value) {
11028
12733
  if (value == null) return null;
11029
- if (Buffer38.isBuffer(value)) return codec.decode(value);
11030
- if (value instanceof Uint8Array) return codec.decode(Buffer38.from(value));
12734
+ if (Buffer49.isBuffer(value)) return codec.decode(value);
12735
+ if (value instanceof Uint8Array) return codec.decode(Buffer49.from(value));
11031
12736
  return value;
11032
12737
  }
11033
12738
  function number(value) {
@@ -11088,7 +12793,7 @@ function requireNonEmpty(values, command, noun = "argument") {
11088
12793
  if (values.length === 0) throw new TypeError(`${command} requires at least one ${noun}`);
11089
12794
  return values;
11090
12795
  }
11091
- function commandName3(args) {
12796
+ function commandName4(args) {
11092
12797
  return typeof args[0] === "string" ? args[0] : "command";
11093
12798
  }
11094
12799
  function commandArgs(client, args) {
@@ -11103,7 +12808,7 @@ function arrayOrRest(values) {
11103
12808
  function appendXReadStreams(args, streams) {
11104
12809
  const offset = args.length;
11105
12810
  const streamCount = streams.length;
11106
- requireNonEmpty(streams, commandName3(args), "stream");
12811
+ requireNonEmpty(streams, commandName4(args), "stream");
11107
12812
  args.length = offset + 1 + streamCount * 2;
11108
12813
  args[offset] = "STREAMS";
11109
12814
  for (let index = 0; index < streamCount; index += 1) {
@@ -11113,7 +12818,7 @@ function appendXReadStreams(args, streams) {
11113
12818
  const stream = streams[index];
11114
12819
  if (stream == null) throw new TypeError("XREAD streams must contain only stream descriptors");
11115
12820
  if (!Object.hasOwn(stream, "key") || !Object.hasOwn(stream, "id")) {
11116
- throw new TypeError(`${commandName3(args)} streams require own key and id fields`);
12821
+ throw new TypeError(`${commandName4(args)} streams require own key and id fields`);
11117
12822
  }
11118
12823
  args[offset + 1 + index] = stream.key;
11119
12824
  args[offset + 1 + streamCount + index] = stream.id;
@@ -11135,7 +12840,7 @@ function concatArgs(...parts) {
11135
12840
  return args;
11136
12841
  }
11137
12842
  function encodedArgs(prefix, codec, values, allowEmpty = false) {
11138
- if (!allowEmpty) requireNonEmpty(values, commandName3(prefix));
12843
+ if (!allowEmpty) requireNonEmpty(values, commandName4(prefix));
11139
12844
  const args = new Array(prefix.length + values.length);
11140
12845
  for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
11141
12846
  for (let index = 0; index < values.length; index += 1) {
@@ -11149,7 +12854,7 @@ function encodedArgs(prefix, codec, values, allowEmpty = false) {
11149
12854
  function keyValueArgs(prefix, codec, entries) {
11150
12855
  const validateTuples = Array.isArray(entries);
11151
12856
  const pairs = validateTuples ? entries : Object.entries(entries);
11152
- requireNonEmpty(pairs, commandName3(prefix), "entry");
12857
+ requireNonEmpty(pairs, commandName4(prefix), "entry");
11153
12858
  const args = new Array(prefix.length + pairs.length * 2);
11154
12859
  for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
11155
12860
  for (let index = 0; index < pairs.length; index += 1) {
@@ -11163,7 +12868,7 @@ function keyValueArgs(prefix, codec, entries) {
11163
12868
  return args;
11164
12869
  }
11165
12870
  function encodedEntryArgs(prefix, codec, entries) {
11166
- requireNonEmpty(entries, commandName3(prefix), "entry");
12871
+ requireNonEmpty(entries, commandName4(prefix), "entry");
11167
12872
  const args = new Array(prefix.length + entries.length * 2);
11168
12873
  for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
11169
12874
  for (let index = 0; index < entries.length; index += 1) {
@@ -11617,15 +13322,15 @@ function compressionOptions(options) {
11617
13322
  // src/store-decoders.ts
11618
13323
  function decodeHashRecord(codec, value) {
11619
13324
  const result = {};
11620
- for (const [field2, item] of hashPairs(value)) {
11621
- setOwnValue(result, textToken(field2), decode(codec, item));
13325
+ for (const [field3, item] of hashPairs(value)) {
13326
+ setOwnValue(result, textToken(field3), decode(codec, item));
11622
13327
  }
11623
13328
  return result;
11624
13329
  }
11625
13330
  function decodeHashFlatPairs(codec, value) {
11626
13331
  const result = [];
11627
- for (const [field2, item] of hashPairs(value)) {
11628
- result.push(textToken(field2), decode(codec, item));
13332
+ for (const [field3, item] of hashPairs(value)) {
13333
+ result.push(textToken(field3), decode(codec, item));
11629
13334
  }
11630
13335
  return result;
11631
13336
  }
@@ -11745,7 +13450,7 @@ function requiredPair(value, message) {
11745
13450
  }
11746
13451
  function decodeStreamFieldValues(codec, value) {
11747
13452
  const result = [];
11748
- for (const [field2, item] of hashPairs(value)) result.push(textToken(field2), decode(codec, item));
13453
+ for (const [field3, item] of hashPairs(value)) result.push(textToken(field3), decode(codec, item));
11749
13454
  return result;
11750
13455
  }
11751
13456
  var geoSearchMetadataTokens = /* @__PURE__ */ new Set(["WITHCOORD", "WITHDIST", "WITHHASH"]);
@@ -12559,8 +14264,8 @@ var HashStore = class {
12559
14264
  async hset(key, entries) {
12560
14265
  return number(await commandArgs(this.client, keyValueArgs(["HSET", key], this.client.codec, entries)));
12561
14266
  }
12562
- async hget(key, field2) {
12563
- return decode(this.client.codec, await this.client.command("HGET", key, field2));
14267
+ async hget(key, field3) {
14268
+ return decode(this.client.codec, await this.client.command("HGET", key, field3));
12564
14269
  }
12565
14270
  async hdel(key, ...fieldsOrArray) {
12566
14271
  const fields = requireNonEmpty(arrayOrRest(fieldsOrArray), "HDEL", "field");
@@ -12579,8 +14284,8 @@ var HashStore = class {
12579
14284
  async hgetall(key) {
12580
14285
  return decodeHashRecord(this.client.codec, await this.client.command("HGETALL", key));
12581
14286
  }
12582
- async hexists(key, field2) {
12583
- return binaryBooleanResponse(await this.client.command("HEXISTS", key, field2));
14287
+ async hexists(key, field3) {
14288
+ return binaryBooleanResponse(await this.client.command("HEXISTS", key, field3));
12584
14289
  }
12585
14290
  async hkeys(key) {
12586
14291
  return mapArray(await this.client.command("HKEYS", key), "HKEYS", textToken);
@@ -12595,17 +14300,17 @@ var HashStore = class {
12595
14300
  async hlen(key) {
12596
14301
  return number(await this.client.command("HLEN", key));
12597
14302
  }
12598
- async hincrby(key, field2, increment) {
12599
- return integerReply(await this.client.command("HINCRBY", key, field2, increment));
14303
+ async hincrby(key, field3, increment) {
14304
+ return integerReply(await this.client.command("HINCRBY", key, field3, increment));
12600
14305
  }
12601
- async hincrbyfloat(key, field2, increment) {
12602
- return string(await this.client.command("HINCRBYFLOAT", key, field2, increment));
14306
+ async hincrbyfloat(key, field3, increment) {
14307
+ return string(await this.client.command("HINCRBYFLOAT", key, field3, increment));
12603
14308
  }
12604
- async hsetnx(key, field2, value) {
12605
- return binaryBooleanResponse(await this.client.command("HSETNX", key, field2, encode(this.client.codec, value)));
14309
+ async hsetnx(key, field3, value) {
14310
+ return binaryBooleanResponse(await this.client.command("HSETNX", key, field3, encode(this.client.codec, value)));
12606
14311
  }
12607
- async hstrlen(key, field2) {
12608
- return number(await this.client.command("HSTRLEN", key, field2));
14312
+ async hstrlen(key, field3) {
14313
+ return number(await this.client.command("HSTRLEN", key, field3));
12609
14314
  }
12610
14315
  async hrandfield(key, count, withValues = false) {
12611
14316
  if (withValues && count == null) {
@@ -13241,6 +14946,100 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
13241
14946
  }
13242
14947
  };
13243
14948
 
14949
+ // src/client-flow-query.ts
14950
+ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
14951
+ async query(query, params = {}) {
14952
+ if (hasFlowExplainPrefix(query)) {
14953
+ throw new TypeError("query does not accept EXPLAIN; use explain or explainAnalyze");
14954
+ }
14955
+ return decodeFlowQueryResult(await this.executeFlowQuery(query, params));
14956
+ }
14957
+ async explain(query, params = {}) {
14958
+ return await this.executeExplain("EXPLAIN ", query, params);
14959
+ }
14960
+ async explainAnalyze(query, params = {}) {
14961
+ return await this.executeExplain("EXPLAIN ANALYZE ", query, params);
14962
+ }
14963
+ async queryIndexes(indexId) {
14964
+ const args = ["FLOW.QUERY.INDEXES"];
14965
+ if (indexId != null) {
14966
+ validateFlowQueryIndexId(indexId);
14967
+ args.push(indexId);
14968
+ }
14969
+ try {
14970
+ return decodeFlowQueryIndexStatus(await this.commandArgs(args));
14971
+ } catch (error) {
14972
+ this.throwFlowQueryError(error);
14973
+ }
14974
+ }
14975
+ async list(type, options) {
14976
+ return await this.executeFlowRecordQuery(buildFlowListQuery(type, options));
14977
+ }
14978
+ async search(type, options) {
14979
+ return await this.executeFlowRecordQuery(buildFlowSearchQuery(type, options));
14980
+ }
14981
+ async terminals(type, options) {
14982
+ return await this.executeFlowRecordQuery(buildFlowTerminalQuery(type, options));
14983
+ }
14984
+ async failures(type, options) {
14985
+ return await this.executeFlowRecordQuery(buildFlowFailureQuery(type, options));
14986
+ }
14987
+ async byParent(parentFlowId, options) {
14988
+ return await this.executeFlowRecordQuery(
14989
+ buildFlowLineageQuery("parent_flow_id", parentFlowId, options)
14990
+ );
14991
+ }
14992
+ async byRoot(rootFlowId, options) {
14993
+ return await this.executeFlowRecordQuery(
14994
+ buildFlowLineageQuery("root_flow_id", rootFlowId, options)
14995
+ );
14996
+ }
14997
+ async byCorrelation(correlationId, options) {
14998
+ return await this.executeFlowRecordQuery(
14999
+ buildFlowLineageQuery("correlation_id", correlationId, options)
15000
+ );
15001
+ }
15002
+ async stuck(type, options) {
15003
+ return await this.executeFlowRecordQuery(buildFlowStuckQuery(type, options));
15004
+ }
15005
+ records(values) {
15006
+ const records = new Array(values.length);
15007
+ for (let index = 0; index < values.length; index += 1) {
15008
+ if (!Object.hasOwn(values, index)) {
15009
+ throw new TypeError(`Flow record response item ${index} is missing`);
15010
+ }
15011
+ records[index] = flowRecordFromResp(values[index], this.codec);
15012
+ }
15013
+ return records;
15014
+ }
15015
+ async executeFlowQuery(query, params) {
15016
+ const args = flowQueryArgs(query, params);
15017
+ try {
15018
+ return await this.commandArgs(args);
15019
+ } catch (error) {
15020
+ this.throwFlowQueryError(error);
15021
+ }
15022
+ }
15023
+ async executeFlowRecordQuery(request) {
15024
+ const response = await this.executeFlowQuery(request.query, request.params);
15025
+ return decodeFlowQueryRecords(response, (value) => flowRecordFromResp(value, this.codec));
15026
+ }
15027
+ async executeExplain(prefix, query, params) {
15028
+ validateFlowQueryText(query);
15029
+ if (hasFlowExplainPrefix(query)) {
15030
+ throw new TypeError("query already contains an EXPLAIN prefix");
15031
+ }
15032
+ return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query.trim(), params));
15033
+ }
15034
+ throwFlowQueryError(error) {
15035
+ if (error instanceof FerricStoreError) {
15036
+ const diagnostic = tryDecodeFlowQueryError(error.raw, error);
15037
+ if (diagnostic != null) throw diagnostic;
15038
+ }
15039
+ throw error;
15040
+ }
15041
+ };
15042
+
13244
15043
  // src/producer-backpressure.ts
13245
15044
  async function executeProducerWriteWithBackpressure(execute, policy, signal) {
13246
15045
  for (let attempt = 0; ; attempt += 1) {
@@ -13262,8 +15061,167 @@ function throwIfClosed(signal) {
13262
15061
  throw new FerricStoreError("FerricStore client is closed", { raw: signal.reason });
13263
15062
  }
13264
15063
 
15064
+ // src/flow-policy.ts
15065
+ import { Buffer as Buffer51 } from "buffer";
15066
+ var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
15067
+ function assertFlowPolicyGeneration(value) {
15068
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
15069
+ throw new TypeError("expectedGeneration must be a nonnegative safe integer");
15070
+ }
15071
+ }
15072
+ function flowPolicySnapshotFromResp(value) {
15073
+ const policy = requiredRecord(value, "FLOW policy snapshot");
15074
+ const maxActiveMs = optionalPositiveInteger(field(policy, "max_active_ms"), "max_active_ms");
15075
+ const state = optionalText3(field(policy, "state"), "state");
15076
+ const mode = optionalMode(field(policy, "mode"), "mode");
15077
+ const version = optionalVersion(field(policy, "version"));
15078
+ const indexedStateMeta = optionalText3(field(policy, "indexed_state_meta"), "indexed_state_meta");
15079
+ const governance = optionalRecord(field(policy, "governance"), "governance");
15080
+ const states = optionalStates(field(policy, "states"));
15081
+ return {
15082
+ type: requiredText3(field(policy, "type"), "type"),
15083
+ generation: nonNegativeInteger2(field(policy, "generation"), "generation"),
15084
+ ...state == null ? {} : { state },
15085
+ ...version == null ? {} : { version },
15086
+ ...mode == null ? {} : { mode },
15087
+ ...maxActiveMs == null ? {} : { maxActiveMs },
15088
+ retry: retrySnapshot(field(policy, "retry"), "retry"),
15089
+ retention: retentionSnapshot(field(policy, "retention"), "retention"),
15090
+ indexedAttributes: stringArray(field(policy, "indexed_attributes"), "indexed_attributes"),
15091
+ ...indexedStateMeta == null ? {} : { indexedStateMeta },
15092
+ ...governance == null ? {} : { governance },
15093
+ ...states == null ? {} : { states },
15094
+ raw: value
15095
+ };
15096
+ }
15097
+ function retrySnapshot(value, context) {
15098
+ const retry2 = requiredRecord(value, `FLOW policy ${context}`);
15099
+ const backoff = requiredRecord(field(retry2, "backoff"), `FLOW policy ${context}.backoff`);
15100
+ return {
15101
+ maxRetries: nonNegativeInteger2(field(retry2, "max_retries"), `${context}.max_retries`),
15102
+ backoff: {
15103
+ kind: backoffKind(field(backoff, "kind"), `${context}.backoff.kind`),
15104
+ baseMs: nonNegativeInteger2(field(backoff, "base_ms"), `${context}.backoff.base_ms`),
15105
+ maxMs: nonNegativeInteger2(field(backoff, "max_ms"), `${context}.backoff.max_ms`),
15106
+ jitterPct: nonNegativeInteger2(field(backoff, "jitter_pct"), `${context}.backoff.jitter_pct`)
15107
+ },
15108
+ exhaustedTo: requiredText3(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
15109
+ };
15110
+ }
15111
+ function retentionSnapshot(value, context) {
15112
+ const retention = requiredRecord(value, `FLOW policy ${context}`);
15113
+ return {
15114
+ ttlMs: nonNegativeInteger2(field(retention, "ttl_ms"), `${context}.ttl_ms`),
15115
+ historyMaxEvents: nonNegativeInteger2(
15116
+ field(retention, "history_max_events"),
15117
+ `${context}.history_max_events`
15118
+ )
15119
+ };
15120
+ }
15121
+ function optionalStates(value) {
15122
+ if (value == null) return void 0;
15123
+ const source = requiredRecord(value, "FLOW policy states");
15124
+ const result = {};
15125
+ for (const [state, raw] of Object.entries(source)) {
15126
+ const policy = requiredRecord(raw, `FLOW policy state ${state}`);
15127
+ const maxActiveMs = optionalPositiveInteger(
15128
+ field(policy, "max_active_ms"),
15129
+ `states.${state}.max_active_ms`
15130
+ );
15131
+ const governance = optionalRecord(field(policy, "governance"), `states.${state}.governance`);
15132
+ Object.defineProperty(result, state, {
15133
+ configurable: true,
15134
+ enumerable: true,
15135
+ value: {
15136
+ mode: requiredMode(field(policy, "mode"), `states.${state}.mode`),
15137
+ ...maxActiveMs == null ? {} : { maxActiveMs },
15138
+ retry: retrySnapshot(field(policy, "retry"), `states.${state}.retry`),
15139
+ retention: retentionSnapshot(field(policy, "retention"), `states.${state}.retention`),
15140
+ ...governance == null ? {} : { governance }
15141
+ },
15142
+ writable: true
15143
+ });
15144
+ }
15145
+ return result;
15146
+ }
15147
+ function requiredRecord(value, context) {
15148
+ if (value instanceof Map) {
15149
+ const result = {};
15150
+ for (const [key, item] of value.entries()) {
15151
+ setOwnValue(result, requiredText3(key, `${context} key`), item);
15152
+ }
15153
+ return result;
15154
+ }
15155
+ if (typeof value === "object" && value != null && !Array.isArray(value) && !Buffer51.isBuffer(value) && !(value instanceof Uint8Array)) return value;
15156
+ throw new TypeError(`${context} returned an unexpected response`);
15157
+ }
15158
+ function optionalRecord(value, context) {
15159
+ return value == null ? void 0 : requiredRecord(value, `FLOW policy ${context}`);
15160
+ }
15161
+ function stringArray(value, context) {
15162
+ if (!Array.isArray(value)) {
15163
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15164
+ }
15165
+ const result = new Array(value.length);
15166
+ for (let index = 0; index < value.length; index += 1) {
15167
+ if (!Object.hasOwn(value, index)) {
15168
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15169
+ }
15170
+ result[index] = requiredText3(value[index], `${context}[${index}]`);
15171
+ }
15172
+ return result;
15173
+ }
15174
+ function requiredText3(value, context) {
15175
+ if (typeof value === "string") return value;
15176
+ if (Buffer51.isBuffer(value) || value instanceof Uint8Array) {
15177
+ return Buffer51.from(value).toString("utf8");
15178
+ }
15179
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15180
+ }
15181
+ function optionalText3(value, context) {
15182
+ return value == null ? void 0 : requiredText3(value, context);
15183
+ }
15184
+ function nonNegativeInteger2(value, context) {
15185
+ let parsed;
15186
+ try {
15187
+ parsed = integer(value);
15188
+ } catch {
15189
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15190
+ }
15191
+ if (parsed < 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15192
+ return parsed;
15193
+ }
15194
+ function optionalPositiveInteger(value, context) {
15195
+ if (value == null) return void 0;
15196
+ const parsed = nonNegativeInteger2(value, context);
15197
+ if (parsed === 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15198
+ return parsed;
15199
+ }
15200
+ function optionalVersion(value) {
15201
+ if (value == null) return void 0;
15202
+ if (typeof value === "number" || typeof value === "bigint") {
15203
+ return nonNegativeInteger2(value, "version");
15204
+ }
15205
+ return requiredText3(value, "version");
15206
+ }
15207
+ function backoffKind(value, context) {
15208
+ const kind = requiredText3(value, context).toLowerCase();
15209
+ if (kind === "none" || kind === "fixed" || kind === "linear" || kind === "exponential") {
15210
+ return kind;
15211
+ }
15212
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15213
+ }
15214
+ function requiredMode(value, context) {
15215
+ const mode = requiredText3(value, context).toLowerCase();
15216
+ if (mode === "fifo" || mode === "parallel") return mode;
15217
+ throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
15218
+ }
15219
+ function optionalMode(value, context) {
15220
+ return value == null ? void 0 : requiredMode(value, context);
15221
+ }
15222
+
13265
15223
  // src/client-flow-support.ts
13266
- var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
15224
+ var FerricStoreFlowSupportClient = class extends FerricStoreFlowQueryClient {
13267
15225
  async rewind(id, options = {}) {
13268
15226
  const partitionKey = options.partitionKey;
13269
15227
  const returnRecord = options.returnRecord === true;
@@ -13289,43 +15247,9 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13289
15247
  }
13290
15248
  return flowRecordFromResp(response, this.codec);
13291
15249
  }
13292
- async list(type, options = {}) {
13293
- return await this.indexQuery("FLOW.LIST", type, options);
13294
- }
13295
- async search(type, options = {}) {
13296
- const args = ["FLOW.SEARCH", type];
13297
- appendReadOptions(args, options);
13298
- appendAttributes(args, options.attributes);
13299
- appendSearchStateMeta(args, options.state, options.stateMeta);
13300
- const response = await this.commandArgs(args);
13301
- return this.records(requiredArrayResponse(response, "FLOW.SEARCH"));
13302
- }
13303
- async terminals(type, options = {}) {
13304
- return await this.indexQuery("FLOW.TERMINALS", type, options);
13305
- }
13306
- async failures(type, options = {}) {
13307
- return await this.indexQuery("FLOW.FAILURES", type, options);
13308
- }
13309
- async byParent(parentFlowId, options = {}) {
13310
- return await this.indexQuery("FLOW.BY_PARENT", parentFlowId, options);
13311
- }
13312
- async byRoot(rootFlowId, options = {}) {
13313
- return await this.indexQuery("FLOW.BY_ROOT", rootFlowId, options);
13314
- }
13315
- async byCorrelation(correlationId, options = {}) {
13316
- return await this.indexQuery("FLOW.BY_CORRELATION", correlationId, options);
13317
- }
13318
15250
  async info(type) {
13319
15251
  return parseKvResponse(await this.command("FLOW.INFO", type));
13320
15252
  }
13321
- async stuck(type, options = {}) {
13322
- const args = ["FLOW.STUCK", type];
13323
- append(args, "PARTITION", options.partitionKey);
13324
- append(args, "COUNT", options.count);
13325
- append(args, "OLDER_THAN", options.olderThanMs);
13326
- append(args, "NOW", options.nowMs);
13327
- return this.records(arrayResponse(await this.commandArgs(args)));
13328
- }
13329
15253
  async history(id, options = {}) {
13330
15254
  const args = ["FLOW.HISTORY", id];
13331
15255
  append(args, "PARTITION", options.partitionKey);
@@ -13404,27 +15328,36 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13404
15328
  }
13405
15329
  async installPolicy(type, options = {}) {
13406
15330
  const args = ["FLOW.POLICY.SET", type];
15331
+ const expectedGeneration = Object.hasOwn(options, "expectedGeneration") ? options.expectedGeneration : void 0;
15332
+ const replace = Object.hasOwn(options, "replace") ? options.replace : void 0;
15333
+ if (expectedGeneration != null) assertFlowPolicyGeneration(expectedGeneration);
15334
+ if (replace != null && typeof replace !== "boolean") {
15335
+ throw new TypeError("replace must be a boolean");
15336
+ }
15337
+ append(args, "EXPECTED_GENERATION", expectedGeneration);
15338
+ appendBool(args, "REPLACE", replace);
13407
15339
  if (options.indexedAttributes != null) {
13408
15340
  args.push("INDEXED_ATTRIBUTES", JSON.stringify(options.indexedAttributes));
13409
15341
  }
13410
15342
  append(args, "INDEXED_STATE_META", options.indexedStateMeta);
13411
15343
  append(args, "MAX_ACTIVE_MS", options.maxActiveMs);
15344
+ if (options.state == null) append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
13412
15345
  append(args, "STATE", options.state);
13413
15346
  appendPolicyMode(args, options.state, options.mode);
13414
15347
  if (options.retry != null) {
13415
15348
  appendRetryPolicy(args, options.retry);
13416
15349
  }
15350
+ if (options.state != null) append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
13417
15351
  for (const [state, policy] of Object.entries(options.states ?? {})) {
13418
15352
  args.push("STATE", state);
13419
15353
  appendFlowStatePolicy(args, policy);
13420
15354
  }
13421
- append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
13422
- return await this.commandArgs(args);
15355
+ return flowPolicySnapshotFromResp(await this.commandArgs(args));
13423
15356
  }
13424
15357
  async policyGet(type, options = {}) {
13425
15358
  const args = ["FLOW.POLICY.GET", type];
13426
15359
  append(args, "STATE", options.state);
13427
- return parseKvResponse(await this.commandArgs(args));
15360
+ return flowPolicySnapshotFromResp(await this.commandArgs(args));
13428
15361
  }
13429
15362
  async retentionCleanup() {
13430
15363
  return parseKvResponse(await this.command("FLOW.RETENTION_CLEANUP"));
@@ -13446,16 +15379,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13446
15379
  }
13447
15380
  return record;
13448
15381
  }
13449
- records(values) {
13450
- const records = new Array(values.length);
13451
- for (let index = 0; index < values.length; index += 1) {
13452
- if (!Object.hasOwn(values, index)) {
13453
- throw new TypeError(`Flow record response item ${index} is missing`);
13454
- }
13455
- records[index] = flowRecordFromResp(values[index], this.codec);
13456
- }
13457
- return records;
13458
- }
13459
15382
  recordsOrResponse(value) {
13460
15383
  if (Array.isArray(value) && value.every(isRecordLike)) {
13461
15384
  return this.records(value);
@@ -13485,12 +15408,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13485
15408
  }
13486
15409
  return results;
13487
15410
  }
13488
- async indexQuery(command, key, options) {
13489
- const args = [command, key];
13490
- appendReadOptions(args, options);
13491
- const response = await this.commandArgs(args);
13492
- return this.records(requiredArrayResponse(response, command));
13493
- }
13494
15411
  appendPartitionOptions(args, options) {
13495
15412
  if (options.partitionKey != null && options.partitionKeys != null) {
13496
15413
  throw new Error("partitionKey and partitionKeys are mutually exclusive");
@@ -13513,7 +15430,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13513
15430
  };
13514
15431
 
13515
15432
  // src/flow-many-snapshot.ts
13516
- import { Buffer as Buffer41 } from "buffer";
15433
+ import { Buffer as Buffer53 } from "buffer";
13517
15434
  var encodedOptionFields = ["error", "payload", "reason", "result"];
13518
15435
  function snapshotCreateItem(item, codec) {
13519
15436
  const snapshot = {
@@ -13531,9 +15448,9 @@ function snapshotCreateItem(item, codec) {
13531
15448
  function snapshotFlowManyOptions(options, codec) {
13532
15449
  const snapshot = { ...options };
13533
15450
  const mutable = snapshot;
13534
- for (const field2 of encodedOptionFields) {
13535
- const value = options[field2];
13536
- if (value != null) mutable[field2] = snapshotFlowValue(codec, value);
15451
+ for (const field3 of encodedOptionFields) {
15452
+ const value = options[field3];
15453
+ if (value != null) mutable[field3] = snapshotFlowValue(codec, value);
13537
15454
  }
13538
15455
  if (options.attributes != null) mutable.attributes = snapshotCommandRecord(options.attributes);
13539
15456
  if (options.attributesMerge != null) {
@@ -13553,7 +15470,7 @@ function snapshotFlowManyOptions(options, codec) {
13553
15470
  }
13554
15471
  function snapshotClaimedItem(item) {
13555
15472
  const wire = item[CLAIMED_ITEM_WIRE];
13556
- const leaseToken = Buffer41.from(wire?.leaseToken ?? item.leaseToken);
15473
+ const leaseToken = Buffer53.from(wire?.leaseToken ?? item.leaseToken);
13557
15474
  const snapshot = {
13558
15475
  ...item,
13559
15476
  fencingToken: wire?.fencingToken ?? item.fencingToken,
@@ -13570,15 +15487,15 @@ function snapshotClaimedItem(item) {
13570
15487
  function snapshotFencedItem(item) {
13571
15488
  return Object.freeze({
13572
15489
  ...item,
13573
- ...item.leaseToken == null ? {} : { leaseToken: Buffer41.from(item.leaseToken) }
15490
+ ...item.leaseToken == null ? {} : { leaseToken: Buffer53.from(item.leaseToken) }
13574
15491
  });
13575
15492
  }
13576
15493
  function snapshotClaimedItemWire(wire, leaseToken) {
13577
15494
  return Object.freeze({
13578
15495
  fencingToken: wire.fencingToken,
13579
- id: Buffer41.from(wire.id),
15496
+ id: Buffer53.from(wire.id),
13580
15497
  leaseToken,
13581
- partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer41.from(wire.partitionKey)
15498
+ partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer53.from(wire.partitionKey)
13582
15499
  });
13583
15500
  }
13584
15501
  function snapshotArray(values) {
@@ -13589,7 +15506,7 @@ function snapshotArray(values) {
13589
15506
  return Object.freeze(snapshot);
13590
15507
  }
13591
15508
  function snapshotStateMeta(stateMeta) {
13592
- return snapshotRecord(stateMeta, (value) => Buffer41.isBuffer(value) ? Buffer41.from(value) : value);
15509
+ return snapshotRecord(stateMeta, (value) => Buffer53.isBuffer(value) ? Buffer53.from(value) : value);
13593
15510
  }
13594
15511
  function snapshotCommandRecord(values) {
13595
15512
  const seen = /* @__PURE__ */ new WeakMap();
@@ -13607,7 +15524,7 @@ function snapshotRecord(values, capture) {
13607
15524
  }
13608
15525
  function snapshotCommandArgument(value, seen) {
13609
15526
  if (typeof value !== "object" || value == null) return value;
13610
- if (Buffer41.isBuffer(value) || value instanceof Uint8Array) return Buffer41.from(value);
15527
+ if (Buffer53.isBuffer(value) || value instanceof Uint8Array) return Buffer53.from(value);
13611
15528
  const objectValue = value;
13612
15529
  const existing = seen.get(objectValue);
13613
15530
  if (existing != null) return existing;
@@ -14594,6 +16511,142 @@ function nativeOptionsForBootstrap(options, signal) {
14594
16511
  };
14595
16512
  }
14596
16513
 
16514
+ // src/flow-query-projection.ts
16515
+ import { Buffer as Buffer54 } from "buffer";
16516
+ var MAX_PROJECTION_FIELDS = 32;
16517
+ var MAX_DYNAMIC_NAME_BYTES = 64;
16518
+ var FIELD_BRAND = /* @__PURE__ */ Symbol("FerricStoreFlowProjectionField");
16519
+ function field2(source, selector) {
16520
+ return Object.freeze({ source, selector, [FIELD_BRAND]: true });
16521
+ }
16522
+ var run = Object.freeze({
16523
+ id: field2("runs", "run_id"),
16524
+ type: field2("runs", "type"),
16525
+ state: field2("runs", "state"),
16526
+ version: field2("runs", "version"),
16527
+ priority: field2("runs", "priority"),
16528
+ partitionKey: field2("runs", "partition_key"),
16529
+ createdAtMs: field2("runs", "created_at_ms"),
16530
+ updatedAtMs: field2("runs", "updated_at_ms"),
16531
+ nextRunAtMs: field2("runs", "next_run_at_ms"),
16532
+ leaseDeadlineMs: field2("runs", "lease_deadline_ms"),
16533
+ attempts: field2("runs", "attempts"),
16534
+ runState: field2("runs", "run_state"),
16535
+ maxActiveMs: field2("runs", "max_active_ms"),
16536
+ parentFlowId: field2("runs", "parent_flow_id"),
16537
+ rootFlowId: field2("runs", "root_flow_id"),
16538
+ correlationId: field2("runs", "correlation_id"),
16539
+ attributes: field2("runs", "attributes"),
16540
+ stateMetadata: field2("runs", "state_meta"),
16541
+ attribute(name) {
16542
+ return field2("runs", `attribute[${quoteName(name, false)}]`);
16543
+ },
16544
+ stateMeta(state, name) {
16545
+ return field2(
16546
+ "runs",
16547
+ `state_meta[${quoteName(state, true)}][${quoteName(name, false)}]`
16548
+ );
16549
+ }
16550
+ });
16551
+ var event = Object.freeze({
16552
+ id: field2("events", "event_id"),
16553
+ fields: field2("events", "fields"),
16554
+ field(name) {
16555
+ return field2("events", `fields[${quoteName(name, false)}]`);
16556
+ }
16557
+ });
16558
+ var FlowProjection = Object.freeze({ run, event });
16559
+ function projectFlowQuery(query, shape, ...fields) {
16560
+ validateFlowQueryText(query);
16561
+ if (shape !== "record" && shape !== "records") {
16562
+ throw new TypeError("Flow query projection shape must be record or records");
16563
+ }
16564
+ if (fields.length === 0 || fields.length > MAX_PROJECTION_FIELDS) {
16565
+ throw new TypeError(
16566
+ `Flow query projection must contain 1..${MAX_PROJECTION_FIELDS} fields`
16567
+ );
16568
+ }
16569
+ if (!fields.every((item) => item?.[FIELD_BRAND])) {
16570
+ throw new TypeError("Flow query projection accepts only FlowProjection fields");
16571
+ }
16572
+ const source = querySource(query);
16573
+ if (fields.some((item) => item.source !== source)) {
16574
+ throw new TypeError(`Flow query projection fields must belong to ${source}`);
16575
+ }
16576
+ const selectors = fields.map((item) => item.selector);
16577
+ if (new Set(selectors).size !== selectors.length) {
16578
+ throw new TypeError("Flow query projection contains a duplicate field");
16579
+ }
16580
+ if (containsReturnKeyword(query)) {
16581
+ throw new TypeError("Flow query already contains a RETURN clause");
16582
+ }
16583
+ const trimmed = query.trim();
16584
+ const base = trimmed.endsWith(";") ? trimmed.slice(0, -1).trimEnd() : trimmed;
16585
+ const result = `${base} RETURN ${shape.toUpperCase()} (${selectors.join(", ")})`;
16586
+ if (Buffer54.byteLength(result, "utf8") > FLOW_QUERY_MAX_BYTES) {
16587
+ throw new TypeError(`FLOW.QUERY query exceeds ${FLOW_QUERY_MAX_BYTES} bytes`);
16588
+ }
16589
+ return result;
16590
+ }
16591
+ function querySource(query) {
16592
+ const match = /^\s*FROM\s+(runs|events)\b/iu.exec(query);
16593
+ if (match?.[1] == null) {
16594
+ throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
16595
+ }
16596
+ return match[1].toLowerCase();
16597
+ }
16598
+ function containsReturnKeyword(query) {
16599
+ let quoted = false;
16600
+ for (let index = 0; index < query.length; ) {
16601
+ const character = query.charAt(index);
16602
+ if (character === "'") {
16603
+ if (quoted && query[index + 1] === "'") {
16604
+ index += 2;
16605
+ continue;
16606
+ }
16607
+ quoted = !quoted;
16608
+ index += 1;
16609
+ continue;
16610
+ }
16611
+ if (!quoted && /[A-Za-z_]/u.test(character)) {
16612
+ let end = index + 1;
16613
+ while (end < query.length && /[A-Za-z0-9_]/u.test(query.charAt(end))) end += 1;
16614
+ if (query.slice(index, end).toUpperCase() === "RETURN") return true;
16615
+ index = end;
16616
+ continue;
16617
+ }
16618
+ index += 1;
16619
+ }
16620
+ return false;
16621
+ }
16622
+ function quoteName(value, allowPrivate) {
16623
+ if (typeof value !== "string") {
16624
+ throw new TypeError("Flow query projection metadata name must be text");
16625
+ }
16626
+ validateUnicodeScalarText2(value);
16627
+ const size = Buffer54.byteLength(value, "utf8");
16628
+ if (size === 0 || size > MAX_DYNAMIC_NAME_BYTES || !allowPrivate && value.startsWith("__")) {
16629
+ throw new TypeError(
16630
+ `Flow query projection metadata names must be 1..${MAX_DYNAMIC_NAME_BYTES} UTF-8 bytes`
16631
+ );
16632
+ }
16633
+ return `'${value.replaceAll("'", "''")}'`;
16634
+ }
16635
+ function validateUnicodeScalarText2(value) {
16636
+ for (let index = 0; index < value.length; index += 1) {
16637
+ const code = value.charCodeAt(index);
16638
+ if (code >= 55296 && code <= 56319) {
16639
+ const low = value.charCodeAt(index + 1);
16640
+ if (!(low >= 56320 && low <= 57343)) {
16641
+ throw new TypeError("Flow query projection metadata name must be valid UTF-8");
16642
+ }
16643
+ index += 1;
16644
+ } else if (code >= 56320 && code <= 57343) {
16645
+ throw new TypeError("Flow query projection metadata name must be valid UTF-8");
16646
+ }
16647
+ }
16648
+ }
16649
+
14597
16650
  // src/outcomes.ts
14598
16651
  var OUTCOME_BRAND = /* @__PURE__ */ Symbol("ferricstore.outcome");
14599
16652
  function transition(toState, options = {}) {
@@ -14673,7 +16726,7 @@ var LeaseRenewalGuard = class {
14673
16726
  if (options.leaseRenewal === false) {
14674
16727
  return;
14675
16728
  }
14676
- const intervalMs = positiveInteger(options.leaseRenewIntervalMs, Math.max(1, Math.trunc(leaseMs / 2)));
16729
+ const intervalMs = positiveInteger2(options.leaseRenewIntervalMs, Math.max(1, Math.trunc(leaseMs / 2)));
14677
16730
  this.timer = setLongInterval(() => this.renew(), intervalMs);
14678
16731
  this.timer.unref();
14679
16732
  }
@@ -14745,7 +16798,7 @@ function snapshotLeasedJob(job) {
14745
16798
  return snapshot;
14746
16799
  }
14747
16800
  function workerConcurrency(options) {
14748
- return positiveInteger(options.concurrency ?? options.workers, 1);
16801
+ return positiveInteger2(options.concurrency ?? options.workers, 1);
14749
16802
  }
14750
16803
  function workerRefillStrategy(options) {
14751
16804
  return options.refillStrategy === "wave" ? "wave" : "continuous";
@@ -14788,18 +16841,18 @@ function workerErrorPayload(error, options, codec) {
14788
16841
  }
14789
16842
  function workerBatchSize(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
14790
16843
  return Math.min(
14791
- positiveInteger(options.batchSize, 10),
14792
- positiveInteger(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
16844
+ positiveInteger2(options.batchSize, 10),
16845
+ positiveInteger2(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
14793
16846
  );
14794
16847
  }
14795
16848
  function workerClaimLimit(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
14796
16849
  return Math.min(workerBatchSize(options, flowManyBatchLimit), workerConcurrency(options));
14797
16850
  }
14798
16851
  function workerDrainBatches(options) {
14799
- return positiveInteger(options.claimDrainBatches, 1);
16852
+ return positiveInteger2(options.claimDrainBatches, 1);
14800
16853
  }
14801
16854
  function workerLeaseMs(options, fallback = 3e4) {
14802
- return positiveInteger(options.leaseMs, positiveInteger(fallback, 3e4));
16855
+ return positiveInteger2(options.leaseMs, positiveInteger2(fallback, 3e4));
14803
16856
  }
14804
16857
  function workerIdleSleepMs(options) {
14805
16858
  return nonNegativeDuration(options.idleSleepMs, 250);
@@ -14811,7 +16864,7 @@ function workerClaimBlockMs(options, useBlocking) {
14811
16864
  if (options.signal == null || !Number.isFinite(options.blockMs) || options.blockMs < 0) {
14812
16865
  return options.blockMs;
14813
16866
  }
14814
- const abortPollMs = positiveInteger(options.abortPollMs, 1e3);
16867
+ const abortPollMs = positiveInteger2(options.abortPollMs, 1e3);
14815
16868
  return options.blockMs === 0 ? abortPollMs : Math.min(Math.trunc(options.blockMs), abortPollMs);
14816
16869
  }
14817
16870
  function workerMaxIdleSleepMs(options, idleSleepMs = workerIdleSleepMs(options)) {
@@ -14822,14 +16875,14 @@ function nextWorkerIdleSleepMs(currentIdleSleepMs, maxIdleSleepMs) {
14822
16875
  return Math.min(maxIdleSleepMs, Math.max(1, currentIdleSleepMs * 2));
14823
16876
  }
14824
16877
  async function runContinuousWorkerPool(options) {
14825
- const concurrency = positiveInteger(options.concurrency, 1);
14826
- const maxClaimSize = positiveInteger(options.maxClaimSize, concurrency);
16878
+ const concurrency = positiveInteger2(options.concurrency, 1);
16879
+ const maxClaimSize = positiveInteger2(options.maxClaimSize, concurrency);
14827
16880
  const initialIdleSleepMs = nonNegativeDuration(options.idleSleepMs, 250);
14828
16881
  const maxIdleSleepMs = Math.max(
14829
16882
  initialIdleSleepMs,
14830
16883
  nonNegativeDuration(options.maxIdleSleepMs, 5e3)
14831
16884
  );
14832
- const refillDelayMs = nonNegativeInteger(options.refillDelayMs, 0);
16885
+ const refillDelayMs = nonNegativeInteger3(options.refillDelayMs, 0);
14833
16886
  const active = /* @__PURE__ */ new Set();
14834
16887
  const pending = [];
14835
16888
  let pendingIndex = 0;
@@ -14945,10 +16998,10 @@ function normalizeWorkflowWorkerConfig(options) {
14945
16998
  ...captured
14946
16999
  });
14947
17000
  }
14948
- function positiveInteger(value, fallback) {
17001
+ function positiveInteger2(value, fallback) {
14949
17002
  return value == null || !Number.isFinite(value) ? fallback : Math.max(1, Math.trunc(value));
14950
17003
  }
14951
- function nonNegativeInteger(value, fallback) {
17004
+ function nonNegativeInteger3(value, fallback) {
14952
17005
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, Math.trunc(value));
14953
17006
  }
14954
17007
  function nonNegativeDuration(value, fallback) {
@@ -16364,6 +18417,7 @@ var Workflow = class {
16364
18417
  }
16365
18418
  return await this.client.installPolicy(this.type, {
16366
18419
  ...options,
18420
+ replace: Object.hasOwn(options, "replace") ? options.replace ?? true : true,
16367
18421
  states
16368
18422
  });
16369
18423
  }
@@ -16576,8 +18630,8 @@ var WorkflowWorker = class {
16576
18630
  };
16577
18631
 
16578
18632
  // src/version.ts
16579
- var FERRICSTORE_SDK_VERSION = "0.2.0";
16580
- var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.8.0";
18633
+ var FERRICSTORE_SDK_VERSION = "0.5.0";
18634
+ var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.0";
16581
18635
  var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16582
18636
  export {
16583
18637
  BitmapStore,
@@ -16595,6 +18649,8 @@ export {
16595
18649
  FlowAlreadyExistsError,
16596
18650
  FlowBatchError,
16597
18651
  FlowNotFoundError,
18652
+ FlowProjection,
18653
+ FlowQueryError,
16598
18654
  FlowWrongStateError,
16599
18655
  GeoStore,
16600
18656
  HashStore,
@@ -16606,6 +18662,7 @@ export {
16606
18662
  ListStore,
16607
18663
  LockHeldError,
16608
18664
  LockNotOwnedError,
18665
+ MAX_FLOW_POLICY_GENERATION,
16609
18666
  NativeAdapter,
16610
18667
  OverloadedError,
16611
18668
  Queue,
@@ -16620,6 +18677,7 @@ export {
16620
18677
  SetStore,
16621
18678
  SortedSetStore,
16622
18679
  StaleLeaseError,
18680
+ StalePolicyGenerationError,
16623
18681
  StreamStore,
16624
18682
  TDigestStore,
16625
18683
  TopKStore,
@@ -16635,6 +18693,7 @@ export {
16635
18693
  isOutcome,
16636
18694
  isReconnectableClosedConnectionError,
16637
18695
  mapException,
18696
+ projectFlowQuery,
16638
18697
  retry,
16639
18698
  transition
16640
18699
  };