@ferricstore/ferricstore 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +59 -6
  2. package/dist/index.cjs +2273 -600
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +193 -30
  5. package/dist/index.d.ts +193 -30
  6. package/dist/index.js +2275 -605
  7. package/dist/index.js.map +1 -1
  8. package/docs/api/assets/hierarchy.js +1 -1
  9. package/docs/api/assets/navigation.js +1 -1
  10. package/docs/api/assets/search.js +1 -1
  11. package/docs/api/classes/ClaimHydrationError.html +4 -4
  12. package/docs/api/classes/ConnectionClosedError.html +5 -5
  13. package/docs/api/classes/FerricStoreClient.html +6 -2
  14. package/docs/api/classes/FerricStoreError.html +5 -5
  15. package/docs/api/classes/FlowAlreadyExistsError.html +5 -5
  16. package/docs/api/classes/FlowBatchError.html +5 -5
  17. package/docs/api/classes/FlowNotFoundError.html +5 -5
  18. package/docs/api/classes/FlowQueryError.html +42 -0
  19. package/docs/api/classes/FlowWrongStateError.html +5 -5
  20. package/docs/api/classes/InvalidCommandError.html +5 -5
  21. package/docs/api/classes/LeaseRenewalError.html +5 -5
  22. package/docs/api/classes/LockHeldError.html +5 -5
  23. package/docs/api/classes/LockNotOwnedError.html +5 -5
  24. package/docs/api/classes/NativeAdapter.html +3 -3
  25. package/docs/api/classes/OverloadedError.html +5 -5
  26. package/docs/api/classes/QueueCompletionError.html +5 -5
  27. package/docs/api/classes/RequestTimeoutError.html +5 -5
  28. package/docs/api/classes/RerouteError.html +5 -5
  29. package/docs/api/classes/StaleLeaseError.html +5 -5
  30. package/docs/api/classes/StalePolicyGenerationError.html +5 -5
  31. package/docs/api/functions/projectFlowQuery.html +1 -0
  32. package/docs/api/hierarchy.html +1 -1
  33. package/docs/api/index.html +35 -7
  34. package/docs/api/interfaces/AdminListOptions.html +1 -1
  35. package/docs/api/interfaces/CancelOptions.html +1 -1
  36. package/docs/api/interfaces/CompleteOptions.html +1 -1
  37. package/docs/api/interfaces/CompleteOutcome.html +1 -1
  38. package/docs/api/interfaces/CreateManyOptions.html +1 -1
  39. package/docs/api/interfaces/EffectCompensateOptions.html +1 -1
  40. package/docs/api/interfaces/EffectConfirmOptions.html +1 -1
  41. package/docs/api/interfaces/EffectFailOptions.html +1 -1
  42. package/docs/api/interfaces/EffectStatusOptions.html +1 -1
  43. package/docs/api/interfaces/FailOptions.html +1 -1
  44. package/docs/api/interfaces/FailOutcome.html +1 -1
  45. package/docs/api/interfaces/FerricStoreClientFromUrlOptions.html +1 -1
  46. package/docs/api/interfaces/FerricStoreClientOptions.html +1 -1
  47. package/docs/api/interfaces/FlowEventProjectionField.html +4 -0
  48. package/docs/api/interfaces/FlowExplainResult.html +10 -0
  49. package/docs/api/interfaces/FlowPolicyOptions.html +1 -1
  50. package/docs/api/interfaces/FlowQueryCountResult.html +7 -0
  51. package/docs/api/interfaces/FlowQueryErrorPosition.html +4 -0
  52. package/docs/api/interfaces/FlowQueryIndex.html +9 -0
  53. package/docs/api/interfaces/FlowQueryIndexFormat.html +7 -0
  54. package/docs/api/interfaces/FlowQueryIndexRegistry.html +3 -0
  55. package/docs/api/interfaces/FlowQueryIndexStatus.html +8 -0
  56. package/docs/api/interfaces/FlowQueryPage.html +3 -0
  57. package/docs/api/interfaces/FlowQueryQuality.html +5 -0
  58. package/docs/api/interfaces/FlowQueryRecordsResult.html +8 -0
  59. package/docs/api/interfaces/FlowQueryUsage.html +12 -0
  60. package/docs/api/interfaces/FlowRunProjectionField.html +4 -0
  61. package/docs/api/interfaces/HistoryOptions.html +2 -2
  62. package/docs/api/interfaces/InvocationCreateOptions.html +1 -1
  63. package/docs/api/interfaces/LeaseMutationOptions.html +1 -1
  64. package/docs/api/interfaces/LimitListOptions.html +1 -1
  65. package/docs/api/interfaces/MutateOptions.html +1 -1
  66. package/docs/api/interfaces/NamedValueMutation.html +1 -1
  67. package/docs/api/interfaces/ProtocolCommand.html +2 -2
  68. package/docs/api/interfaces/ReadOptions.html +5 -3
  69. package/docs/api/interfaces/ReclaimOptions.html +1 -1
  70. package/docs/api/interfaces/RequestContextOptions.html +1 -1
  71. package/docs/api/interfaces/RetryOptions.html +1 -1
  72. package/docs/api/interfaces/RetryOutcome.html +1 -1
  73. package/docs/api/interfaces/SearchOptions.html +4 -3
  74. package/docs/api/interfaces/StepContinueOptions.html +1 -1
  75. package/docs/api/interfaces/TDigestCreateOptions.html +1 -1
  76. package/docs/api/interfaces/TDigestMergeOptions.html +1 -1
  77. package/docs/api/interfaces/TransitionOptions.html +1 -1
  78. package/docs/api/interfaces/TransitionOutcome.html +1 -1
  79. package/docs/api/modules.html +1 -1
  80. package/docs/api/types/ConnectionRequestDisposition.html +1 -1
  81. package/docs/api/types/FlowProjectionField.html +1 -0
  82. package/docs/api/types/FlowProjectionShape.html +1 -0
  83. package/docs/api/types/FlowQueryInteger.html +1 -0
  84. package/docs/api/types/FlowQueryParameter.html +1 -0
  85. package/docs/api/types/FlowQueryParameters.html +1 -0
  86. package/docs/api/types/FlowQueryRecord.html +1 -0
  87. package/docs/api/types/FlowQueryResult.html +1 -0
  88. package/docs/api/types/ManagementPairs.html +1 -1
  89. package/docs/api/types/SearchStateMeta.html +1 -1
  90. package/docs/api/variables/COMMAND_OPCODES.html +1 -1
  91. package/docs/api/variables/FERRICSTORE_MINIMUM_SERVER_VERSION.html +1 -1
  92. package/docs/api/variables/FERRICSTORE_NATIVE_PROTOCOL_VERSION.html +1 -1
  93. package/docs/api/variables/FERRICSTORE_SDK_VERSION.html +1 -1
  94. package/docs/api/variables/FlowProjection.html +1 -0
  95. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -1182,10 +1182,151 @@ var NativeHeartbeat = class {
1182
1182
  };
1183
1183
 
1184
1184
  // src/protocol.ts
1185
- import { Buffer as Buffer23 } from "buffer";
1185
+ import { Buffer as Buffer27 } from "buffer";
1186
1186
 
1187
- // src/command-grammar.ts
1187
+ // src/flow-query-request.ts
1188
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";
1189
1330
 
1190
1331
  // src/command-metadata-flow.ts
1191
1332
  var flowStateIdCommands = /* @__PURE__ */ new Set([
@@ -1576,20 +1717,15 @@ var typeScopedFlowCommands = /* @__PURE__ */ new Set([
1576
1717
  "FLOW.ATTRIBUTE_VALUES",
1577
1718
  "FLOW.ATTRIBUTES",
1578
1719
  "FLOW.BUDGET.LIST",
1579
- "FLOW.FAILURES",
1580
1720
  "FLOW.GOVERNANCE.OVERVIEW",
1581
1721
  "FLOW.INFO",
1582
1722
  "FLOW.LIMIT.LIST",
1583
- "FLOW.LIST",
1584
1723
  "FLOW.POLICY.GET",
1585
1724
  "FLOW.POLICY.SET",
1586
1725
  "FLOW.RETENTION_CLEANUP",
1587
1726
  "FLOW.SCHEDULE.FIRE_DUE",
1588
1727
  "FLOW.SCHEDULE.LIST",
1589
- "FLOW.SEARCH",
1590
- "FLOW.STATS",
1591
- "FLOW.STUCK",
1592
- "FLOW.TERMINALS"
1728
+ "FLOW.STATS"
1593
1729
  ]);
1594
1730
  var flowScheduleCommands = /* @__PURE__ */ new Set([
1595
1731
  "FLOW.SCHEDULE.CREATE",
@@ -1632,8 +1768,8 @@ var secondKeySubcommands = /* @__PURE__ */ new Map([
1632
1768
  ]);
1633
1769
  function commandToken(value) {
1634
1770
  if (typeof value === "string") return value.toUpperCase();
1635
- if (Buffer4.isBuffer(value) || value instanceof Uint8Array) {
1636
- return Buffer4.from(value).toString("utf8").toUpperCase();
1771
+ if (Buffer5.isBuffer(value) || value instanceof Uint8Array) {
1772
+ return Buffer5.from(value).toString("utf8").toUpperCase();
1637
1773
  }
1638
1774
  return void 0;
1639
1775
  }
@@ -1736,7 +1872,7 @@ function safeIntegerArgument(value) {
1736
1872
  if (typeof value === "bigint") {
1737
1873
  return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
1738
1874
  }
1739
- 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;
1740
1876
  if (source == null || !/^[+-]?\d+$/u.test(source)) return void 0;
1741
1877
  const parsed = BigInt(source);
1742
1878
  return parsed >= BigInt(Number.MIN_SAFE_INTEGER) && parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : void 0;
@@ -1789,7 +1925,7 @@ function hasOwnCommandArgument(args, index, end, section) {
1789
1925
  }
1790
1926
 
1791
1927
  // src/protocol-core.ts
1792
- import { Buffer as Buffer8 } from "buffer";
1928
+ import { Buffer as Buffer9 } from "buffer";
1793
1929
 
1794
1930
  // src/protocol-constants.ts
1795
1931
  import "buffer";
@@ -1887,7 +2023,6 @@ var COMMAND_OPCODES = {
1887
2023
  "FLOW.VALUE.PUT": 523,
1888
2024
  "FLOW.VALUE.MGET": 524,
1889
2025
  "FLOW.SIGNAL": 525,
1890
- "FLOW.LIST": 526,
1891
2026
  "FLOW.CREATE_MANY": 527,
1892
2027
  "FLOW.COMPLETE_MANY": 528,
1893
2028
  "FLOW.TRANSITION_MANY": 529,
@@ -1896,13 +2031,7 @@ var COMMAND_OPCODES = {
1896
2031
  "FLOW.CANCEL_MANY": 532,
1897
2032
  "FLOW.RECLAIM": 533,
1898
2033
  "FLOW.REWIND": 534,
1899
- "FLOW.TERMINALS": 535,
1900
- "FLOW.FAILURES": 536,
1901
- "FLOW.BY_PARENT": 537,
1902
- "FLOW.BY_ROOT": 538,
1903
- "FLOW.BY_CORRELATION": 539,
1904
2034
  "FLOW.INFO": 540,
1905
- "FLOW.STUCK": 541,
1906
2035
  "FLOW.POLICY.SET": 542,
1907
2036
  "FLOW.POLICY.GET": 543,
1908
2037
  "FLOW.SPAWN_CHILDREN": 544,
@@ -1921,7 +2050,7 @@ var COMMAND_OPCODES = {
1921
2050
  "FLOW.STATS": 557,
1922
2051
  "FLOW.ATTRIBUTES": 558,
1923
2052
  "FLOW.ATTRIBUTE_VALUES": 559,
1924
- "FLOW.SEARCH": 560,
2053
+ "FLOW.QUERY": 561,
1925
2054
  "FLOW.EFFECT.RESERVE": 576,
1926
2055
  "FLOW.EFFECT.CONFIRM": 577,
1927
2056
  "FLOW.EFFECT.FAIL": 578,
@@ -2010,7 +2139,7 @@ var OPCODES = {
2010
2139
  flowStepContinue: COMMAND_OPCODES["FLOW.STEP_CONTINUE"],
2011
2140
  flowStartAndClaim: COMMAND_OPCODES["FLOW.START_AND_CLAIM"],
2012
2141
  flowRunStepsMany: COMMAND_OPCODES["FLOW.RUN_STEPS_MANY"],
2013
- flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
2142
+ flowQuery: COMMAND_OPCODES["FLOW.QUERY"]
2014
2143
  };
2015
2144
  var COMPACT_FLOW_CLAIM_JOBS = 128;
2016
2145
  var COMPACT_OK_LIST = 129;
@@ -2037,11 +2166,12 @@ var COMPACT_FLOW_TRANSITION_MANY_REQUEST = 155;
2037
2166
  var COMPACT_FLOW_TRANSITION_MANY_OK_REQUEST = 156;
2038
2167
  var COMPACT_FLOW_VALUE_MGET_REQUEST = 157;
2039
2168
  var COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST = 158;
2040
- var COMPACT_FLOW_LIST_REQUEST = 159;
2169
+ var COMPACT_FLOW_QUERY_RESULT = 160;
2041
2170
  var COMPACT_PIPELINE_DECODED = /* @__PURE__ */ Symbol("ferricstore.compactPipelineDecoded");
2042
2171
  var NULL_U32 = 4294967295;
2043
- var MIN_I64 = -9223372036854775808n;
2044
- var MAX_I64 = 9223372036854775807n;
2172
+ var MIN_I642 = -9223372036854775808n;
2173
+ var MAX_I642 = 9223372036854775807n;
2174
+ var MAX_U64 = 18446744073709551615n;
2045
2175
  var MAX_SAFE_INTEGER_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
2046
2176
  var MIN_SAFE_INTEGER_BIGINT = BigInt(Number.MIN_SAFE_INTEGER);
2047
2177
  var FLOW_RECORD_FIELD_KEYS = [
@@ -2090,16 +2220,16 @@ var FLOW_RECORD_FIELD_KEYS = [
2090
2220
  ];
2091
2221
 
2092
2222
  // src/protocol-text.ts
2093
- import { Buffer as Buffer6 } from "buffer";
2223
+ import { Buffer as Buffer7 } from "buffer";
2094
2224
  function toBuffer(value) {
2095
- if (Buffer6.isBuffer(value)) return value;
2096
- if (value instanceof Uint8Array) return Buffer6.from(value);
2097
- 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);
2098
2228
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2099
- return Buffer6.from(String(value));
2229
+ return Buffer7.from(String(value));
2100
2230
  }
2101
- if (typeof value === "symbol") return Buffer6.from(value.description ?? value.toString());
2102
- 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);
2103
2233
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2104
2234
  }
2105
2235
  function asText(value) {
@@ -2107,14 +2237,14 @@ function asText(value) {
2107
2237
  }
2108
2238
  function optionalText(value) {
2109
2239
  if (value == null || value === "") return void 0;
2110
- 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) {
2111
2241
  return asText(value);
2112
2242
  }
2113
2243
  return void 0;
2114
2244
  }
2115
2245
  function commandTokenIs(value, expected) {
2116
2246
  if (typeof value === "string") return value.toUpperCase() === expected;
2117
- if (Buffer6.isBuffer(value) || value instanceof Uint8Array) {
2247
+ if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2118
2248
  return asText(value).toUpperCase() === expected;
2119
2249
  }
2120
2250
  return false;
@@ -2128,7 +2258,7 @@ function commandNameIs(value, expected) {
2128
2258
  }
2129
2259
 
2130
2260
  // src/request-context.ts
2131
- import { Buffer as Buffer7 } from "buffer";
2261
+ import { Buffer as Buffer8 } from "buffer";
2132
2262
  var requestContextCommands = /* @__PURE__ */ new Set([
2133
2263
  "INVOCATION.CREATE",
2134
2264
  "INVOCATION.DEFINITION.GET",
@@ -2183,9 +2313,9 @@ function requestContextCommandToken(value) {
2183
2313
  const upper = value.toUpperCase();
2184
2314
  return isRequestContextCommand(upper) ? upper : void 0;
2185
2315
  }
2186
- if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2316
+ if (Buffer8.isBuffer(value) || value instanceof Uint8Array) {
2187
2317
  if (value[0] !== 73 && value[0] !== 105) return void 0;
2188
- const command = Buffer7.from(value).toString("utf8").toUpperCase();
2318
+ const command = Buffer8.from(value).toString("utf8").toUpperCase();
2189
2319
  return isRequestContextCommand(command) ? command : void 0;
2190
2320
  }
2191
2321
  return void 0;
@@ -2216,12 +2346,12 @@ function requestContextText(context, fieldName) {
2216
2346
  return value;
2217
2347
  }
2218
2348
  function isPlainObject(value) {
2219
- 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);
2220
2350
  }
2221
2351
  function commandToken2(value) {
2222
2352
  if (typeof value === "string") return value.toUpperCase();
2223
- if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2224
- return Buffer7.from(value).toString("utf8").toUpperCase();
2353
+ if (Buffer8.isBuffer(value) || value instanceof Uint8Array) {
2354
+ return Buffer8.from(value).toString("utf8").toUpperCase();
2225
2355
  }
2226
2356
  return "";
2227
2357
  }
@@ -2311,17 +2441,17 @@ function requestFrameTooLarge(maxBytes) {
2311
2441
  );
2312
2442
  }
2313
2443
  function binaryValueByteLength(value) {
2314
- if (Buffer8.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2315
- 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);
2316
2446
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2317
- return Buffer8.byteLength(String(value));
2447
+ return Buffer9.byteLength(String(value));
2318
2448
  }
2319
- if (typeof value === "symbol") return Buffer8.byteLength(value.description ?? value.toString());
2449
+ if (typeof value === "symbol") return Buffer9.byteLength(value.description ?? value.toString());
2320
2450
  if (value == null) return 0;
2321
2451
  return toBuffer(value).byteLength;
2322
2452
  }
2323
2453
  function writeCustomPayload(output, offset, value, knownByteLength) {
2324
- if (Buffer8.isBuffer(value)) {
2454
+ if (Buffer9.isBuffer(value)) {
2325
2455
  value.copy(output, offset);
2326
2456
  return;
2327
2457
  }
@@ -2340,7 +2470,7 @@ function writeCustomPayload(output, offset, value, knownByteLength) {
2340
2470
  } else {
2341
2471
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2342
2472
  }
2343
- output.write(text3, offset, knownByteLength ?? Buffer8.byteLength(text3), "utf8");
2473
+ output.write(text3, offset, knownByteLength ?? Buffer9.byteLength(text3), "utf8");
2344
2474
  }
2345
2475
  function compactBinaryEncodedLength(value) {
2346
2476
  return 4 + compactBinaryByteLength(value);
@@ -2353,10 +2483,10 @@ function compactBinaryByteLength(value) {
2353
2483
  return byteLength;
2354
2484
  }
2355
2485
  function isCompactBinaryArgument(value) {
2356
- return typeof value === "string" || Buffer8.isBuffer(value) || value instanceof Uint8Array;
2486
+ return typeof value === "string" || Buffer9.isBuffer(value) || value instanceof Uint8Array;
2357
2487
  }
2358
2488
  function isCompactBinaryScalar(value) {
2359
- 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;
2360
2490
  }
2361
2491
  function compactOptionalBinaryEncodedLength(value) {
2362
2492
  return value == null ? 4 : compactBinaryEncodedLength(value);
@@ -2422,7 +2552,7 @@ function integerArg(value) {
2422
2552
  throw new FerricStoreError("integer command argument must be an integer");
2423
2553
  }
2424
2554
  const integer2 = BigInt(source);
2425
- if (integer2 < MIN_I64 || integer2 > MAX_I64) {
2555
+ if (integer2 < MIN_I642 || integer2 > MAX_I642) {
2426
2556
  throw new FerricStoreError("integer command argument exceeds the signed 64-bit range");
2427
2557
  }
2428
2558
  return integer2 >= MIN_SAFE_INTEGER_BIGINT && integer2 <= MAX_SAFE_INTEGER_BIGINT ? Number(integer2) : integer2;
@@ -2453,7 +2583,7 @@ function independentMode(value) {
2453
2583
  return 0;
2454
2584
  }
2455
2585
  function optionalI64(value) {
2456
- return typeof value === "number" ? BigInt(value) : MIN_I64;
2586
+ return typeof value === "number" ? BigInt(value) : MIN_I642;
2457
2587
  }
2458
2588
  function compactClaimReturnMode(value) {
2459
2589
  const mode = value == null ? "" : asText(value).toUpperCase();
@@ -2487,18 +2617,18 @@ function setOwnValue2(target, key, value) {
2487
2617
  }
2488
2618
 
2489
2619
  // src/protocol-flow-options.ts
2490
- import { Buffer as Buffer9 } from "buffer";
2620
+ import { Buffer as Buffer10 } from "buffer";
2491
2621
 
2492
2622
  // src/protocol-flow-option-value.ts
2493
- function setFlowOptionValue(payload, field2, value, repeat) {
2494
- if (!repeat || !Object.hasOwn(payload, field2)) {
2495
- setOwnValue2(payload, field2, value);
2623
+ function setFlowOptionValue(payload, field3, value, repeat) {
2624
+ if (!repeat || !Object.hasOwn(payload, field3)) {
2625
+ setOwnValue2(payload, field3, value);
2496
2626
  return;
2497
2627
  }
2498
- const previous = payload[field2];
2628
+ const previous = payload[field3];
2499
2629
  setOwnValue2(
2500
2630
  payload,
2501
- field2,
2631
+ field3,
2502
2632
  Array.isArray(previous) ? [...previous, value] : [previous, value]
2503
2633
  );
2504
2634
  }
@@ -2541,44 +2671,30 @@ function optionMap(args) {
2541
2671
  index += 3;
2542
2672
  continue;
2543
2673
  }
2544
- const field2 = OPTION_FIELDS[token] ?? token.toLowerCase();
2674
+ const field3 = OPTION_FIELDS[token] ?? token.toLowerCase();
2545
2675
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow options")) {
2546
2676
  throw new FerricStoreError(`${token} requires a value`);
2547
2677
  }
2548
2678
  const value = args[index + 1];
2549
- if (BOOL_OPTION_FIELDS.has(field2) && !isBoolToken(value)) {
2679
+ if (BOOL_OPTION_FIELDS.has(field3) && !isBoolToken(value)) {
2550
2680
  return void 0;
2551
2681
  }
2552
- setOwnValue2(payload, field2, BOOL_OPTION_FIELDS.has(field2) ? boolArg(value) : value);
2682
+ setOwnValue2(payload, field3, BOOL_OPTION_FIELDS.has(field3) ? boolArg(value) : value);
2553
2683
  index += 2;
2554
2684
  }
2555
2685
  return payload;
2556
2686
  }
2557
- function ensureObjectField(payload, field2) {
2558
- const value = payload[field2];
2687
+ function ensureObjectField(payload, field3) {
2688
+ const value = payload[field3];
2559
2689
  if (isPlainObject2(value)) {
2560
2690
  return value;
2561
2691
  }
2562
2692
  const next = {};
2563
- setOwnValue2(payload, field2, next);
2693
+ setOwnValue2(payload, field3, next);
2564
2694
  return next;
2565
2695
  }
2566
- function normalizeFlowSearchStateMeta(payload) {
2567
- const stateMeta = payload.state_meta;
2568
- if (!isPlainObject2(stateMeta) || Object.keys(stateMeta).length === 0) {
2569
- return;
2570
- }
2571
- if (Object.values(stateMeta).every(isPlainObject2)) {
2572
- return;
2573
- }
2574
- const state = payload.state;
2575
- if (state == null) {
2576
- throw new FerricStoreError("FLOW.SEARCH STATE_META filters require STATE or nested state metadata");
2577
- }
2578
- payload.state_meta = { [asText(state)]: stateMeta };
2579
- }
2580
2696
  function isPlainObject2(value) {
2581
- 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);
2582
2698
  }
2583
2699
  function parseFlowOptions(args, start, end, config) {
2584
2700
  const payload = {};
@@ -2672,9 +2788,9 @@ function parseFlowOptions(args, start, end, config) {
2672
2788
  case "TRANSITION_TO":
2673
2789
  case "TO_EVENT":
2674
2790
  case "EXPECT_STATE": {
2675
- const field2 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2791
+ const field3 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2676
2792
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2677
- setFlowOptionValue(payload, field2, args[index + 1], token === "IF_STATE");
2793
+ setFlowOptionValue(payload, field3, args[index + 1], token === "IF_STATE");
2678
2794
  index += 2;
2679
2795
  break;
2680
2796
  }
@@ -2682,8 +2798,8 @@ function parseFlowOptions(args, start, end, config) {
2682
2798
  case "RESULT":
2683
2799
  case "ERROR":
2684
2800
  case "REASON": {
2685
- const field2 = token === "LEASE_TOKEN" ? "lease_token" : token.toLowerCase();
2686
- 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;
2687
2803
  index += 2;
2688
2804
  break;
2689
2805
  }
@@ -2705,8 +2821,8 @@ function parseFlowOptions(args, start, end, config) {
2705
2821
  case "VALUE_REF":
2706
2822
  case "STATE_META": {
2707
2823
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options") || !hasOwnCommandArgument(args, index + 2, end, "Flow options")) return void 0;
2708
- const field2 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "VALUE_REF" ? "value_refs" : "state_meta";
2709
- 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);
2710
2826
  setOwnValue2(values, asText(args[index + 1]), args[index + 2]);
2711
2827
  index += 3;
2712
2828
  break;
@@ -2715,8 +2831,8 @@ function parseFlowOptions(args, start, end, config) {
2715
2831
  case "OVERRIDE_VALUE":
2716
2832
  case "ATTRIBUTE_DELETE": {
2717
2833
  if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2718
- const field2 = token === "DROP_VALUE" ? "drop_values" : token === "OVERRIDE_VALUE" ? "override_values" : "attributes_delete";
2719
- 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);
2720
2836
  values.push(args[index + 1]);
2721
2837
  index += 2;
2722
2838
  break;
@@ -2833,13 +2949,13 @@ function putScalar(payload, key, args, index, end) {
2833
2949
  setOwnValue2(payload, key, args[index]);
2834
2950
  return true;
2835
2951
  }
2836
- function ensureArrayField(payload, field2) {
2837
- const value = payload[field2];
2952
+ function ensureArrayField(payload, field3) {
2953
+ const value = payload[field3];
2838
2954
  if (Array.isArray(value)) {
2839
2955
  return value;
2840
2956
  }
2841
2957
  const next = [];
2842
- setOwnValue2(payload, field2, next);
2958
+ setOwnValue2(payload, field3, next);
2843
2959
  return next;
2844
2960
  }
2845
2961
  function putNumber(payload, key, args, index, end) {
@@ -3060,8 +3176,8 @@ function flowHistoryPayload(args) {
3060
3176
  case "CONSISTENT_PROJECTION":
3061
3177
  case "VALUES": {
3062
3178
  if (!isBoolToken(value)) return void 0;
3063
- const field2 = token === "REV" ? "rev" : token === "INCLUDE_COLD" ? "include_cold" : token === "CONSISTENT_PROJECTION" ? "consistent_projection" : "values";
3064
- 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);
3065
3181
  break;
3066
3182
  }
3067
3183
  default:
@@ -3073,9 +3189,9 @@ function flowHistoryPayload(args) {
3073
3189
  function flowAdminPayload(opcode, args, leadingFields = []) {
3074
3190
  if (args.length < leadingFields.length) return void 0;
3075
3191
  const payload = {};
3076
- for (const [index, field2] of leadingFields.entries()) {
3192
+ for (const [index, field3] of leadingFields.entries()) {
3077
3193
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
3078
- setOwnValue2(payload, field2, args[index]);
3194
+ setOwnValue2(payload, field3, args[index]);
3079
3195
  }
3080
3196
  for (let index = leadingFields.length; index < args.length; ) {
3081
3197
  hasOwnCommandArgument(args, index, args.length, "Flow admin arguments");
@@ -3083,15 +3199,15 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3083
3199
  if (token == null) return void 0;
3084
3200
  if (["ATTRIBUTE", "ATTRIBUTE_MERGE", "STATE_META", "VALUE", "VALUE_REF"].includes(token)) {
3085
3201
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments") || !hasOwnCommandArgument(args, index + 2, args.length, "Flow admin arguments")) return void 0;
3086
- const field3 = token === "ATTRIBUTE" ? "attributes" : token === "ATTRIBUTE_MERGE" ? "attributes_merge" : token === "STATE_META" ? "state_meta" : token === "VALUE" ? "values" : "value_refs";
3087
- 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]);
3088
3204
  index += 3;
3089
3205
  continue;
3090
3206
  }
3091
3207
  if (token === "ATTRIBUTE_DELETE" || token === "DROP_VALUE" || token === "OVERRIDE_VALUE") {
3092
3208
  if (!hasOwnCommandArgument(args, index + 1, args.length, "Flow admin arguments")) return void 0;
3093
- const field3 = token === "ATTRIBUTE_DELETE" ? "attributes_delete" : token === "DROP_VALUE" ? "drop_values" : "override_values";
3094
- 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]);
3095
3211
  index += 2;
3096
3212
  continue;
3097
3213
  }
@@ -3110,13 +3226,13 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3110
3226
  index += 2 + count;
3111
3227
  continue;
3112
3228
  }
3113
- const field2 = FLOW_ADMIN_FIELDS[token];
3114
- 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")) {
3115
3231
  return void 0;
3116
3232
  }
3117
3233
  const rawValue = args[index + 1];
3118
- if (FLOW_ADMIN_BOOLEAN_FIELDS.has(field2) && !isBoolToken(rawValue)) return void 0;
3119
- 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);
3120
3236
  index += 2;
3121
3237
  }
3122
3238
  const serverBlockMs = opcode === COMMAND_OPCODES["FLOW.SCHEDULE.FIRE_DUE"] && payload.block_ms != null ? blockDurationMs(payload.block_ms, 1) : void 0;
@@ -3124,7 +3240,7 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3124
3240
  }
3125
3241
 
3126
3242
  // src/protocol-flow-compact.ts
3127
- import { Buffer as Buffer11 } from "buffer";
3243
+ import { Buffer as Buffer12 } from "buffer";
3128
3244
 
3129
3245
  // src/protocol-flow-compact-common.ts
3130
3246
  function compactManyRequestTag(value, regularTag, okOnSuccessTag) {
@@ -3233,7 +3349,7 @@ function parseNamedCountMap(values, start) {
3233
3349
  }
3234
3350
 
3235
3351
  // src/protocol-flow-compact-transition.ts
3236
- import { Buffer as Buffer10 } from "buffer";
3352
+ import { Buffer as Buffer11 } from "buffer";
3237
3353
  function compactFlowTransitionManyPayload(partition, fromState, toState, rawItems, mixed, options, maxBodyBytes) {
3238
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) {
3239
3355
  return void 0;
@@ -3285,7 +3401,7 @@ function compactFlowTransitionManyPayload(partition, fromState, toState, rawItem
3285
3401
  total += 4 + idLength + 4 + itemPartitionLength + 8 + 4 + leaseLength;
3286
3402
  }
3287
3403
  assertCompactPayloadFits(total, maxBodyBytes);
3288
- const out = Buffer10.allocUnsafe(total);
3404
+ const out = Buffer11.allocUnsafe(total);
3289
3405
  let offset = 0;
3290
3406
  out.writeUInt8(tag, offset);
3291
3407
  offset += 1;
@@ -3343,7 +3459,7 @@ function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options,
3343
3459
  }
3344
3460
  assertCompactPayloadFits(total, maxBodyBytes);
3345
3461
  const tag = mixed ? COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST : auto ? COMPACT_FLOW_CREATE_MANY_REQUEST : COMPACT_FLOW_CREATE_MANY_PARTITION_REQUEST;
3346
- const out = Buffer11.allocUnsafe(total);
3462
+ const out = Buffer12.allocUnsafe(total);
3347
3463
  let offset = 0;
3348
3464
  out.writeUInt8(tag, offset++);
3349
3465
  offset = writeBinary(out, offset, toBuffer(options.type));
@@ -3388,7 +3504,7 @@ function compactFlowClaimDuePayload(type, options, maxBodyBytes) {
3388
3504
  total += 1;
3389
3505
  }
3390
3506
  assertCompactPayloadFits(total, maxBodyBytes);
3391
- const out = Buffer11.allocUnsafe(total);
3507
+ const out = Buffer12.allocUnsafe(total);
3392
3508
  let offset = 0;
3393
3509
  out.writeUInt8(COMPACT_FLOW_CLAIM_DUE_REQUEST, offset++);
3394
3510
  offset = writeBinary(out, offset, toBuffer(type));
@@ -3442,7 +3558,7 @@ function compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto
3442
3558
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3443
3559
  }
3444
3560
  assertCompactPayloadFits(total, maxBodyBytes);
3445
- const out = Buffer11.allocUnsafe(total);
3561
+ const out = Buffer12.allocUnsafe(total);
3446
3562
  let offset = 0;
3447
3563
  out.writeUInt8(
3448
3564
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_COMPLETE_MANY_OK_REQUEST : COMPACT_FLOW_COMPLETE_MANY_REQUEST,
@@ -3489,7 +3605,7 @@ function compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options,
3489
3605
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3490
3606
  }
3491
3607
  assertCompactPayloadFits(total, maxBodyBytes);
3492
- const out = Buffer11.allocUnsafe(total);
3608
+ const out = Buffer12.allocUnsafe(total);
3493
3609
  let offset = 0;
3494
3610
  out.writeUInt8(
3495
3611
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_RETRY_MANY_OK_REQUEST : COMPACT_FLOW_RETRY_MANY_REQUEST,
@@ -3577,7 +3693,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3577
3693
  total += 4 + idLength + 4 + itemPartitionLength + 8;
3578
3694
  }
3579
3695
  assertCompactPayloadFits(total, maxBodyBytes);
3580
- const out = Buffer11.allocUnsafe(total);
3696
+ const out = Buffer12.allocUnsafe(total);
3581
3697
  let offset = 0;
3582
3698
  out.writeUInt8(tag, offset);
3583
3699
  offset += 1;
@@ -3600,6 +3716,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3600
3716
  offset += 8;
3601
3717
  }
3602
3718
  return {
3719
+ compactResponseItems: count,
3603
3720
  flags: FLAG_CUSTOM_PAYLOAD,
3604
3721
  opcode: COMMAND_OPCODES["FLOW.CANCEL_MANY"],
3605
3722
  payload: out
@@ -3613,7 +3730,7 @@ function isOptionalSafeIntegerNumber(value) {
3613
3730
  }
3614
3731
 
3615
3732
  // src/protocol-flow-compact-single.ts
3616
- import { Buffer as Buffer12 } from "buffer";
3733
+ import { Buffer as Buffer13 } from "buffer";
3617
3734
  function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3618
3735
  if (refs.length > 4294967295 || maxBytes != null && (typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 0)) return void 0;
3619
3736
  const minimum = 13 + refs.length * 4;
@@ -3630,7 +3747,7 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3630
3747
  total += 4 + byteLength;
3631
3748
  }
3632
3749
  assertCompactPayloadFits(total, maxBodyBytes);
3633
- const out = Buffer12.allocUnsafe(total);
3750
+ const out = Buffer13.allocUnsafe(total);
3634
3751
  let offset = 0;
3635
3752
  out.writeUInt8(COMPACT_FLOW_VALUE_MGET_REQUEST, offset);
3636
3753
  offset += 1;
@@ -3643,47 +3760,6 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3643
3760
  }
3644
3761
  return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.flowValueMGet, payload: out };
3645
3762
  }
3646
- function compactFlowListPayload(args, maxBodyBytes) {
3647
- const type = args[0];
3648
- if (!isCompactBinaryArgument(type)) return void 0;
3649
- let state;
3650
- let count = 100;
3651
- let returnMode = 0;
3652
- const seen = /* @__PURE__ */ new Set();
3653
- for (let index = 1; index < args.length; index += 2) {
3654
- if (index + 1 >= args.length) return void 0;
3655
- const token = asText(args[index]).toUpperCase();
3656
- if (seen.has(token)) return void 0;
3657
- seen.add(token);
3658
- if (token === "STATE") {
3659
- if (!isCompactBinaryArgument(args[index + 1])) return void 0;
3660
- state = args[index + 1];
3661
- } else if (token === "COUNT") {
3662
- const value = safeIntegerNumberArg(args[index + 1]);
3663
- if (value <= 0) return void 0;
3664
- count = value;
3665
- } else if (token === "RETURN") {
3666
- if (!commandTokenIs(args[index + 1], "META")) return void 0;
3667
- returnMode = 1;
3668
- } else {
3669
- return void 0;
3670
- }
3671
- }
3672
- const typeLength = compactBinaryByteLength(type);
3673
- const stateLength = state == null ? 0 : compactBinaryByteLength(state);
3674
- const total = 1 + 4 + typeLength + 4 + stateLength + 8 + 1;
3675
- assertCompactPayloadFits(total, maxBodyBytes);
3676
- const out = Buffer12.allocUnsafe(total);
3677
- let offset = 0;
3678
- out.writeUInt8(COMPACT_FLOW_LIST_REQUEST, offset);
3679
- offset += 1;
3680
- offset = writeBinaryValue(out, offset, type, typeLength);
3681
- offset = writeOptionalBinaryValue(out, offset, state, stateLength);
3682
- out.writeBigInt64BE(BigInt(count), offset);
3683
- offset += 8;
3684
- out.writeUInt8(returnMode, offset);
3685
- return { flags: FLAG_CUSTOM_PAYLOAD, opcode: COMMAND_OPCODES["FLOW.LIST"], payload: out };
3686
- }
3687
3763
 
3688
3764
  // src/protocol-flow-routing.ts
3689
3765
  function withFlowPartitionRouting(command, payload) {
@@ -3732,15 +3808,6 @@ function expandFlowClaimStates(args) {
3732
3808
  }
3733
3809
 
3734
3810
  // src/protocol-flow.ts
3735
- function hasFlowCommandOnlyOption(command, args) {
3736
- if (command !== "FLOW.SEARCH") return false;
3737
- for (let index = 1; index < args.length; ) {
3738
- const token = asText(args[index]).toUpperCase();
3739
- if (token === "INDEXED_STATE_META") return true;
3740
- index += token === "ATTRIBUTE" || token === "STATE_META" ? 3 : 2;
3741
- }
3742
- return false;
3743
- }
3744
3811
  function flowCreatePayload(args) {
3745
3812
  if (args.length < 7) return void 0;
3746
3813
  const id = args[0];
@@ -3797,9 +3864,9 @@ function flowValueMGetPayload(args, maxBodyBytes, allowCompact) {
3797
3864
  }
3798
3865
  if (allowCompact) {
3799
3866
  const compact = compactFlowValueMGetPayload(refs, payload.max_bytes, maxBodyBytes);
3800
- if (compact != null) return compact;
3867
+ if (compact != null) return { ...compact, compactResponseItems: refs.length };
3801
3868
  }
3802
- return { opcode: OPCODES.flowValueMGet, payload };
3869
+ return { compactResponseItems: refs.length, opcode: OPCODES.flowValueMGet, payload };
3803
3870
  }
3804
3871
  function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3805
3872
  if (args.length < 2) return void 0;
@@ -3835,7 +3902,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3835
3902
  if (items2 == null) return void 0;
3836
3903
  const payload2 = { ...options, items: items2 };
3837
3904
  if (!auto && !mixed) payload2.partition_key = partition;
3838
- return { opcode: OPCODES.flowCreateMany, payload: payload2 };
3905
+ return { compactResponseItems: items2.length, opcode: OPCODES.flowCreateMany, payload: payload2 };
3839
3906
  }
3840
3907
  const rawItems = denseCommandArgumentTail(args, itemsIndex + 1, "ITEMS");
3841
3908
  const width = mixed ? 3 : 2;
@@ -3849,7 +3916,9 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3849
3916
  options,
3850
3917
  maxBodyBytes
3851
3918
  );
3852
- if (compact != null) return compact;
3919
+ if (compact != null) {
3920
+ return { ...compact, compactResponseItems: rawItems.length / width };
3921
+ }
3853
3922
  }
3854
3923
  const items = [];
3855
3924
  for (let index = 0; index < rawItems.length; index += width) {
@@ -3861,7 +3930,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
3861
3930
  }
3862
3931
  const payload = { ...options, items };
3863
3932
  if (!auto && !mixed) payload.partition_key = partition;
3864
- return { opcode: OPCODES.flowCreateMany, payload };
3933
+ return { compactResponseItems: items.length, opcode: OPCODES.flowCreateMany, payload };
3865
3934
  }
3866
3935
  function flowClaimDuePayload(args, maxBodyBytes, allowCompact) {
3867
3936
  if (args.length < 1) return void 0;
@@ -4024,7 +4093,9 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4024
4093
  if (rawItems.length === 0 || rawItems.length % width !== 0) return void 0;
4025
4094
  if (allowCompact) {
4026
4095
  const compact = command === "FLOW.RETRY_MANY" ? compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options, maxBodyBytes) : compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto, options, maxBodyBytes);
4027
- if (compact != null) return compact;
4096
+ if (compact != null) {
4097
+ return { ...compact, compactResponseItems: rawItems.length / width };
4098
+ }
4028
4099
  }
4029
4100
  const items = [];
4030
4101
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4036,7 +4107,7 @@ function flowClaimedManyPayload(command, opcode, args, maxBodyBytes = Number.MAX
4036
4107
  }
4037
4108
  const payload = { ...options, items };
4038
4109
  if (!auto && !mixed) payload.partition_key = partition;
4039
- return { opcode, payload };
4110
+ return { compactResponseItems: items.length, opcode, payload };
4040
4111
  }
4041
4112
  function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4042
4113
  if (args.length < 4) return void 0;
@@ -4076,7 +4147,9 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4076
4147
  options,
4077
4148
  maxBodyBytes
4078
4149
  ) : void 0;
4079
- if (compact != null) return compact;
4150
+ if (compact != null) {
4151
+ return { ...compact, compactResponseItems: rawItems.length / width };
4152
+ }
4080
4153
  }
4081
4154
  const items = [];
4082
4155
  for (let index = 0; index < rawItems.length; index += width) {
@@ -4096,7 +4169,11 @@ function flowTransitionManyPayload(args, maxBodyBytes, allowCompact) {
4096
4169
  items
4097
4170
  };
4098
4171
  if (!mixed) payload.partition_key = args[0];
4099
- return { opcode: OPCODES.flowTransitionMany, payload };
4172
+ return {
4173
+ compactResponseItems: items.length,
4174
+ opcode: OPCODES.flowTransitionMany,
4175
+ payload
4176
+ };
4100
4177
  }
4101
4178
  function flowSpawnChildrenPayload(args) {
4102
4179
  if (args.length < 2) return void 0;
@@ -4139,13 +4216,6 @@ function flowSpawnChildrenPayload(args) {
4139
4216
  payload: { id: args[0], ...options, children }
4140
4217
  };
4141
4218
  }
4142
- function flowSearchPayload(args) {
4143
- if (args.length < 1) return void 0;
4144
- const payload = optionMap(args.slice(1));
4145
- if (payload == null) return void 0;
4146
- normalizeFlowSearchStateMeta(payload);
4147
- return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
4148
- }
4149
4219
 
4150
4220
  // src/protocol-flow-signal.ts
4151
4221
  function flowSignalPayload(args) {
@@ -4171,7 +4241,7 @@ function flowSignalPayload(args) {
4171
4241
  }
4172
4242
 
4173
4243
  // src/protocol-flow-policy.ts
4174
- import { Buffer as Buffer13 } from "buffer";
4244
+ import { Buffer as Buffer14 } from "buffer";
4175
4245
  var BACKOFF_FIELDS = {
4176
4246
  BASE_MS: "base_ms",
4177
4247
  MAX_MS: "max_ms",
@@ -4301,7 +4371,7 @@ function maxActiveOption(value) {
4301
4371
  return integerOption(value);
4302
4372
  }
4303
4373
  function isBinaryArgument(value) {
4304
- return typeof value === "string" || Buffer13.isBuffer(value) || value instanceof Uint8Array;
4374
+ return typeof value === "string" || Buffer14.isBuffer(value) || value instanceof Uint8Array;
4305
4375
  }
4306
4376
  function objectField(target, name) {
4307
4377
  const existing = Object.hasOwn(target, name) ? target[name] : void 0;
@@ -4373,7 +4443,7 @@ function commandRequiresOrderedPipelineExecution(args) {
4373
4443
  }
4374
4444
 
4375
4445
  // src/protocol-compact-request.ts
4376
- import { Buffer as Buffer14 } from "buffer";
4446
+ import { Buffer as Buffer15 } from "buffer";
4377
4447
  function compactMsetPayload(args, maxBodyBytes) {
4378
4448
  if (args.length % 2 !== 0) throw new FerricStoreError("MSET requires key/value pairs");
4379
4449
  const minimum = 6 + args.length * 4;
@@ -4392,7 +4462,7 @@ function compactMsetPayload(args, maxBodyBytes) {
4392
4462
  total += 4 + byteLength;
4393
4463
  }
4394
4464
  assertCompactPayloadFits(total, maxBodyBytes);
4395
- const out = Buffer14.allocUnsafe(total);
4465
+ const out = Buffer15.allocUnsafe(total);
4396
4466
  let offset = writeCompactPipelineHeader(out, 1, args.length / 2);
4397
4467
  for (let index = 0; index < args.length; index += 1) {
4398
4468
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4416,7 +4486,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4416
4486
  total += 4 + byteLength;
4417
4487
  }
4418
4488
  assertCompactPayloadFits(total, maxBodyBytes);
4419
- const out = Buffer14.allocUnsafe(total);
4489
+ const out = Buffer15.allocUnsafe(total);
4420
4490
  let offset = writeCompactPipelineHeader(out, mode, args.length);
4421
4491
  for (let index = 0; index < args.length; index += 1) {
4422
4492
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4426,7 +4496,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4426
4496
  function compactPipelinePayload(commands, maxBodyBytes) {
4427
4497
  if (commands.length === 0) {
4428
4498
  assertCompactPayloadFits(6, maxBodyBytes);
4429
- const out = Buffer14.allocUnsafe(6);
4499
+ const out = Buffer15.allocUnsafe(6);
4430
4500
  writeCompactPipelineHeader(out, 128 | 2, 0);
4431
4501
  return out;
4432
4502
  }
@@ -4468,7 +4538,7 @@ function compactSetPipelinePayload(commands, maxBodyBytes) {
4468
4538
  total += 8 + keyByteLength + valueByteLength;
4469
4539
  }
4470
4540
  assertCompactPayloadFits(total, maxBodyBytes);
4471
- const out = Buffer14.allocUnsafe(total);
4541
+ const out = Buffer15.allocUnsafe(total);
4472
4542
  let offset = writeCompactPipelineHeader(out, 128 | 1, commands.length);
4473
4543
  for (let index = 0; index < commands.length; index += 1) {
4474
4544
  offset = writeBinaryValue(out, offset, argumentValues[index * 2], argumentByteLengths[index * 2] ?? 0);
@@ -4503,7 +4573,7 @@ function compactGetPipelinePayload(commands, maxBodyBytes) {
4503
4573
  total += 4 + keyByteLength;
4504
4574
  }
4505
4575
  assertCompactPayloadFits(total, maxBodyBytes);
4506
- const out = Buffer14.allocUnsafe(total);
4576
+ const out = Buffer15.allocUnsafe(total);
4507
4577
  let offset = writeCompactPipelineHeader(out, 128 | 2, commands.length);
4508
4578
  for (let index = 0; index < commands.length; index += 1) {
4509
4579
  offset = writeBinaryValue(out, offset, keys[index], keyByteLengths[index] ?? 0);
@@ -4544,7 +4614,7 @@ function writeCompactPipelineHeader(out, mode, count) {
4544
4614
  }
4545
4615
 
4546
4616
  // src/protocol-kv.ts
4547
- import { Buffer as Buffer15 } from "buffer";
4617
+ import { Buffer as Buffer16 } from "buffer";
4548
4618
  function collectionProtocolCommand(command, args) {
4549
4619
  switch (command) {
4550
4620
  case "CAS":
@@ -4615,8 +4685,8 @@ function stringSetPayload(args) {
4615
4685
  if (value == null || token === "EX" && value > Math.floor(Number.MAX_SAFE_INTEGER / 1e3)) {
4616
4686
  return void 0;
4617
4687
  }
4618
- const field2 = token === "EX" || token === "PX" ? "ttl" : token.toLowerCase();
4619
- 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);
4620
4690
  expirySeen = true;
4621
4691
  index += 2;
4622
4692
  } else if (token === "NX") {
@@ -4715,25 +4785,25 @@ function hashSetCommand(args) {
4715
4785
  if (!isBinaryCommandArgument(args[0]) || args.length < 3 || args.length % 2 !== 1) return void 0;
4716
4786
  const fields = /* @__PURE__ */ Object.create(null);
4717
4787
  for (let index = 1; index < args.length; index += 2) {
4718
- const field2 = args[index];
4788
+ const field3 = args[index];
4719
4789
  const value = args[index + 1];
4720
- if (typeof field2 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4721
- setOwnValue2(fields, field2, value);
4790
+ if (typeof field3 !== "string" || !isBinaryCommandArgument(value)) return void 0;
4791
+ setOwnValue2(fields, field3, value);
4722
4792
  }
4723
4793
  return { opcode: COMMAND_OPCODES.HSET, payload: { fields, key: args[0] } };
4724
4794
  }
4725
4795
  function keyOnlyCommand(opcode, args) {
4726
4796
  return args.length === 1 && isBinaryCommandArgument(args[0]) ? { opcode, payload: { key: args[0] } } : void 0;
4727
4797
  }
4728
- function binaryFieldsCommand(opcode, args, field2, length) {
4798
+ function binaryFieldsCommand(opcode, args, field3, length) {
4729
4799
  if (args.length !== length || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1])) return void 0;
4730
- return { opcode, payload: { [field2]: args[1], key: args[0] } };
4800
+ return { opcode, payload: { [field3]: args[1], key: args[0] } };
4731
4801
  }
4732
- function binaryListCommand(opcode, args, field2) {
4802
+ function binaryListCommand(opcode, args, field3) {
4733
4803
  if (!isBinaryCommandArgument(args[0]) || args.length < 2) return void 0;
4734
4804
  const values = args.slice(1);
4735
4805
  if (!values.every(isBinaryCommandArgument)) return void 0;
4736
- return { opcode, payload: { [field2]: values, key: args[0] } };
4806
+ return { opcode, payload: { [field3]: values, key: args[0] } };
4737
4807
  }
4738
4808
  function listPopCommand(opcode, args) {
4739
4809
  if (!isBinaryCommandArgument(args[0]) || args.length !== 1 && args.length !== 2) return void 0;
@@ -4791,17 +4861,35 @@ function parsedNumber(value) {
4791
4861
  }
4792
4862
  }
4793
4863
  function isBinaryCommandArgument(value) {
4794
- return typeof value === "string" || Buffer15.isBuffer(value);
4864
+ return typeof value === "string" || Buffer16.isBuffer(value);
4795
4865
  }
4796
4866
  function isDirectKvValueArgument(value) {
4797
4867
  return isBinaryCommandArgument(value) || typeof value === "object" && value != null;
4798
4868
  }
4799
4869
  function binaryToken(value) {
4800
- return typeof value === "string" ? value.toUpperCase() : Buffer15.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);
4801
4890
  }
4802
4891
 
4803
4892
  // src/protocol-value.ts
4804
- import { Buffer as Buffer16 } from "buffer";
4805
4893
  function planValueWithLimit(value, maxBytes) {
4806
4894
  const budget = {
4807
4895
  maxBytes,
@@ -4856,7 +4944,7 @@ function planContainerValue(value, budget, ancestors, depth) {
4856
4944
  let byteLength = 5;
4857
4945
  let index = 0;
4858
4946
  for (const [key, item] of entries) {
4859
- const keyByteLength = Buffer16.byteLength(key);
4947
+ const keyByteLength = Buffer17.byteLength(key);
4860
4948
  consumeEncodeBytes(budget, 4 + keyByteLength);
4861
4949
  const valuePlan = planValueAt(item, budget, ancestors, depth + 1);
4862
4950
  entryPlans[index] = { key, keyByteLength, value: valuePlan };
@@ -4895,17 +4983,21 @@ function planScalarValue(value, budget) {
4895
4983
  return { byteLength: 9, tag: 3, value: BigInt(value) };
4896
4984
  }
4897
4985
  if (typeof value === "bigint") {
4898
- if (value < MIN_I64 || value > MAX_I64) {
4899
- 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 };
4900
4989
  }
4901
- consumeEncodeBytes(budget, 9);
4902
- 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");
4903
4995
  }
4904
4996
  if (typeof value === "number") {
4905
4997
  consumeEncodeBytes(budget, 9);
4906
4998
  return { byteLength: 9, tag: 7, value };
4907
4999
  }
4908
- if (typeof value === "string" || Buffer16.isBuffer(value) || value instanceof Uint8Array) {
5000
+ if (typeof value === "string" || Buffer17.isBuffer(value) || value instanceof Uint8Array) {
4909
5001
  const valueByteLength = binaryValueByteLength(value);
4910
5002
  const byteLength = 5 + valueByteLength;
4911
5003
  consumeEncodeBytes(budget, byteLength);
@@ -4929,7 +5021,7 @@ function writeValuePlan(output, start, plan) {
4929
5021
  offset += 4;
4930
5022
  if (typeof plan.value === "string") {
4931
5023
  output.write(plan.value, offset, plan.valueByteLength, "utf8");
4932
- } else if (Buffer16.isBuffer(plan.value)) {
5024
+ } else if (Buffer17.isBuffer(plan.value)) {
4933
5025
  plan.value.copy(output, offset);
4934
5026
  } else {
4935
5027
  output.set(plan.value, offset);
@@ -4954,6 +5046,9 @@ function writeValuePlan(output, start, plan) {
4954
5046
  case 7:
4955
5047
  output.writeDoubleBE(plan.value, offset);
4956
5048
  return offset + 8;
5049
+ case 8:
5050
+ output.writeBigUInt64BE(plan.value, offset);
5051
+ return offset + 8;
4957
5052
  }
4958
5053
  }
4959
5054
  function consumeEncodeBytes(budget, bytes2) {
@@ -5011,7 +5106,7 @@ function decodeValueAt(data, offset, limits, budget, depth) {
5011
5106
  const key = readBinary(data, offset);
5012
5107
  offset = key.offset;
5013
5108
  const item = decodeValueAt(data, offset, limits, budget, depth + 1);
5014
- setOwnValue2(value, key.value.toString("utf8"), item.value);
5109
+ setProtocolMapEntry(value, key.value, item.value);
5015
5110
  offset = item.offset;
5016
5111
  }
5017
5112
  return { value, offset };
@@ -5020,6 +5115,14 @@ function decodeValueAt(data, offset, limits, budget, depth) {
5020
5115
  requireAvailable(data, offset, 8);
5021
5116
  return { value: data.readDoubleBE(offset), offset: offset + 8 };
5022
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
+ }
5023
5126
  throw new FerricStoreError(`unknown protocol value tag ${tag}`);
5024
5127
  }
5025
5128
  function decodeValueWithBudget(data, offset, budget) {
@@ -5063,20 +5166,20 @@ function requireAvailable(data, offset, size) {
5063
5166
  }
5064
5167
 
5065
5168
  // src/key-slot-validation.ts
5066
- import { Buffer as Buffer18 } from "buffer";
5169
+ import { Buffer as Buffer19 } from "buffer";
5067
5170
 
5068
5171
  // src/topology-utilities.ts
5069
- import { Buffer as Buffer17 } from "buffer";
5172
+ import { Buffer as Buffer18 } from "buffer";
5070
5173
  function isPlainObject3(value) {
5071
- return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer17.isBuffer(value);
5174
+ return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer18.isBuffer(value);
5072
5175
  }
5073
5176
  function getField(source, ...keys) {
5074
5177
  if (source instanceof Map) {
5075
5178
  for (const key of keys) {
5076
5179
  if (source.has(key)) return source.get(key);
5077
- const bufferKey = Buffer17.from(key);
5180
+ const bufferKey = Buffer18.from(key);
5078
5181
  for (const [itemKey, value] of source.entries()) {
5079
- if (Buffer17.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
5182
+ if (Buffer18.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
5080
5183
  }
5081
5184
  }
5082
5185
  return void 0;
@@ -5090,14 +5193,14 @@ function getField(source, ...keys) {
5090
5193
  }
5091
5194
  function textOrUndefined(value) {
5092
5195
  if (typeof value === "string") return value;
5093
- if (Buffer17.isBuffer(value)) return value.toString("utf8");
5196
+ if (Buffer18.isBuffer(value)) return value.toString("utf8");
5094
5197
  return void 0;
5095
5198
  }
5096
5199
  function numberOrUndefined(value) {
5097
5200
  return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
5098
5201
  }
5099
- function nativeEventName(event) {
5100
- return textOrUndefined(getField(event.value, "event"))?.toUpperCase();
5202
+ function nativeEventName(event2) {
5203
+ return textOrUndefined(getField(event2.value, "event"))?.toUpperCase();
5101
5204
  }
5102
5205
  function endpointFromRange(item) {
5103
5206
  const endpointValue = getField(item, "endpoint");
@@ -5265,7 +5368,7 @@ function stringHashRange(key) {
5265
5368
  var validatedCommands = /* @__PURE__ */ new WeakSet();
5266
5369
  function assertAtomicKeyValueCommandSharesSlot(args) {
5267
5370
  const value = args[0];
5268
- const command = (typeof value === "string" ? value : Buffer18.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5371
+ const command = (typeof value === "string" ? value : Buffer19.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5269
5372
  if (command === "MSET" || command === "MSETNX") {
5270
5373
  assertKeyValueCommandSharesSlot(args, command);
5271
5374
  }
@@ -5275,7 +5378,7 @@ function assertKeyValueCommandSharesSlot(args, command) {
5275
5378
  let expectedSlot;
5276
5379
  for (let index = 1; index < args.length; index += 2) {
5277
5380
  const key = args[index];
5278
- if (typeof key !== "string" && !Buffer18.isBuffer(key)) return;
5381
+ if (typeof key !== "string" && !Buffer19.isBuffer(key)) return;
5279
5382
  const slot = routingSlotForKey(key);
5280
5383
  expectedSlot ??= slot;
5281
5384
  if (slot !== expectedSlot) {
@@ -5286,62 +5389,202 @@ function assertKeyValueCommandSharesSlot(args, command) {
5286
5389
  }
5287
5390
 
5288
5391
  // src/protocol-response.ts
5289
- import { Buffer as Buffer22 } from "buffer";
5392
+ import { Buffer as Buffer26 } from "buffer";
5290
5393
 
5291
5394
  // src/protocol-compact-response.ts
5292
- import { Buffer as Buffer21 } from "buffer";
5395
+ import { Buffer as Buffer25 } from "buffer";
5293
5396
 
5294
5397
  // src/native-negotiation.ts
5295
- import { Buffer as Buffer19 } from "buffer";
5398
+ import { Buffer as Buffer20 } from "buffer";
5296
5399
  var EMPTY_COMPACT_RESPONSE_OPCODES = /* @__PURE__ */ new Map();
5297
5400
  function nativeNegotiation(value) {
5298
5401
  const capabilities = field(value, "capabilities") ?? value;
5299
5402
  const limits = field(capabilities, "limits");
5300
- 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");
5301
5406
  const maxResponseBytes = positiveSafeInteger3(field(limits, "max_response_bytes"));
5302
5407
  return {
5303
5408
  compactResponseOpcodes: parseCompactResponseOpcodes(
5304
5409
  field(responseCodecs, "compact_response_opcodes")
5305
5410
  ),
5411
+ flowQuery: parseFlowQueryNegotiation(capabilities, schemas),
5306
5412
  ...maxResponseBytes == null ? {} : { maxResponseBytes }
5307
5413
  };
5308
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
+ }
5309
5531
  function compactResponseOpcodeSupports(capabilities, codec, opcode) {
5310
5532
  return capabilities?.get(codec)?.has(opcode) === true;
5311
5533
  }
5312
5534
  function parseCompactResponseOpcodes(value) {
5535
+ if (value == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
5313
5536
  const entries = mapEntries(value);
5314
- 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
+ }
5315
5543
  const result = /* @__PURE__ */ new Map();
5544
+ let totalOpcodes = 0;
5316
5545
  for (const [rawName, rawOpcodes] of entries) {
5317
- const name = text2(rawName);
5318
- 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
+ }
5319
5560
  const opcodes = /* @__PURE__ */ new Set();
5320
- let valid = true;
5321
5561
  for (let index = 0; index < rawOpcodes.length; index += 1) {
5322
5562
  if (!Object.hasOwn(rawOpcodes, index)) {
5323
- valid = false;
5324
- break;
5563
+ throw incompatibleServer(`HELLO compact_response_opcodes codec ${name} must be dense`);
5325
5564
  }
5326
- const opcode = unsigned16(rawOpcodes[index]);
5565
+ const opcode = strictUnsigned16(rawOpcodes[index]);
5327
5566
  if (opcode == null) {
5328
- valid = false;
5329
- 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`);
5330
5571
  }
5331
5572
  opcodes.add(opcode);
5332
5573
  }
5333
- if (valid) result.set(name, opcodes);
5574
+ result.set(name, opcodes);
5334
5575
  }
5335
5576
  return result;
5336
5577
  }
5337
5578
  function mapEntries(value) {
5338
5579
  if (value instanceof Map) return [...value.entries()];
5339
- 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;
5340
5581
  return Object.entries(value);
5341
5582
  }
5342
- function unsigned16(value) {
5343
- const parsed = nonNegativeSafeInteger2(value);
5344
- 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;
5345
5588
  }
5346
5589
  function positiveSafeInteger3(value) {
5347
5590
  const parsed = nonNegativeSafeInteger2(value);
@@ -5360,8 +5603,8 @@ function nonNegativeSafeInteger2(value) {
5360
5603
  }
5361
5604
  function text2(value) {
5362
5605
  if (typeof value === "string") return value;
5363
- if (Buffer19.isBuffer(value) || value instanceof Uint8Array) {
5364
- return Buffer19.from(value).toString("utf8");
5606
+ if (Buffer20.isBuffer(value) || value instanceof Uint8Array) {
5607
+ return Buffer20.from(value).toString("utf8");
5365
5608
  }
5366
5609
  return void 0;
5367
5610
  }
@@ -5432,7 +5675,7 @@ function readCompactBinaryMap(data, offset, budget) {
5432
5675
  for (let index = 0; index < count; index += 1) {
5433
5676
  const key = readBinary(data, offset);
5434
5677
  const value = readBinary(data, key.offset);
5435
- setOwnValue2(values, key.value.toString("utf8"), value.value);
5678
+ setProtocolMapEntry(values, key.value, value.value);
5436
5679
  offset = value.offset;
5437
5680
  }
5438
5681
  return { value: values, offset };
@@ -5448,52 +5691,287 @@ function requireCompactContainer(count, budget) {
5448
5691
  consumeDecodeItems(count, budget);
5449
5692
  }
5450
5693
 
5451
- // src/protocol-compact-response.ts
5452
- function tryDecodeCompactResponse(opcode, body, hints) {
5453
- if (body.byteLength === 0) return { found: false, value: void 0 };
5454
- const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
5455
- const tag = body.readUInt8(0);
5456
- const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
5457
- if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
5458
- const values = decodeCompactOkList(body, budget);
5459
- return {
5460
- found: true,
5461
- value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values.length === 1 ? "OK" : values
5462
- };
5463
- }
5464
- if (tag === COMPACT_KV_GET && supports(hints, "kv_get_v1", opcode)) {
5465
- return { found: true, value: decodeCompactKvGet(body) };
5466
- }
5467
- if ((tag === COMPACT_KV_MGET || tag === COMPACT_KV_MGET_FIXED) && (supports(hints, "kv_mget_v1", opcode) || pipelineValues)) {
5468
- const values = tag === COMPACT_KV_MGET ? decodeCompactMget(body, budget) : decodeCompactMgetFixed(body, budget);
5469
- return {
5470
- found: true,
5471
- value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
5472
- };
5473
- }
5474
- if (tag === COMPACT_INTEGER_LIST && pipelineValues) {
5475
- return { found: true, value: markCompactPipelineDecoded(decodeCompactIntegerList(body, budget)) };
5476
- }
5477
- if (tag === COMPACT_BINARY_LIST_LIST && pipelineValues) {
5478
- return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryListList(body, budget)) };
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);
5479
5707
  }
5480
- if (tag === COMPACT_BINARY_MAP_LIST && pipelineValues) {
5481
- return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryMapList(body, budget)) };
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);
5482
5715
  }
5483
- if (tag === COMPACT_PIPELINE_RESPONSE && pipelineValues) {
5484
- return { found: true, value: decodeCompactPipeline(body, budget, hints.pipelineClaimModes) };
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;
5485
5745
  }
5486
- if (tag === COMPACT_FLOW_CLAIM_JOBS && (supports(hints, "flow_claim_jobs_v1", opcode) || pipelineValues)) {
5487
- const values = decodeCompactClaimJobs(body, budget, hints.compactClaimMode);
5488
- return {
5489
- found: true,
5490
- value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
5491
- };
5746
+ if (!isDecodedRecord(value)) return value;
5747
+ for (const key of Object.keys(value)) {
5748
+ setOwnValue2(value, key, detachDecodedBinary(value[key], backingBytes));
5492
5749
  }
5493
- if (tag === COMPACT_FLOW_RECORD && supports(hints, "flow_record_v1", opcode)) {
5494
- const read = readCompactFlowRecord(body, 0, budget);
5495
- if (read.offset !== body.byteLength) throw new FerricStoreError("trailing compact Flow record bytes");
5496
- return { found: true, value: read.value };
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) {
5930
+ if (body.byteLength === 0) return { found: false, value: void 0 };
5931
+ const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
5932
+ const tag = body.readUInt8(0);
5933
+ validateCompactResponseItems(tag, opcode, body, hints);
5934
+ const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
5935
+ if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
5936
+ const values = decodeCompactOkList(body, budget);
5937
+ return {
5938
+ found: true,
5939
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values.length === 1 ? "OK" : values
5940
+ };
5941
+ }
5942
+ if (tag === COMPACT_KV_GET && supports(hints, "kv_get_v1", opcode)) {
5943
+ return { found: true, value: decodeCompactKvGet(body) };
5944
+ }
5945
+ if ((tag === COMPACT_KV_MGET || tag === COMPACT_KV_MGET_FIXED) && (supports(hints, "kv_mget_v1", opcode) || pipelineValues)) {
5946
+ const values = tag === COMPACT_KV_MGET ? decodeCompactMget(body, budget) : decodeCompactMgetFixed(body, budget);
5947
+ return {
5948
+ found: true,
5949
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
5950
+ };
5951
+ }
5952
+ if (tag === COMPACT_INTEGER_LIST && pipelineValues) {
5953
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactIntegerList(body, budget)) };
5954
+ }
5955
+ if (tag === COMPACT_BINARY_LIST_LIST && pipelineValues) {
5956
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryListList(body, budget)) };
5957
+ }
5958
+ if (tag === COMPACT_BINARY_MAP_LIST && pipelineValues) {
5959
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryMapList(body, budget)) };
5960
+ }
5961
+ if (tag === COMPACT_PIPELINE_RESPONSE && pipelineValues) {
5962
+ return { found: true, value: decodeCompactPipeline(body, budget, hints.pipelineClaimModes) };
5963
+ }
5964
+ if (tag === COMPACT_FLOW_CLAIM_JOBS && (supports(hints, "flow_claim_jobs_v1", opcode) || pipelineValues)) {
5965
+ const values = decodeCompactClaimJobs(body, budget, hints.compactClaimMode);
5966
+ return {
5967
+ found: true,
5968
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
5969
+ };
5970
+ }
5971
+ if (tag === COMPACT_FLOW_RECORD && supports(hints, "flow_record_v1", opcode)) {
5972
+ const read = readCompactFlowRecord(body, 0, budget);
5973
+ if (read.offset !== body.byteLength) throw new FerricStoreError("trailing compact Flow record bytes");
5974
+ return { found: true, value: read.value };
5497
5975
  }
5498
5976
  if (tag === COMPACT_FLOW_RECORD_LIST && (supports(hints, "flow_record_list_v1", opcode) || pipelineValues)) {
5499
5977
  const read = readCompactFlowRecordList(body, 0, budget);
@@ -5503,6 +5981,9 @@ function tryDecodeCompactResponse(opcode, body, hints) {
5503
5981
  value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(read.value) : read.value
5504
5982
  };
5505
5983
  }
5984
+ if (tag === COMPACT_FLOW_QUERY_RESULT && supports(hints, "flow_query_result_v1", opcode)) {
5985
+ return { found: true, value: decodeCompactFlowQueryResult(body, budget) };
5986
+ }
5506
5987
  return { found: false, value: void 0 };
5507
5988
  }
5508
5989
  function supports(hints, codec, opcode) {
@@ -5513,7 +5994,7 @@ function decodeCompactOkList(data, budget) {
5513
5994
  const count = data.readUInt32BE(1);
5514
5995
  requireCompactContainer2(count, budget);
5515
5996
  if (data.byteLength !== 5) throw new FerricStoreError("invalid compact OK list response");
5516
- return Array.from({ length: count }, () => Buffer21.from("OK"));
5997
+ return Array.from({ length: count }, () => Buffer25.from("OK"));
5517
5998
  }
5518
5999
  function decodeCompactKvGet(data) {
5519
6000
  requireAvailable(data, 0, 2);
@@ -5559,7 +6040,7 @@ function decodeCompactMgetFixed(data, budget) {
5559
6040
  if (size === NULL_U32 || data.byteLength !== expected) {
5560
6041
  throw new FerricStoreError("invalid compact fixed MGET response");
5561
6042
  }
5562
- if (size === 0) return new Array(count).fill(Buffer21.alloc(0));
6043
+ if (size === 0) return new Array(count).fill(Buffer25.alloc(0));
5563
6044
  const values = new Array(count);
5564
6045
  for (let index = 0, offset = 9; index < count; index += 1, offset += size) {
5565
6046
  values[index] = data.subarray(offset, offset + size);
@@ -5620,7 +6101,7 @@ function decodeCompactPipeline(data, budget, claimModes) {
5620
6101
  const read = readBinary(data, offset);
5621
6102
  const errorStatus = status === 1 ? "busy" : "error";
5622
6103
  values[index] = classifyServerError(
5623
- errorMessage(status === 1 ? 4 : 1, read.value),
6104
+ protocolErrorMessage(status === 1 ? 4 : 1, read.value),
5624
6105
  read.value,
5625
6106
  void 0,
5626
6107
  errorStatus
@@ -5730,13 +6211,13 @@ function readCompactFlowRecord(data, offset, budget = { remainingItems: DEFAULT_
5730
6211
  let key;
5731
6212
  if (keyId === 0) {
5732
6213
  const read2 = readBinary(data, offset);
5733
- key = read2.value.toString("utf8");
6214
+ key = read2.value;
5734
6215
  offset = read2.offset;
5735
6216
  } else {
5736
6217
  key = FLOW_RECORD_FIELD_KEYS[keyId] ?? `field_${keyId}`;
5737
6218
  }
5738
6219
  const read = decodeValueWithBudget(data, offset, budget);
5739
- setOwnValue2(record, key, read.value);
6220
+ setProtocolMapEntry(record, key, read.value);
5740
6221
  offset = read.offset;
5741
6222
  }
5742
6223
  return { value: record, offset };
@@ -5772,15 +6253,29 @@ function requireCompactContainer2(count, budget) {
5772
6253
  }
5773
6254
  consumeDecodeItems(count, budget);
5774
6255
  }
5775
- function errorMessage(status, value) {
5776
- if (typeof value === "string") return value;
5777
- if (Buffer21.isBuffer(value)) return value.toString("utf8");
5778
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5779
- const message = value.message;
5780
- 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
+ );
5781
6266
  }
5782
- return `ERR native request failed status=${status}: ${String(value)}`;
5783
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
+ ]);
5784
6279
 
5785
6280
  // src/protocol-response.ts
5786
6281
  function decodeResponse(frame, expectedOpcode, hints = {}) {
@@ -5798,9 +6293,16 @@ function decodeResponse(frame, expectedOpcode, hints = {}) {
5798
6293
  }
5799
6294
  const status = frame.body.readUInt16BE(0);
5800
6295
  const body = frame.body.subarray(2);
5801
- 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
+ );
5802
6304
  if (status === STATUS_OK) return value;
5803
- const message = errorMessage2(status, value);
6305
+ const message = protocolErrorMessage(status, value);
5804
6306
  throw classifyServerError(message, value, void 0, status);
5805
6307
  }
5806
6308
  function unwrapPipelineResponse(value, options = {}, expectedItems) {
@@ -5839,7 +6341,7 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5839
6341
  continue;
5840
6342
  }
5841
6343
  const error = classifyServerError(
5842
- errorMessage2(status === "busy" ? 4 : 1, payload),
6344
+ protocolErrorMessage(status === "busy" ? 4 : 1, payload),
5843
6345
  payload,
5844
6346
  void 0,
5845
6347
  status
@@ -5854,28 +6356,24 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5854
6356
  return out;
5855
6357
  }
5856
6358
  function pipelineStatus(value) {
5857
- if (typeof value !== "string" && !Buffer22.isBuffer(value) && !(value instanceof Uint8Array)) return null;
6359
+ if (typeof value !== "string" && !Buffer26.isBuffer(value) && !(value instanceof Uint8Array)) return null;
5858
6360
  const status = asText(value).toLowerCase();
5859
6361
  return status === "ok" || status === "busy" || status === "error" ? status : null;
5860
6362
  }
5861
- function decodeResponseValue(opcode, body, hints) {
5862
- const compact = tryDecodeCompactResponse(opcode, body, hints);
5863
- 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
+ }
5864
6371
  const decoded = decodeValue(body);
5865
6372
  if (decoded.offset !== body.byteLength) {
5866
6373
  throw new FerricStoreError("native protocol response has trailing bytes", { raw: body });
5867
6374
  }
5868
6375
  return decoded.value;
5869
6376
  }
5870
- function errorMessage2(status, value) {
5871
- if (typeof value === "string") return value;
5872
- if (Buffer22.isBuffer(value)) return value.toString("utf8");
5873
- if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5874
- const message = value.message;
5875
- return typeof message === "string" ? message : String(message);
5876
- }
5877
- return `ERR native request failed status=${status}: ${String(value)}`;
5878
- }
5879
6377
 
5880
6378
  // src/protocol.ts
5881
6379
  function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
@@ -5885,7 +6383,7 @@ function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGE
5885
6383
  const bodyLength = customPayload ? binaryValueByteLength(command.payload) : plan?.byteLength ?? 0;
5886
6384
  if (bodyLength > bodyLimit) throw requestFrameTooLarge(bodyLimit);
5887
6385
  const flags = command.flags ?? 0;
5888
- const frame = Buffer23.allocUnsafe(HEADER_SIZE + bodyLength);
6386
+ const frame = Buffer27.allocUnsafe(HEADER_SIZE + bodyLength);
5889
6387
  frame.write(MAGIC, 0, "ascii");
5890
6388
  frame.writeUInt8(REQUEST_VERSION, 4);
5891
6389
  frame.writeUInt8(flags, 5);
@@ -5986,18 +6484,18 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5986
6484
  }
5987
6485
  if (command === "SET" && commandArgs2.length >= 2) {
5988
6486
  const payload = stringSetPayload(commandArgs2);
5989
- return payload == null ? commandExec(args) : { opcode: OPCODES.set, payload };
6487
+ return payload == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.set, payload };
5990
6488
  }
5991
6489
  if (command === "MGET" && commandArgs2.length > 0) {
5992
6490
  const compact = allowCustomPayload ? compactKeyPipelinePayload(OPCODES.mget, commandArgs2, 2, maxBodyBytes) : void 0;
5993
- if (compact != null) return compact;
5994
- 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);
5995
6493
  }
5996
6494
  if (command === "MSET" && commandArgs2.length >= 2 && commandArgs2.length % 2 === 0) {
5997
6495
  const compact = allowCustomPayload ? compactMsetPayload(commandArgs2, maxBodyBytes) : void 0;
5998
- if (compact != null) return compact;
6496
+ if (compact != null) return { ...compact, compactResponseItems: 1 };
5999
6497
  const pairs = typedKeyValuePairs(commandArgs2);
6000
- return pairs == null ? commandExec(args) : { opcode: OPCODES.mset, payload: { pairs } };
6498
+ return pairs == null ? commandExec(args) : { compactResponseItems: 1, opcode: OPCODES.mset, payload: { pairs } };
6001
6499
  }
6002
6500
  if (command === "DEL" && commandArgs2.length > 0) {
6003
6501
  return commandArgs2.every(isBinaryCommandArgument) ? { opcode: OPCODES.del, payload: { keys: commandArgs2 } } : commandExec(args);
@@ -6007,8 +6505,8 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
6007
6505
  if (command === "FLOW.HISTORY") {
6008
6506
  return flowHistoryPayload(commandArgs2) ?? commandExec(args);
6009
6507
  }
6010
- if (command === "FLOW.LIST") {
6011
- return (allowCustomPayload ? compactFlowListPayload(commandArgs2, maxBodyBytes) : void 0) ?? commandExec(args);
6508
+ if (command === "FLOW.QUERY") {
6509
+ return { opcode: OPCODES.flowQuery, payload: flowQueryPayload(commandArgs2) };
6012
6510
  }
6013
6511
  if (command === "FLOW.POLICY.SET") {
6014
6512
  return flowPolicySetPayload(commandArgs2) ?? commandExec(args);
@@ -6167,24 +6665,17 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
6167
6665
  if (command === "FLOW.RUN_STEPS_MANY") {
6168
6666
  return flowAdminPayload(OPCODES.flowRunStepsMany, commandArgs2) ?? commandExec(args);
6169
6667
  }
6170
- if (command === "FLOW.SEARCH") {
6171
- if (hasFlowCommandOnlyOption(command, commandArgs2)) {
6172
- const fallback = commandExec(args);
6173
- try {
6174
- const parsed = flowSearchPayload(commandArgs2);
6175
- return parsed == null ? fallback : withFlowPartitionRouting(fallback, parsed.payload);
6176
- } catch {
6177
- return fallback;
6178
- }
6179
- }
6180
- return flowSearchPayload(commandArgs2) ?? commandExec(args);
6181
- }
6182
6668
  return commandExec(args);
6183
6669
  }
6184
6670
  function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6185
6671
  const compact = compactPipelinePayload(commands, maxBodyBytes);
6186
6672
  if (compact != null) {
6187
- 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
+ };
6188
6679
  }
6189
6680
  const protocols = new Array(commands.length);
6190
6681
  for (let index = 0; index < commands.length; index += 1) {
@@ -6223,6 +6714,7 @@ function tryPipelineCommand(commands, maxBodyBytes = Number.MAX_SAFE_INTEGER) {
6223
6714
  const pipelineClaimModes = pipelineProtocols.map((protocol) => protocol.compactClaimMode);
6224
6715
  const hasPipelineClaimMode = pipelineClaimModes.some((mode) => mode != null);
6225
6716
  return {
6717
+ compactResponseItems: commands.length,
6226
6718
  opcode: OPCODES.pipeline,
6227
6719
  payload: {
6228
6720
  atomicity: "none",
@@ -6271,7 +6763,7 @@ import "net";
6271
6763
  import "tls";
6272
6764
 
6273
6765
  // src/client-native-options.ts
6274
- import { Buffer as Buffer24 } from "buffer";
6766
+ import { Buffer as Buffer28 } from "buffer";
6275
6767
 
6276
6768
  // src/string-array-snapshot.ts
6277
6769
  function snapshotOwnStringArray(values, name) {
@@ -6354,7 +6846,7 @@ function snapshotTlsOptions(options) {
6354
6846
  return Object.freeze(snapshot);
6355
6847
  }
6356
6848
  function snapshotTlsValue(value, name) {
6357
- if (Buffer24.isBuffer(value)) return Buffer24.from(value);
6849
+ if (Buffer28.isBuffer(value)) return Buffer28.from(value);
6358
6850
  if (value instanceof Uint8Array) return value.slice();
6359
6851
  if (Array.isArray(value)) {
6360
6852
  const snapshot = new Array(value.length);
@@ -7209,7 +7701,7 @@ var NativeResponseHandler = class {
7209
7701
  compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
7210
7702
  });
7211
7703
  if (frame.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
7212
- const event = {
7704
+ const event2 = {
7213
7705
  flags: frame.flags,
7214
7706
  laneId: frame.laneId,
7215
7707
  opcode: frame.opcode,
@@ -7217,7 +7709,7 @@ var NativeResponseHandler = class {
7217
7709
  };
7218
7710
  if (frame.opcode === OPCODES.goaway) this.options.beginDraining();
7219
7711
  try {
7220
- const callback = this.options.onEvent?.(event);
7712
+ const callback = this.options.onEvent?.(event2);
7221
7713
  if (callback != null) void Promise.resolve(callback).catch(() => void 0);
7222
7714
  } catch {
7223
7715
  }
@@ -7381,12 +7873,14 @@ var NativeConnectionCapabilities = class {
7381
7873
  }
7382
7874
  configuredRequestFrameBytes;
7383
7875
  compactResponseOpcodes = EMPTY_COMPACT_RESPONSE_OPCODES;
7876
+ flowQuery;
7384
7877
  requestFrameBytes;
7385
7878
  negotiatedRequestFrameBytes;
7386
7879
  apply(value) {
7387
7880
  const limits = startupLimits(value);
7388
7881
  const negotiation = nativeNegotiation(value);
7389
7882
  this.compactResponseOpcodes = negotiation.compactResponseOpcodes;
7883
+ this.flowQuery = negotiation.flowQuery;
7390
7884
  if (limits.frameBytes != null) {
7391
7885
  this.negotiatedRequestFrameBytes = Math.min(
7392
7886
  this.configuredRequestFrameBytes,
@@ -7406,6 +7900,19 @@ var NativeConnectionCapabilities = class {
7406
7900
  }
7407
7901
  };
7408
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
+
7409
7916
  // src/native-adapter.ts
7410
7917
  var NativeAdapter = class _NativeAdapter {
7411
7918
  socket;
@@ -7564,13 +8071,7 @@ var NativeAdapter = class _NativeAdapter {
7564
8071
  const response = await this.request({
7565
8072
  laneId: 0,
7566
8073
  opcode: OPCODES.startup,
7567
- payload: {
7568
- client_name: clientName ?? "ferricstore-typescript",
7569
- compact_flow_responses: true,
7570
- compression: "none",
7571
- driver_name: clientName ?? "ferricstore-typescript",
7572
- ...events == null || events.length === 0 ? {} : { events: [...events] }
7573
- }
8074
+ payload: nativeStartupPayload(clientName, events)
7574
8075
  });
7575
8076
  this.applyStartupLimits(response);
7576
8077
  const authRequired = field(response, "auth_required");
@@ -7630,6 +8131,7 @@ var NativeAdapter = class _NativeAdapter {
7630
8131
  if (!hasFlowControlCredit) this.pendingControlRequests += 1;
7631
8132
  this.pending.set(requestId, {
7632
8133
  ...command.compactClaimMode == null ? {} : { compactClaimMode: command.compactClaimMode },
8134
+ ...command.compactResponseItems == null ? {} : { compactResponseItems: command.compactResponseItems },
7633
8135
  hasFlowControlCredit,
7634
8136
  indefinite: timeoutMs == null,
7635
8137
  laneId,
@@ -7764,7 +8266,7 @@ function executeCommandArgs(executor, args) {
7764
8266
  import "buffer";
7765
8267
 
7766
8268
  // src/command-retry-policy.ts
7767
- import { Buffer as Buffer28 } from "buffer";
8269
+ import { Buffer as Buffer32 } from "buffer";
7768
8270
  function isCasMutation(args) {
7769
8271
  const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
7770
8272
  const name = commandName2(args[offset]);
@@ -7778,8 +8280,8 @@ function isCasMutation(args) {
7778
8280
  }
7779
8281
  function commandName2(value) {
7780
8282
  if (typeof value === "string") return value.toUpperCase();
7781
- if (Buffer28.isBuffer(value) || value instanceof Uint8Array) {
7782
- return Buffer28.from(value).toString("utf8").toUpperCase();
8283
+ if (Buffer32.isBuffer(value) || value instanceof Uint8Array) {
8284
+ return Buffer32.from(value).toString("utf8").toUpperCase();
7783
8285
  }
7784
8286
  return void 0;
7785
8287
  }
@@ -7994,16 +8496,88 @@ function normalizeNonNegativeInteger2(value, fallback) {
7994
8496
  import "buffer";
7995
8497
 
7996
8498
  // src/topology-routing.ts
7997
- import { Buffer as Buffer30 } from "buffer";
8499
+ import { Buffer as Buffer35 } from "buffer";
8500
+
8501
+ // src/flow-partition-route-cache.ts
8502
+ import { Buffer as Buffer34 } from "buffer";
7998
8503
  import { createHash } from "crypto";
7999
- var FLOW_PARTITION_ROUTE_CACHE_MAX = 1024;
8000
- 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
8001
8575
  function routingKeyFromProtocolPayload(name, command) {
8002
8576
  if (command.opcode < 256 || name === "CLUSTER.KEYSLOT" || name === "SHARDS" || name === "ROUTE") {
8003
8577
  return void 0;
8004
8578
  }
8005
8579
  if (isPlainObject3(command.payload)) {
8006
- for (const field2 of [
8580
+ for (const field3 of [
8007
8581
  "key",
8008
8582
  "partition_key",
8009
8583
  "id",
@@ -8013,8 +8587,8 @@ function routingKeyFromProtocolPayload(name, command) {
8013
8587
  "correlation_id",
8014
8588
  "scope"
8015
8589
  ]) {
8016
- const value = getField(command.payload, field2);
8017
- if (typeof value === "string" || Buffer30.isBuffer(value)) {
8590
+ const value = getField(command.payload, field3);
8591
+ if (typeof value === "string" || Buffer35.isBuffer(value)) {
8018
8592
  return value;
8019
8593
  }
8020
8594
  }
@@ -8048,6 +8622,7 @@ function flowRoutingData(name, args) {
8048
8622
  if (flowScheduleCommands.has(name)) {
8049
8623
  return void 0;
8050
8624
  }
8625
+ if (name === "FLOW.QUERY") return void 0;
8051
8626
  if (flowApprovalIdCommands.has(name)) {
8052
8627
  const id = flowArgs[0];
8053
8628
  return flowRoutingResult(flowLogicalPartitionRoutingKey(id));
@@ -8061,7 +8636,7 @@ function flowRoutingData(name, args) {
8061
8636
  if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
8062
8637
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
8063
8638
  }
8064
- if (Buffer30.isBuffer(partition)) {
8639
+ if (Buffer35.isBuffer(partition)) {
8065
8640
  const text3 = partition.toString("utf8").toUpperCase();
8066
8641
  if (text3 !== "AUTO" && text3 !== "MIXED") {
8067
8642
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
@@ -8152,46 +8727,17 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
8152
8727
  return { handled: false };
8153
8728
  }
8154
8729
  function isRoutingKey(value) {
8155
- return typeof value === "string" || Buffer30.isBuffer(value);
8156
- }
8157
- function flowLogicalPartitionRoutingKey(value) {
8158
- if (typeof value !== "string" && !Buffer30.isBuffer(value)) {
8159
- return void 0;
8160
- }
8161
- const bytes2 = Buffer30.isBuffer(value) ? value : Buffer30.from(value);
8162
- const text3 = bytes2.toString("utf8");
8163
- const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(text3);
8164
- if (autoMatch != null) {
8165
- const bucket = Number(autoMatch[1]);
8166
- if (bucket < 256) {
8167
- return `{fa:${bucket}}`;
8168
- }
8169
- }
8170
- const cacheKey = `${Buffer30.isBuffer(value) ? "b" : "s"}:${bytes2.toString("base64")}`;
8171
- const cached = flowPartitionRouteCache.get(cacheKey);
8172
- if (cached != null) {
8173
- flowPartitionRouteCache.delete(cacheKey);
8174
- flowPartitionRouteCache.set(cacheKey, cached);
8175
- return cached;
8176
- }
8177
- const digest = createHash("sha256").update(bytes2).digest("base64url");
8178
- const routeKey = `{f:${digest}}`;
8179
- if (flowPartitionRouteCache.size >= FLOW_PARTITION_ROUTE_CACHE_MAX) {
8180
- const oldest = flowPartitionRouteCache.keys().next().value;
8181
- if (oldest != null) flowPartitionRouteCache.delete(oldest);
8182
- }
8183
- flowPartitionRouteCache.set(cacheKey, routeKey);
8184
- return routeKey;
8730
+ return typeof value === "string" || Buffer35.isBuffer(value);
8185
8731
  }
8186
8732
  function flowAutoIdRoutingKey(value) {
8187
- if (typeof value !== "string" && !Buffer30.isBuffer(value)) {
8733
+ if (typeof value !== "string" && !Buffer35.isBuffer(value)) {
8188
8734
  return void 0;
8189
8735
  }
8190
- const bucket = (Buffer30.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
8736
+ const bucket = (Buffer35.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
8191
8737
  return `{fa:${bucket}}`;
8192
8738
  }
8193
8739
  function flowClaimLogicalPartitionRoutingKey(value) {
8194
- if (typeof value !== "string" && !Buffer30.isBuffer(value)) return void 0;
8740
+ if (typeof value !== "string" && !Buffer35.isBuffer(value)) return void 0;
8195
8741
  const selector = commandPart(value);
8196
8742
  if (selector === "AUTO" || selector === "ANY") return void 0;
8197
8743
  if (selector === "GLOBAL") return "{f}";
@@ -8206,7 +8752,7 @@ function singleShardFlowClaimPartitionKey(values) {
8206
8752
  return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
8207
8753
  }
8208
8754
  function singleShardKey(keys) {
8209
- if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer30.isBuffer(key))) {
8755
+ if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer35.isBuffer(key))) {
8210
8756
  return void 0;
8211
8757
  }
8212
8758
  const usable = keys;
@@ -8239,7 +8785,7 @@ function routedKeyGroups(keys, routeKey) {
8239
8785
  const groups = /* @__PURE__ */ new Map();
8240
8786
  for (let index = 0; index < keys.length; index += 1) {
8241
8787
  const key = keys[index];
8242
- if (typeof key !== "string" && !Buffer30.isBuffer(key)) return void 0;
8788
+ if (typeof key !== "string" && !Buffer35.isBuffer(key)) return void 0;
8243
8789
  const route = routeKey(key);
8244
8790
  const groupKey = `${route.endpointKey}\0${route.laneId}`;
8245
8791
  const group = groups.get(groupKey);
@@ -9011,15 +9557,15 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9011
9557
  this.adapterOptions = {
9012
9558
  ...adapterOptions,
9013
9559
  events: [.../* @__PURE__ */ new Set([...adapterOptions.events ?? [], "TOPOLOGY_CHANGED"])],
9014
- onEvent: (event) => {
9560
+ onEvent: (event2) => {
9015
9561
  try {
9016
- const callback = userOnEvent?.(event);
9562
+ const callback = userOnEvent?.(event2);
9017
9563
  if (callback != null) {
9018
9564
  void Promise.resolve(callback).catch(() => void 0);
9019
9565
  }
9020
9566
  } catch {
9021
9567
  }
9022
- if (!this.closed && nativeEventName(event) === "TOPOLOGY_CHANGED") {
9568
+ if (!this.closed && nativeEventName(event2) === "TOPOLOGY_CHANGED") {
9023
9569
  this.requestTopologyRefresh();
9024
9570
  }
9025
9571
  }
@@ -9328,7 +9874,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
9328
9874
  };
9329
9875
 
9330
9876
  // src/response-map-preservation.ts
9331
- import { Buffer as Buffer32 } from "buffer";
9877
+ import { Buffer as Buffer37 } from "buffer";
9332
9878
  function toStringKeyMapPreservingValues(value) {
9333
9879
  if (value == null) return void 0;
9334
9880
  const result = {};
@@ -9338,7 +9884,7 @@ function toStringKeyMapPreservingValues(value) {
9338
9884
  }
9339
9885
  return result;
9340
9886
  }
9341
- if (typeof value === "object" && !Array.isArray(value) && !Buffer32.isBuffer(value) && !(value instanceof Uint8Array)) {
9887
+ if (typeof value === "object" && !Array.isArray(value) && !Buffer37.isBuffer(value) && !(value instanceof Uint8Array)) {
9342
9888
  for (const [key, item] of Object.entries(value)) {
9343
9889
  setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
9344
9890
  }
@@ -9347,7 +9893,7 @@ function toStringKeyMapPreservingValues(value) {
9347
9893
  return void 0;
9348
9894
  }
9349
9895
  function normalizeMapStructurePreservingBytes(value) {
9350
- if (Buffer32.isBuffer(value) || value instanceof Uint8Array) return value;
9896
+ if (Buffer37.isBuffer(value) || value instanceof Uint8Array) return value;
9351
9897
  if (value instanceof Map) {
9352
9898
  const result = {};
9353
9899
  for (const [key, item] of value.entries()) {
@@ -9369,7 +9915,7 @@ function normalizeMapStructurePreservingBytes(value) {
9369
9915
  }
9370
9916
 
9371
9917
  // src/native-kv-responses.ts
9372
- import { Buffer as Buffer33 } from "buffer";
9918
+ import { Buffer as Buffer38 } from "buffer";
9373
9919
  function rateLimitResultFromResp(value) {
9374
9920
  if (!Array.isArray(value) || value.length !== 4) {
9375
9921
  throw new TypeError("RATELIMIT.ADD returned an unexpected response");
@@ -9426,13 +9972,13 @@ function fetchOrComputeResultFromResp(value, codec) {
9426
9972
  }
9427
9973
  function decodePayload(codec, value) {
9428
9974
  if (value == null) return null;
9429
- if (Buffer33.isBuffer(value)) return codec.decode(value);
9430
- if (value instanceof Uint8Array) return codec.decode(Buffer33.from(value));
9431
- if (typeof value === "string") return codec.decode(Buffer33.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));
9432
9978
  return normalizeRefMeta(value);
9433
9979
  }
9434
9980
  function requiredResponseString(value, context) {
9435
- if (typeof value !== "string" && !Buffer33.isBuffer(value) && !(value instanceof Uint8Array)) {
9981
+ if (typeof value !== "string" && !Buffer38.isBuffer(value) && !(value instanceof Uint8Array)) {
9436
9982
  throw new TypeError(`${context} returned an unexpected response`);
9437
9983
  }
9438
9984
  const result = text(value);
@@ -9449,7 +9995,7 @@ function requiredNonNegativeInteger(value, context) {
9449
9995
  return result;
9450
9996
  }
9451
9997
  function responseBytes(value, context) {
9452
- if (typeof value !== "string" && !Buffer33.isBuffer(value) && !(value instanceof Uint8Array)) {
9998
+ if (typeof value !== "string" && !Buffer38.isBuffer(value) && !(value instanceof Uint8Array)) {
9453
9999
  throw new TypeError(`${context} returned an unexpected response`);
9454
10000
  }
9455
10001
  return bytes(value);
@@ -9772,17 +10318,6 @@ function finiteNonNegativeInteger(value, fallback) {
9772
10318
  function finiteNonNegativeNumber(value, fallback) {
9773
10319
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, value);
9774
10320
  }
9775
- function appendReadOptions(args, options) {
9776
- append(args, "COUNT", options.count);
9777
- append(args, "PARTITION", options.partitionKey);
9778
- append(args, "FROM_MS", options.fromMs);
9779
- append(args, "TO_MS", options.toMs);
9780
- appendBool(args, "REV", options.rev);
9781
- append(args, "STATE", options.state);
9782
- appendBool(args, "TERMINAL_ONLY", options.terminalOnly);
9783
- appendBool(args, "INCLUDE_COLD", options.includeCold);
9784
- appendBool(args, "CONSISTENT_PROJECTION", options.consistentProjection);
9785
- }
9786
10321
  function appendAttributeQueryOptions(args, options) {
9787
10322
  append(args, "STATE", options.state);
9788
10323
  append(args, "PARTITION", options.partitionKey);
@@ -9836,22 +10371,6 @@ function appendAttributes(args, attributes) {
9836
10371
  args.push("ATTRIBUTE", name, value);
9837
10372
  }
9838
10373
  }
9839
- function appendSearchStateMeta(args, state, stateMeta) {
9840
- const entries = Object.entries(stateMeta ?? {});
9841
- if (entries.length === 0) {
9842
- return;
9843
- }
9844
- if (entries.every(([, value]) => isPlainObject5(value))) {
9845
- for (const [metaState, values] of entries) {
9846
- args.push("STATE_META", metaState, values);
9847
- }
9848
- return;
9849
- }
9850
- if (state == null) {
9851
- throw new Error("search stateMeta filters require state or nested state metadata");
9852
- }
9853
- args.push("STATE_META", state, stateMeta);
9854
- }
9855
10374
  function normalizeAdminResponse(value) {
9856
10375
  return normalizeRefMeta(value);
9857
10376
  }
@@ -10159,7 +10678,7 @@ function groupAutoPartitionItems(items) {
10159
10678
  }
10160
10679
 
10161
10680
  // src/client-values.ts
10162
- import { Buffer as Buffer34 } from "buffer";
10681
+ import { Buffer as Buffer39 } from "buffer";
10163
10682
  async function valueMGetEntries(client, refs, options = {}) {
10164
10683
  const refCount = refs.length;
10165
10684
  if (refCount === 0) {
@@ -10194,12 +10713,12 @@ async function valueMGetEntries(client, refs, options = {}) {
10194
10713
  const item = response[index];
10195
10714
  if (item == null) {
10196
10715
  entries[index] = { found: false };
10197
- } else if (Buffer34.isBuffer(item)) {
10716
+ } else if (Buffer39.isBuffer(item)) {
10198
10717
  entries[index] = { found: true, value: client.codec.decode(item) };
10199
10718
  } else if (item instanceof Uint8Array) {
10200
- entries[index] = { found: true, value: client.codec.decode(Buffer34.from(item)) };
10719
+ entries[index] = { found: true, value: client.codec.decode(Buffer39.from(item)) };
10201
10720
  } else if (typeof item === "string") {
10202
- entries[index] = { found: true, value: client.codec.decode(Buffer34.from(item)) };
10721
+ entries[index] = { found: true, value: client.codec.decode(Buffer39.from(item)) };
10203
10722
  } else {
10204
10723
  entries[index] = { found: true, value: item };
10205
10724
  }
@@ -10211,7 +10730,7 @@ async function valueMGetEntries(client, refs, options = {}) {
10211
10730
  import "buffer";
10212
10731
 
10213
10732
  // src/auto-batch-ordering.ts
10214
- import { Buffer as Buffer35 } from "buffer";
10733
+ import { Buffer as Buffer40 } from "buffer";
10215
10734
  function autoBatchOrderingPlan(batch) {
10216
10735
  const accesses = /* @__PURE__ */ new Map();
10217
10736
  const fallbackDependencies = [];
@@ -10326,13 +10845,13 @@ function flowManyAutoBatchIds(command, name) {
10326
10845
  return fixedFlowItemIds(
10327
10846
  command,
10328
10847
  mixed ? 4 : 3,
10329
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && Buffer35.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)])
10330
10849
  );
10331
10850
  }
10332
10851
  return fixedFlowItemIds(
10333
10852
  command,
10334
10853
  mixed ? 4 : 3,
10335
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer35.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)])
10336
10855
  );
10337
10856
  }
10338
10857
  function createManyAutoBatchIds(command) {
@@ -10345,7 +10864,7 @@ function createManyAutoBatchIds(command) {
10345
10864
  const ids = fixedFlowItemIds(
10346
10865
  command,
10347
10866
  width,
10348
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer35.isBuffer(command[itemIndex + width - 1]),
10867
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer40.isBuffer(command[itemIndex + width - 1]),
10349
10868
  markerIndex
10350
10869
  );
10351
10870
  if (ids != null) return ids;
@@ -10363,7 +10882,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
10363
10882
  let cursor = markerIndex + 2;
10364
10883
  for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
10365
10884
  const id = command[cursor];
10366
- if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer35.isBuffer(command[cursor + 2])) return void 0;
10885
+ if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer40.isBuffer(command[cursor + 2])) return void 0;
10367
10886
  ids.push(id);
10368
10887
  cursor += 3;
10369
10888
  const afterValues = skipExtendedNamedItems(command, cursor, true);
@@ -10382,7 +10901,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
10382
10901
  for (let index = 0; index < count; index += 1) {
10383
10902
  const name = command[firstItem + index * 2];
10384
10903
  const value = command[firstItem + index * 2 + 1];
10385
- if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer35.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
10904
+ if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer40.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
10386
10905
  }
10387
10906
  return firstItem + count * 2;
10388
10907
  }
@@ -10397,7 +10916,7 @@ function runStepsManyAutoBatchIds(command) {
10397
10916
  ids.push(item);
10398
10917
  continue;
10399
10918
  }
10400
- if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer35.isBuffer(item)) return void 0;
10919
+ if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer40.isBuffer(item)) return void 0;
10401
10920
  const id = item.id;
10402
10921
  if (!isAutoBatchResourceValue(id)) return void 0;
10403
10922
  ids.push(id);
@@ -10438,7 +10957,7 @@ function flowValuePutOwner(command, start) {
10438
10957
  }
10439
10958
  var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
10440
10959
  function isAutoBatchResourceValue(value) {
10441
- return typeof value === "string" || Buffer35.isBuffer(value);
10960
+ return typeof value === "string" || Buffer40.isBuffer(value);
10442
10961
  }
10443
10962
  function isFencingToken(value) {
10444
10963
  return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
@@ -10447,7 +10966,7 @@ function nonNegativeItemCount(value) {
10447
10966
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
10448
10967
  }
10449
10968
  function autoBatchResourceKey(namespace, value) {
10450
- return `${namespace}:${Buffer35.from(value).toString("base64")}`;
10969
+ return `${namespace}:${Buffer40.from(value).toString("base64")}`;
10451
10970
  }
10452
10971
  function autoBatchCommandName(command) {
10453
10972
  return commandView(command).name ?? null;
@@ -10823,7 +11342,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10823
11342
  const results = new Array(claimed.length);
10824
11343
  let cursor = 0;
10825
11344
  let failure;
10826
- const run = async () => {
11345
+ const run2 = async () => {
10827
11346
  while (failure == null) {
10828
11347
  const index = cursor;
10829
11348
  cursor += 1;
@@ -10836,7 +11355,7 @@ async function hydrateClaimedRecords(claimed, concurrency, hydrate) {
10836
11355
  }
10837
11356
  }
10838
11357
  };
10839
- 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));
10840
11359
  if (failure != null) {
10841
11360
  const hydratedItems = [];
10842
11361
  for (let index = 0; index < results.length; index += 1) {
@@ -10858,69 +11377,1037 @@ function claimFailure(error) {
10858
11377
  // src/client-flow-support.ts
10859
11378
  import "buffer";
10860
11379
 
10861
- // src/client-core.ts
10862
- import "buffer";
11380
+ // src/flow-query-builder.ts
11381
+ import { Buffer as Buffer43 } from "buffer";
10863
11382
 
10864
- // src/client-core-helpers.ts
10865
- import { Buffer as Buffer37 } from "buffer";
10866
- function bgsaveResponse(response) {
10867
- if ((typeof response === "string" || Buffer37.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
10868
- 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;
10869
11393
  }
10870
- return okResponse(response);
10871
- }
10872
- function clientNameResponse(response) {
10873
- return response == null ? null : textResponse(response, "CLIENT GETNAME");
10874
- }
10875
- function fetchOrComputeCompletionToken(options) {
10876
- if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
11394
+ if (nested.some(Boolean)) {
10877
11395
  throw new TypeError(
10878
- "fetch-or-compute completion requires computeToken"
11396
+ "stateMeta must be entirely flat or entirely nested by state"
10879
11397
  );
10880
11398
  }
10881
- if (!Buffer37.isBuffer(options.computeToken)) {
10882
- 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
+ );
10883
11403
  }
10884
- return options.computeToken;
11404
+ return { [state]: value };
10885
11405
  }
10886
- function concatCommandArgs(prefix, suffix) {
10887
- const args = new Array(prefix.length + suffix.length);
10888
- for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
10889
- for (let index = 0; index < suffix.length; index += 1) {
10890
- 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
+ }
10891
11420
  }
10892
- return args;
11421
+ return entries;
10893
11422
  }
10894
- function unsupportedClientTracking() {
10895
- throw new InvalidCommandError(
10896
- "CLIENT TRACKING is not supported by the FerricStore native protocol; use native event subscriptions"
10897
- );
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]]);
10898
11431
  }
10899
- function unsupportedClientCaching() {
10900
- 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;
10901
11438
  }
10902
-
10903
- // src/client-base.ts
10904
- import "buffer";
10905
-
10906
- // src/client-executor.ts
10907
- import "buffer";
10908
- var ErrorMappingExecutor = class {
10909
- constructor(executor) {
10910
- 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;
10911
11453
  }
10912
- executor;
10913
- async executeCommand(...args) {
10914
- 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;
10915
11467
  }
10916
- async executeCommandArgs(args) {
10917
- try {
10918
- return await executeCommandArgs(this.executor, args);
10919
- } catch (error) {
10920
- 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
+ );
10921
11496
  }
10922
11497
  }
10923
- async executePipeline(commands, options) {
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) {
10924
12411
  let results;
10925
12412
  try {
10926
12413
  if (this.executor.executePipeline != null) {
@@ -11238,14 +12725,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
11238
12725
  };
11239
12726
 
11240
12727
  // src/store-utilities.ts
11241
- import { Buffer as Buffer40 } from "buffer";
12728
+ import { Buffer as Buffer49 } from "buffer";
11242
12729
  function encode(codec, value) {
11243
12730
  return codec.encode(value);
11244
12731
  }
11245
12732
  function decode(codec, value) {
11246
12733
  if (value == null) return null;
11247
- if (Buffer40.isBuffer(value)) return codec.decode(value);
11248
- if (value instanceof Uint8Array) return codec.decode(Buffer40.from(value));
12734
+ if (Buffer49.isBuffer(value)) return codec.decode(value);
12735
+ if (value instanceof Uint8Array) return codec.decode(Buffer49.from(value));
11249
12736
  return value;
11250
12737
  }
11251
12738
  function number(value) {
@@ -11835,15 +13322,15 @@ function compressionOptions(options) {
11835
13322
  // src/store-decoders.ts
11836
13323
  function decodeHashRecord(codec, value) {
11837
13324
  const result = {};
11838
- for (const [field2, item] of hashPairs(value)) {
11839
- setOwnValue(result, textToken(field2), decode(codec, item));
13325
+ for (const [field3, item] of hashPairs(value)) {
13326
+ setOwnValue(result, textToken(field3), decode(codec, item));
11840
13327
  }
11841
13328
  return result;
11842
13329
  }
11843
13330
  function decodeHashFlatPairs(codec, value) {
11844
13331
  const result = [];
11845
- for (const [field2, item] of hashPairs(value)) {
11846
- result.push(textToken(field2), decode(codec, item));
13332
+ for (const [field3, item] of hashPairs(value)) {
13333
+ result.push(textToken(field3), decode(codec, item));
11847
13334
  }
11848
13335
  return result;
11849
13336
  }
@@ -11963,7 +13450,7 @@ function requiredPair(value, message) {
11963
13450
  }
11964
13451
  function decodeStreamFieldValues(codec, value) {
11965
13452
  const result = [];
11966
- 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));
11967
13454
  return result;
11968
13455
  }
11969
13456
  var geoSearchMetadataTokens = /* @__PURE__ */ new Set(["WITHCOORD", "WITHDIST", "WITHHASH"]);
@@ -12777,8 +14264,8 @@ var HashStore = class {
12777
14264
  async hset(key, entries) {
12778
14265
  return number(await commandArgs(this.client, keyValueArgs(["HSET", key], this.client.codec, entries)));
12779
14266
  }
12780
- async hget(key, field2) {
12781
- 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));
12782
14269
  }
12783
14270
  async hdel(key, ...fieldsOrArray) {
12784
14271
  const fields = requireNonEmpty(arrayOrRest(fieldsOrArray), "HDEL", "field");
@@ -12797,8 +14284,8 @@ var HashStore = class {
12797
14284
  async hgetall(key) {
12798
14285
  return decodeHashRecord(this.client.codec, await this.client.command("HGETALL", key));
12799
14286
  }
12800
- async hexists(key, field2) {
12801
- return binaryBooleanResponse(await this.client.command("HEXISTS", key, field2));
14287
+ async hexists(key, field3) {
14288
+ return binaryBooleanResponse(await this.client.command("HEXISTS", key, field3));
12802
14289
  }
12803
14290
  async hkeys(key) {
12804
14291
  return mapArray(await this.client.command("HKEYS", key), "HKEYS", textToken);
@@ -12813,17 +14300,17 @@ var HashStore = class {
12813
14300
  async hlen(key) {
12814
14301
  return number(await this.client.command("HLEN", key));
12815
14302
  }
12816
- async hincrby(key, field2, increment) {
12817
- 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));
12818
14305
  }
12819
- async hincrbyfloat(key, field2, increment) {
12820
- 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));
12821
14308
  }
12822
- async hsetnx(key, field2, value) {
12823
- 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)));
12824
14311
  }
12825
- async hstrlen(key, field2) {
12826
- return number(await this.client.command("HSTRLEN", key, field2));
14312
+ async hstrlen(key, field3) {
14313
+ return number(await this.client.command("HSTRLEN", key, field3));
12827
14314
  }
12828
14315
  async hrandfield(key, count, withValues = false) {
12829
14316
  if (withValues && count == null) {
@@ -13459,6 +14946,100 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
13459
14946
  }
13460
14947
  };
13461
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
+
13462
15043
  // src/producer-backpressure.ts
13463
15044
  async function executeProducerWriteWithBackpressure(execute, policy, signal) {
13464
15045
  for (let attempt = 0; ; attempt += 1) {
@@ -13481,7 +15062,7 @@ function throwIfClosed(signal) {
13481
15062
  }
13482
15063
 
13483
15064
  // src/flow-policy.ts
13484
- import { Buffer as Buffer42 } from "buffer";
15065
+ import { Buffer as Buffer51 } from "buffer";
13485
15066
  var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
13486
15067
  function assertFlowPolicyGeneration(value) {
13487
15068
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
@@ -13491,15 +15072,15 @@ function assertFlowPolicyGeneration(value) {
13491
15072
  function flowPolicySnapshotFromResp(value) {
13492
15073
  const policy = requiredRecord(value, "FLOW policy snapshot");
13493
15074
  const maxActiveMs = optionalPositiveInteger(field(policy, "max_active_ms"), "max_active_ms");
13494
- const state = optionalText2(field(policy, "state"), "state");
15075
+ const state = optionalText3(field(policy, "state"), "state");
13495
15076
  const mode = optionalMode(field(policy, "mode"), "mode");
13496
15077
  const version = optionalVersion(field(policy, "version"));
13497
- const indexedStateMeta = optionalText2(field(policy, "indexed_state_meta"), "indexed_state_meta");
15078
+ const indexedStateMeta = optionalText3(field(policy, "indexed_state_meta"), "indexed_state_meta");
13498
15079
  const governance = optionalRecord(field(policy, "governance"), "governance");
13499
15080
  const states = optionalStates(field(policy, "states"));
13500
15081
  return {
13501
- type: requiredText(field(policy, "type"), "type"),
13502
- generation: nonNegativeInteger(field(policy, "generation"), "generation"),
15082
+ type: requiredText3(field(policy, "type"), "type"),
15083
+ generation: nonNegativeInteger2(field(policy, "generation"), "generation"),
13503
15084
  ...state == null ? {} : { state },
13504
15085
  ...version == null ? {} : { version },
13505
15086
  ...mode == null ? {} : { mode },
@@ -13517,21 +15098,21 @@ function retrySnapshot(value, context) {
13517
15098
  const retry2 = requiredRecord(value, `FLOW policy ${context}`);
13518
15099
  const backoff = requiredRecord(field(retry2, "backoff"), `FLOW policy ${context}.backoff`);
13519
15100
  return {
13520
- maxRetries: nonNegativeInteger(field(retry2, "max_retries"), `${context}.max_retries`),
15101
+ maxRetries: nonNegativeInteger2(field(retry2, "max_retries"), `${context}.max_retries`),
13521
15102
  backoff: {
13522
15103
  kind: backoffKind(field(backoff, "kind"), `${context}.backoff.kind`),
13523
- baseMs: nonNegativeInteger(field(backoff, "base_ms"), `${context}.backoff.base_ms`),
13524
- maxMs: nonNegativeInteger(field(backoff, "max_ms"), `${context}.backoff.max_ms`),
13525
- jitterPct: nonNegativeInteger(field(backoff, "jitter_pct"), `${context}.backoff.jitter_pct`)
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`)
13526
15107
  },
13527
- exhaustedTo: requiredText(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
15108
+ exhaustedTo: requiredText3(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
13528
15109
  };
13529
15110
  }
13530
15111
  function retentionSnapshot(value, context) {
13531
15112
  const retention = requiredRecord(value, `FLOW policy ${context}`);
13532
15113
  return {
13533
- ttlMs: nonNegativeInteger(field(retention, "ttl_ms"), `${context}.ttl_ms`),
13534
- historyMaxEvents: nonNegativeInteger(
15114
+ ttlMs: nonNegativeInteger2(field(retention, "ttl_ms"), `${context}.ttl_ms`),
15115
+ historyMaxEvents: nonNegativeInteger2(
13535
15116
  field(retention, "history_max_events"),
13536
15117
  `${context}.history_max_events`
13537
15118
  )
@@ -13567,11 +15148,11 @@ function requiredRecord(value, context) {
13567
15148
  if (value instanceof Map) {
13568
15149
  const result = {};
13569
15150
  for (const [key, item] of value.entries()) {
13570
- setOwnValue(result, requiredText(key, `${context} key`), item);
15151
+ setOwnValue(result, requiredText3(key, `${context} key`), item);
13571
15152
  }
13572
15153
  return result;
13573
15154
  }
13574
- if (typeof value === "object" && value != null && !Array.isArray(value) && !Buffer42.isBuffer(value) && !(value instanceof Uint8Array)) return value;
15155
+ if (typeof value === "object" && value != null && !Array.isArray(value) && !Buffer51.isBuffer(value) && !(value instanceof Uint8Array)) return value;
13575
15156
  throw new TypeError(`${context} returned an unexpected response`);
13576
15157
  }
13577
15158
  function optionalRecord(value, context) {
@@ -13586,21 +15167,21 @@ function stringArray(value, context) {
13586
15167
  if (!Object.hasOwn(value, index)) {
13587
15168
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13588
15169
  }
13589
- result[index] = requiredText(value[index], `${context}[${index}]`);
15170
+ result[index] = requiredText3(value[index], `${context}[${index}]`);
13590
15171
  }
13591
15172
  return result;
13592
15173
  }
13593
- function requiredText(value, context) {
15174
+ function requiredText3(value, context) {
13594
15175
  if (typeof value === "string") return value;
13595
- if (Buffer42.isBuffer(value) || value instanceof Uint8Array) {
13596
- return Buffer42.from(value).toString("utf8");
15176
+ if (Buffer51.isBuffer(value) || value instanceof Uint8Array) {
15177
+ return Buffer51.from(value).toString("utf8");
13597
15178
  }
13598
15179
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13599
15180
  }
13600
- function optionalText2(value, context) {
13601
- return value == null ? void 0 : requiredText(value, context);
15181
+ function optionalText3(value, context) {
15182
+ return value == null ? void 0 : requiredText3(value, context);
13602
15183
  }
13603
- function nonNegativeInteger(value, context) {
15184
+ function nonNegativeInteger2(value, context) {
13604
15185
  let parsed;
13605
15186
  try {
13606
15187
  parsed = integer(value);
@@ -13612,26 +15193,26 @@ function nonNegativeInteger(value, context) {
13612
15193
  }
13613
15194
  function optionalPositiveInteger(value, context) {
13614
15195
  if (value == null) return void 0;
13615
- const parsed = nonNegativeInteger(value, context);
15196
+ const parsed = nonNegativeInteger2(value, context);
13616
15197
  if (parsed === 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13617
15198
  return parsed;
13618
15199
  }
13619
15200
  function optionalVersion(value) {
13620
15201
  if (value == null) return void 0;
13621
15202
  if (typeof value === "number" || typeof value === "bigint") {
13622
- return nonNegativeInteger(value, "version");
15203
+ return nonNegativeInteger2(value, "version");
13623
15204
  }
13624
- return requiredText(value, "version");
15205
+ return requiredText3(value, "version");
13625
15206
  }
13626
15207
  function backoffKind(value, context) {
13627
- const kind = requiredText(value, context).toLowerCase();
15208
+ const kind = requiredText3(value, context).toLowerCase();
13628
15209
  if (kind === "none" || kind === "fixed" || kind === "linear" || kind === "exponential") {
13629
15210
  return kind;
13630
15211
  }
13631
15212
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13632
15213
  }
13633
15214
  function requiredMode(value, context) {
13634
- const mode = requiredText(value, context).toLowerCase();
15215
+ const mode = requiredText3(value, context).toLowerCase();
13635
15216
  if (mode === "fifo" || mode === "parallel") return mode;
13636
15217
  throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
13637
15218
  }
@@ -13640,7 +15221,7 @@ function optionalMode(value, context) {
13640
15221
  }
13641
15222
 
13642
15223
  // src/client-flow-support.ts
13643
- var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
15224
+ var FerricStoreFlowSupportClient = class extends FerricStoreFlowQueryClient {
13644
15225
  async rewind(id, options = {}) {
13645
15226
  const partitionKey = options.partitionKey;
13646
15227
  const returnRecord = options.returnRecord === true;
@@ -13666,43 +15247,9 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13666
15247
  }
13667
15248
  return flowRecordFromResp(response, this.codec);
13668
15249
  }
13669
- async list(type, options = {}) {
13670
- return await this.indexQuery("FLOW.LIST", type, options);
13671
- }
13672
- async search(type, options = {}) {
13673
- const args = ["FLOW.SEARCH", type];
13674
- appendReadOptions(args, options);
13675
- appendAttributes(args, options.attributes);
13676
- appendSearchStateMeta(args, options.state, options.stateMeta);
13677
- const response = await this.commandArgs(args);
13678
- return this.records(requiredArrayResponse(response, "FLOW.SEARCH"));
13679
- }
13680
- async terminals(type, options = {}) {
13681
- return await this.indexQuery("FLOW.TERMINALS", type, options);
13682
- }
13683
- async failures(type, options = {}) {
13684
- return await this.indexQuery("FLOW.FAILURES", type, options);
13685
- }
13686
- async byParent(parentFlowId, options = {}) {
13687
- return await this.indexQuery("FLOW.BY_PARENT", parentFlowId, options);
13688
- }
13689
- async byRoot(rootFlowId, options = {}) {
13690
- return await this.indexQuery("FLOW.BY_ROOT", rootFlowId, options);
13691
- }
13692
- async byCorrelation(correlationId, options = {}) {
13693
- return await this.indexQuery("FLOW.BY_CORRELATION", correlationId, options);
13694
- }
13695
15250
  async info(type) {
13696
15251
  return parseKvResponse(await this.command("FLOW.INFO", type));
13697
15252
  }
13698
- async stuck(type, options = {}) {
13699
- const args = ["FLOW.STUCK", type];
13700
- append(args, "PARTITION", options.partitionKey);
13701
- append(args, "COUNT", options.count);
13702
- append(args, "OLDER_THAN", options.olderThanMs);
13703
- append(args, "NOW", options.nowMs);
13704
- return this.records(arrayResponse(await this.commandArgs(args)));
13705
- }
13706
15253
  async history(id, options = {}) {
13707
15254
  const args = ["FLOW.HISTORY", id];
13708
15255
  append(args, "PARTITION", options.partitionKey);
@@ -13832,16 +15379,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13832
15379
  }
13833
15380
  return record;
13834
15381
  }
13835
- records(values) {
13836
- const records = new Array(values.length);
13837
- for (let index = 0; index < values.length; index += 1) {
13838
- if (!Object.hasOwn(values, index)) {
13839
- throw new TypeError(`Flow record response item ${index} is missing`);
13840
- }
13841
- records[index] = flowRecordFromResp(values[index], this.codec);
13842
- }
13843
- return records;
13844
- }
13845
15382
  recordsOrResponse(value) {
13846
15383
  if (Array.isArray(value) && value.every(isRecordLike)) {
13847
15384
  return this.records(value);
@@ -13871,12 +15408,6 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13871
15408
  }
13872
15409
  return results;
13873
15410
  }
13874
- async indexQuery(command, key, options) {
13875
- const args = [command, key];
13876
- appendReadOptions(args, options);
13877
- const response = await this.commandArgs(args);
13878
- return this.records(requiredArrayResponse(response, command));
13879
- }
13880
15411
  appendPartitionOptions(args, options) {
13881
15412
  if (options.partitionKey != null && options.partitionKeys != null) {
13882
15413
  throw new Error("partitionKey and partitionKeys are mutually exclusive");
@@ -13899,7 +15430,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13899
15430
  };
13900
15431
 
13901
15432
  // src/flow-many-snapshot.ts
13902
- import { Buffer as Buffer44 } from "buffer";
15433
+ import { Buffer as Buffer53 } from "buffer";
13903
15434
  var encodedOptionFields = ["error", "payload", "reason", "result"];
13904
15435
  function snapshotCreateItem(item, codec) {
13905
15436
  const snapshot = {
@@ -13917,9 +15448,9 @@ function snapshotCreateItem(item, codec) {
13917
15448
  function snapshotFlowManyOptions(options, codec) {
13918
15449
  const snapshot = { ...options };
13919
15450
  const mutable = snapshot;
13920
- for (const field2 of encodedOptionFields) {
13921
- const value = options[field2];
13922
- 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);
13923
15454
  }
13924
15455
  if (options.attributes != null) mutable.attributes = snapshotCommandRecord(options.attributes);
13925
15456
  if (options.attributesMerge != null) {
@@ -13939,7 +15470,7 @@ function snapshotFlowManyOptions(options, codec) {
13939
15470
  }
13940
15471
  function snapshotClaimedItem(item) {
13941
15472
  const wire = item[CLAIMED_ITEM_WIRE];
13942
- const leaseToken = Buffer44.from(wire?.leaseToken ?? item.leaseToken);
15473
+ const leaseToken = Buffer53.from(wire?.leaseToken ?? item.leaseToken);
13943
15474
  const snapshot = {
13944
15475
  ...item,
13945
15476
  fencingToken: wire?.fencingToken ?? item.fencingToken,
@@ -13956,15 +15487,15 @@ function snapshotClaimedItem(item) {
13956
15487
  function snapshotFencedItem(item) {
13957
15488
  return Object.freeze({
13958
15489
  ...item,
13959
- ...item.leaseToken == null ? {} : { leaseToken: Buffer44.from(item.leaseToken) }
15490
+ ...item.leaseToken == null ? {} : { leaseToken: Buffer53.from(item.leaseToken) }
13960
15491
  });
13961
15492
  }
13962
15493
  function snapshotClaimedItemWire(wire, leaseToken) {
13963
15494
  return Object.freeze({
13964
15495
  fencingToken: wire.fencingToken,
13965
- id: Buffer44.from(wire.id),
15496
+ id: Buffer53.from(wire.id),
13966
15497
  leaseToken,
13967
- partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer44.from(wire.partitionKey)
15498
+ partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer53.from(wire.partitionKey)
13968
15499
  });
13969
15500
  }
13970
15501
  function snapshotArray(values) {
@@ -13975,7 +15506,7 @@ function snapshotArray(values) {
13975
15506
  return Object.freeze(snapshot);
13976
15507
  }
13977
15508
  function snapshotStateMeta(stateMeta) {
13978
- return snapshotRecord(stateMeta, (value) => Buffer44.isBuffer(value) ? Buffer44.from(value) : value);
15509
+ return snapshotRecord(stateMeta, (value) => Buffer53.isBuffer(value) ? Buffer53.from(value) : value);
13979
15510
  }
13980
15511
  function snapshotCommandRecord(values) {
13981
15512
  const seen = /* @__PURE__ */ new WeakMap();
@@ -13993,7 +15524,7 @@ function snapshotRecord(values, capture) {
13993
15524
  }
13994
15525
  function snapshotCommandArgument(value, seen) {
13995
15526
  if (typeof value !== "object" || value == null) return value;
13996
- if (Buffer44.isBuffer(value) || value instanceof Uint8Array) return Buffer44.from(value);
15527
+ if (Buffer53.isBuffer(value) || value instanceof Uint8Array) return Buffer53.from(value);
13997
15528
  const objectValue = value;
13998
15529
  const existing = seen.get(objectValue);
13999
15530
  if (existing != null) return existing;
@@ -14980,6 +16511,142 @@ function nativeOptionsForBootstrap(options, signal) {
14980
16511
  };
14981
16512
  }
14982
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
+
14983
16650
  // src/outcomes.ts
14984
16651
  var OUTCOME_BRAND = /* @__PURE__ */ Symbol("ferricstore.outcome");
14985
16652
  function transition(toState, options = {}) {
@@ -15059,7 +16726,7 @@ var LeaseRenewalGuard = class {
15059
16726
  if (options.leaseRenewal === false) {
15060
16727
  return;
15061
16728
  }
15062
- 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)));
15063
16730
  this.timer = setLongInterval(() => this.renew(), intervalMs);
15064
16731
  this.timer.unref();
15065
16732
  }
@@ -15131,7 +16798,7 @@ function snapshotLeasedJob(job) {
15131
16798
  return snapshot;
15132
16799
  }
15133
16800
  function workerConcurrency(options) {
15134
- return positiveInteger(options.concurrency ?? options.workers, 1);
16801
+ return positiveInteger2(options.concurrency ?? options.workers, 1);
15135
16802
  }
15136
16803
  function workerRefillStrategy(options) {
15137
16804
  return options.refillStrategy === "wave" ? "wave" : "continuous";
@@ -15174,18 +16841,18 @@ function workerErrorPayload(error, options, codec) {
15174
16841
  }
15175
16842
  function workerBatchSize(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
15176
16843
  return Math.min(
15177
- positiveInteger(options.batchSize, 10),
15178
- positiveInteger(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
16844
+ positiveInteger2(options.batchSize, 10),
16845
+ positiveInteger2(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
15179
16846
  );
15180
16847
  }
15181
16848
  function workerClaimLimit(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
15182
16849
  return Math.min(workerBatchSize(options, flowManyBatchLimit), workerConcurrency(options));
15183
16850
  }
15184
16851
  function workerDrainBatches(options) {
15185
- return positiveInteger(options.claimDrainBatches, 1);
16852
+ return positiveInteger2(options.claimDrainBatches, 1);
15186
16853
  }
15187
16854
  function workerLeaseMs(options, fallback = 3e4) {
15188
- return positiveInteger(options.leaseMs, positiveInteger(fallback, 3e4));
16855
+ return positiveInteger2(options.leaseMs, positiveInteger2(fallback, 3e4));
15189
16856
  }
15190
16857
  function workerIdleSleepMs(options) {
15191
16858
  return nonNegativeDuration(options.idleSleepMs, 250);
@@ -15197,7 +16864,7 @@ function workerClaimBlockMs(options, useBlocking) {
15197
16864
  if (options.signal == null || !Number.isFinite(options.blockMs) || options.blockMs < 0) {
15198
16865
  return options.blockMs;
15199
16866
  }
15200
- const abortPollMs = positiveInteger(options.abortPollMs, 1e3);
16867
+ const abortPollMs = positiveInteger2(options.abortPollMs, 1e3);
15201
16868
  return options.blockMs === 0 ? abortPollMs : Math.min(Math.trunc(options.blockMs), abortPollMs);
15202
16869
  }
15203
16870
  function workerMaxIdleSleepMs(options, idleSleepMs = workerIdleSleepMs(options)) {
@@ -15208,14 +16875,14 @@ function nextWorkerIdleSleepMs(currentIdleSleepMs, maxIdleSleepMs) {
15208
16875
  return Math.min(maxIdleSleepMs, Math.max(1, currentIdleSleepMs * 2));
15209
16876
  }
15210
16877
  async function runContinuousWorkerPool(options) {
15211
- const concurrency = positiveInteger(options.concurrency, 1);
15212
- const maxClaimSize = positiveInteger(options.maxClaimSize, concurrency);
16878
+ const concurrency = positiveInteger2(options.concurrency, 1);
16879
+ const maxClaimSize = positiveInteger2(options.maxClaimSize, concurrency);
15213
16880
  const initialIdleSleepMs = nonNegativeDuration(options.idleSleepMs, 250);
15214
16881
  const maxIdleSleepMs = Math.max(
15215
16882
  initialIdleSleepMs,
15216
16883
  nonNegativeDuration(options.maxIdleSleepMs, 5e3)
15217
16884
  );
15218
- const refillDelayMs = nonNegativeInteger2(options.refillDelayMs, 0);
16885
+ const refillDelayMs = nonNegativeInteger3(options.refillDelayMs, 0);
15219
16886
  const active = /* @__PURE__ */ new Set();
15220
16887
  const pending = [];
15221
16888
  let pendingIndex = 0;
@@ -15331,10 +16998,10 @@ function normalizeWorkflowWorkerConfig(options) {
15331
16998
  ...captured
15332
16999
  });
15333
17000
  }
15334
- function positiveInteger(value, fallback) {
17001
+ function positiveInteger2(value, fallback) {
15335
17002
  return value == null || !Number.isFinite(value) ? fallback : Math.max(1, Math.trunc(value));
15336
17003
  }
15337
- function nonNegativeInteger2(value, fallback) {
17004
+ function nonNegativeInteger3(value, fallback) {
15338
17005
  return value == null || !Number.isFinite(value) ? fallback : Math.max(0, Math.trunc(value));
15339
17006
  }
15340
17007
  function nonNegativeDuration(value, fallback) {
@@ -16963,8 +18630,8 @@ var WorkflowWorker = class {
16963
18630
  };
16964
18631
 
16965
18632
  // src/version.ts
16966
- var FERRICSTORE_SDK_VERSION = "0.3.0";
16967
- var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.9.1";
18633
+ var FERRICSTORE_SDK_VERSION = "0.5.1";
18634
+ var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.0";
16968
18635
  var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16969
18636
  export {
16970
18637
  BitmapStore,
@@ -16982,6 +18649,8 @@ export {
16982
18649
  FlowAlreadyExistsError,
16983
18650
  FlowBatchError,
16984
18651
  FlowNotFoundError,
18652
+ FlowProjection,
18653
+ FlowQueryError,
16985
18654
  FlowWrongStateError,
16986
18655
  GeoStore,
16987
18656
  HashStore,
@@ -17024,6 +18693,7 @@ export {
17024
18693
  isOutcome,
17025
18694
  isReconnectableClosedConnectionError,
17026
18695
  mapException,
18696
+ projectFlowQuery,
17027
18697
  retry,
17028
18698
  transition
17029
18699
  };