@ferricstore/ferricstore 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +17 -5
  2. package/dist/index.cjs +869 -548
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +29 -30
  5. package/dist/index.d.ts +29 -30
  6. package/dist/index.js +856 -537
  7. package/dist/index.js.map +1 -1
  8. package/docs/api/assets/hierarchy.js +1 -1
  9. package/docs/api/assets/navigation.js +1 -1
  10. package/docs/api/assets/search.js +1 -1
  11. package/docs/api/classes/ClaimHydrationError.html +5 -2
  12. package/docs/api/classes/ConnectionClosedError.html +6 -3
  13. package/docs/api/classes/FerricStoreClient.html +4 -4
  14. package/docs/api/classes/FerricStoreError.html +6 -3
  15. package/docs/api/classes/FlowAlreadyExistsError.html +6 -3
  16. package/docs/api/classes/FlowBatchError.html +6 -3
  17. package/docs/api/classes/FlowNotFoundError.html +6 -3
  18. package/docs/api/classes/FlowWrongStateError.html +6 -3
  19. package/docs/api/classes/InvalidCommandError.html +6 -3
  20. package/docs/api/classes/KeyValueStore.html +2 -2
  21. package/docs/api/classes/LeaseRenewalError.html +1 -1
  22. package/docs/api/classes/LockHeldError.html +6 -3
  23. package/docs/api/classes/LockNotOwnedError.html +6 -3
  24. package/docs/api/classes/NativeAdapter.html +2 -2
  25. package/docs/api/classes/OverloadedError.html +6 -4
  26. package/docs/api/classes/QueueCompletionError.html +1 -1
  27. package/docs/api/classes/RequestTimeoutError.html +6 -3
  28. package/docs/api/classes/RerouteError.html +6 -3
  29. package/docs/api/classes/StaleLeaseError.html +6 -3
  30. package/docs/api/classes/TDigestStore.html +2 -2
  31. package/docs/api/classes/TopKStore.html +1 -1
  32. package/docs/api/classes/TopologyNativeAdapterPool.html +1 -1
  33. package/docs/api/classes/Workflow.html +1 -1
  34. package/docs/api/functions/classifyServerError.html +1 -1
  35. package/docs/api/functions/mapException.html +1 -1
  36. package/docs/api/hierarchy.html +1 -1
  37. package/docs/api/index.html +16 -6
  38. package/docs/api/interfaces/AdminListOptions.html +1 -1
  39. package/docs/api/interfaces/CancelOptions.html +2 -2
  40. package/docs/api/interfaces/ClaimDueOptions.html +3 -3
  41. package/docs/api/interfaces/CompleteJobsAndClaimJobsResult.html +6 -6
  42. package/docs/api/interfaces/CompleteManyOptions.html +2 -2
  43. package/docs/api/interfaces/CompleteOptions.html +2 -2
  44. package/docs/api/interfaces/CompleteOutcome.html +1 -1
  45. package/docs/api/interfaces/CreateManyOptions.html +1 -1
  46. package/docs/api/interfaces/EffectCompensateOptions.html +1 -1
  47. package/docs/api/interfaces/EffectConfirmOptions.html +1 -1
  48. package/docs/api/interfaces/EffectFailOptions.html +1 -1
  49. package/docs/api/interfaces/EffectStatusOptions.html +1 -1
  50. package/docs/api/interfaces/ExtendLeaseOptions.html +2 -2
  51. package/docs/api/interfaces/FailOptions.html +2 -2
  52. package/docs/api/interfaces/FailOutcome.html +1 -1
  53. package/docs/api/interfaces/FerricStoreClientFromUrlOptions.html +1 -1
  54. package/docs/api/interfaces/FerricStoreClientOptions.html +1 -1
  55. package/docs/api/interfaces/{FetchOrComputeLegacyResult.html → FetchOrComputeComputeResult.html} +2 -2
  56. package/docs/api/interfaces/FlowMaxActiveFailure.html +3 -0
  57. package/docs/api/interfaces/FlowPolicyOptions.html +3 -3
  58. package/docs/api/interfaces/FlowRecord.html +4 -2
  59. package/docs/api/interfaces/FlowStatePolicy.html +2 -2
  60. package/docs/api/interfaces/HistoryOptions.html +2 -2
  61. package/docs/api/interfaces/InvocationCreateOptions.html +2 -2
  62. package/docs/api/interfaces/LeaseMutationOptions.html +2 -2
  63. package/docs/api/interfaces/LimitListOptions.html +1 -1
  64. package/docs/api/interfaces/MutateOptions.html +2 -2
  65. package/docs/api/interfaces/NamedValueMutation.html +1 -1
  66. package/docs/api/interfaces/ProtocolCommand.html +2 -2
  67. package/docs/api/interfaces/ReadOptions.html +2 -2
  68. package/docs/api/interfaces/ReclaimOptions.html +2 -2
  69. package/docs/api/interfaces/RequestContext.html +2 -2
  70. package/docs/api/interfaces/RequestContextOptions.html +2 -2
  71. package/docs/api/interfaces/RetryOptions.html +2 -2
  72. package/docs/api/interfaces/RetryOutcome.html +1 -1
  73. package/docs/api/interfaces/RunStepsItem.html +2 -2
  74. package/docs/api/interfaces/RunStepsManyOptions.html +2 -2
  75. package/docs/api/interfaces/SearchOptions.html +2 -2
  76. package/docs/api/interfaces/StartAndClaimOptions.html +4 -2
  77. package/docs/api/interfaces/StepContinueOptions.html +3 -3
  78. package/docs/api/interfaces/TDigestCreateOptions.html +1 -1
  79. package/docs/api/interfaces/TDigestMergeOptions.html +1 -1
  80. package/docs/api/interfaces/TransitionOptions.html +2 -2
  81. package/docs/api/interfaces/TransitionOutcome.html +1 -1
  82. package/docs/api/modules.html +1 -1
  83. package/docs/api/types/FetchOrComputeFencedResult.html +1 -0
  84. package/docs/api/types/FetchOrComputeResult.html +1 -1
  85. package/docs/api/types/FlowStateMode.html +1 -1
  86. package/docs/api/types/FlowStatePolicyLike.html +1 -1
  87. package/docs/api/types/ManagementPairs.html +1 -1
  88. package/docs/api/types/RequestDisposition.html +1 -1
  89. package/docs/api/types/SearchStateMeta.html +1 -1
  90. package/docs/api/types/TopKReserveOptions.html +1 -1
  91. package/docs/api/variables/COMMAND_OPCODES.html +1 -1
  92. package/docs/api/variables/FERRICSTORE_MINIMUM_SERVER_VERSION.html +2 -0
  93. package/docs/api/variables/FERRICSTORE_NATIVE_PROTOCOL_VERSION.html +2 -0
  94. package/docs/api/variables/FERRICSTORE_SDK_VERSION.html +2 -0
  95. package/package.json +6 -1
  96. package/docs/api/interfaces/FetchOrComputeFencedResult.html +0 -9
  97. package/docs/api/types/FetchOrComputeComputeResult.html +0 -1
  98. package/docs/api/variables/COMPACT_RESPONSE_OPCODES.html +0 -2
package/dist/index.js CHANGED
@@ -16,10 +16,16 @@ import "buffer";
16
16
  var FerricStoreError = class extends Error {
17
17
  code = "ferricstore_error";
18
18
  raw;
19
+ retryable;
20
+ safeToRetry;
21
+ retryAfterMs;
19
22
  constructor(message, options = {}) {
20
23
  super(message, { cause: options.cause });
21
24
  this.name = new.target.name;
22
25
  this.raw = options.raw;
26
+ this.retryable = options.retryable ?? structuredBooleanField(options.raw, "retryable");
27
+ this.safeToRetry = options.safeToRetry ?? structuredBooleanField(options.raw, "safe_to_retry");
28
+ this.retryAfterMs = options.retryAfterMs ?? structuredIntegerField(options.raw, "retry_after_ms");
23
29
  }
24
30
  };
25
31
  var ConnectionClosedError = class extends FerricStoreError {
@@ -66,11 +72,14 @@ var InvalidCommandError = class extends FerricStoreError {
66
72
  };
67
73
  var OverloadedError = class extends FerricStoreError {
68
74
  code = "overloaded";
69
- retryAfterMs;
70
75
  reason;
71
76
  constructor(message, options = {}) {
72
- super(message, options);
73
- this.retryAfterMs = options.retryAfterMs;
77
+ const local = options.raw == null;
78
+ super(message, {
79
+ ...options,
80
+ retryable: options.retryable ?? (local ? true : void 0),
81
+ safeToRetry: options.safeToRetry ?? (local ? true : void 0)
82
+ });
74
83
  this.reason = options.reason;
75
84
  }
76
85
  };
@@ -88,15 +97,21 @@ function classifyServerError(message, raw, cause, status) {
88
97
  const lower = message.toLowerCase();
89
98
  const structuredCode = structuredStringField(raw, "code");
90
99
  const code = structuredCode?.toLowerCase();
100
+ const retry2 = {
101
+ retryable: structuredBooleanField(raw, "retryable"),
102
+ safeToRetry: structuredBooleanField(raw, "safe_to_retry"),
103
+ retryAfterMs: structuredIntegerField(raw, "retry_after_ms") ?? intField(lower, "retry_after_ms")
104
+ };
91
105
  if (isRerouteStatus(status) || code === "reroute") {
92
- return new RerouteError(message, { cause, raw });
106
+ return new RerouteError(message, { cause, raw, ...definedRetryMetadata(retry2) });
93
107
  }
94
108
  if (isBusyStatus(status) || isOverloadCode(structuredCode) || overloadMessage(lower)) {
95
109
  return new OverloadedError(message, {
96
110
  cause,
97
111
  raw,
112
+ ...definedRetryMetadata(retry2),
98
113
  reason: structuredStringField(raw, "reason") ?? structuredCode ?? stringField(lower, "reason"),
99
- retryAfterMs: structuredIntegerField(raw, "retry_after_ms") ?? intField(lower, "retry_after_ms")
114
+ retryAfterMs: retry2.retryAfterMs
100
115
  });
101
116
  }
102
117
  if (code === "flow_already_exists" || lower.includes("flow") && lower.includes("already exists")) {
@@ -120,7 +135,7 @@ function classifyServerError(message, raw, cause, status) {
120
135
  if (code === "invalid_command" || lower.includes("wrong number of arguments") || lower.includes("syntax error")) {
121
136
  return new InvalidCommandError(message, { cause, raw });
122
137
  }
123
- return new FerricStoreError(message, { cause, raw });
138
+ return new FerricStoreError(message, { cause, raw, ...definedRetryMetadata(retry2) });
124
139
  }
125
140
  function mapException(error) {
126
141
  if (error instanceof FerricStoreError) {
@@ -160,8 +175,23 @@ function structuredIntegerField(raw, name) {
160
175
  if (typeof value === "bigint") {
161
176
  return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
162
177
  }
163
- const text2 = binaryText(value);
164
- return text2 == null ? void 0 : nonNegativeSafeIntegerText(text2);
178
+ const text3 = binaryText(value);
179
+ return text3 == null ? void 0 : nonNegativeSafeIntegerText(text3);
180
+ }
181
+ function structuredBooleanField(raw, name) {
182
+ const value = structuredField(raw, name);
183
+ if (typeof value === "boolean") return value;
184
+ const text3 = binaryText(value)?.toLowerCase();
185
+ if (text3 === "true" || text3 === "1") return true;
186
+ if (text3 === "false" || text3 === "0") return false;
187
+ return void 0;
188
+ }
189
+ function definedRetryMetadata(metadata) {
190
+ return {
191
+ ...metadata.retryable == null ? {} : { retryable: metadata.retryable },
192
+ ...metadata.safeToRetry == null ? {} : { safeToRetry: metadata.safeToRetry },
193
+ ...metadata.retryAfterMs == null ? {} : { retryAfterMs: metadata.retryAfterMs }
194
+ };
165
195
  }
166
196
  function nonNegativeSafeIntegerText(value) {
167
197
  if (!/^[0-9]+$/u.test(value)) return void 0;
@@ -334,9 +364,6 @@ function mapDenseResponseArray(value, transform) {
334
364
  return result;
335
365
  }
336
366
 
337
- // src/auto-partition.ts
338
- import { Buffer as Buffer3 } from "buffer";
339
-
340
367
  // src/crc32.ts
341
368
  import "buffer";
342
369
  var table = new Uint32Array(256);
@@ -354,12 +381,49 @@ function crc32(buffer) {
354
381
  }
355
382
  return (value ^ 4294967295) >>> 0;
356
383
  }
384
+ function crc32Utf8(text3, start = 0, end = text3.length) {
385
+ let value = 4294967295;
386
+ for (let index = start; index < end; index += 1) {
387
+ const first = text3.charCodeAt(index);
388
+ let point = first;
389
+ if (first >= 55296 && first <= 56319) {
390
+ const second = index + 1 < end ? text3.charCodeAt(index + 1) : 0;
391
+ if (second >= 56320 && second <= 57343) {
392
+ point = 65536 + (first - 55296 << 10) + second - 56320;
393
+ index += 1;
394
+ } else {
395
+ point = 65533;
396
+ }
397
+ } else if (first >= 56320 && first <= 57343) {
398
+ point = 65533;
399
+ }
400
+ if (point < 128) {
401
+ value = updateCrc32(value, point);
402
+ } else if (point < 2048) {
403
+ value = updateCrc32(value, 192 | point >>> 6);
404
+ value = updateCrc32(value, 128 | point & 63);
405
+ } else if (point < 65536) {
406
+ value = updateCrc32(value, 224 | point >>> 12);
407
+ value = updateCrc32(value, 128 | point >>> 6 & 63);
408
+ value = updateCrc32(value, 128 | point & 63);
409
+ } else {
410
+ value = updateCrc32(value, 240 | point >>> 18);
411
+ value = updateCrc32(value, 128 | point >>> 12 & 63);
412
+ value = updateCrc32(value, 128 | point >>> 6 & 63);
413
+ value = updateCrc32(value, 128 | point & 63);
414
+ }
415
+ }
416
+ return (value ^ 4294967295) >>> 0;
417
+ }
418
+ function updateCrc32(value, byte) {
419
+ return value >>> 8 ^ (table[(value ^ byte) & 255] ?? 0);
420
+ }
357
421
 
358
422
  // src/auto-partition.ts
359
423
  var AUTO_PARTITION_PREFIX = "__flow_auto__:";
360
424
  var AUTO_PARTITION_BUCKETS = 256;
361
425
  function autoPartitionKeyForId(id) {
362
- return `${AUTO_PARTITION_PREFIX}${crc32(Buffer3.from(id)) % AUTO_PARTITION_BUCKETS}`;
426
+ return `${AUTO_PARTITION_PREFIX}${crc32Utf8(id) % AUTO_PARTITION_BUCKETS}`;
363
427
  }
364
428
 
365
429
  // src/flow-argument-helpers.ts
@@ -752,7 +816,7 @@ function coerceDiagnosticValue(value) {
752
816
  // src/native-connection.ts
753
817
  import net from "net";
754
818
  import tls from "tls";
755
- import { Buffer as Buffer4 } from "buffer";
819
+ import { Buffer as Buffer3 } from "buffer";
756
820
  function parseFerricUrl(value) {
757
821
  const url = new URL(value);
758
822
  if (url.protocol !== "ferric:" && url.protocol !== "ferrics:") {
@@ -878,7 +942,7 @@ function nonNegativeSafeInteger(value) {
878
942
  if (typeof value === "bigint") {
879
943
  return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
880
944
  }
881
- const source = Buffer4.isBuffer(value) || value instanceof Uint8Array ? Buffer4.from(value).toString("utf8") : value;
945
+ const source = Buffer3.isBuffer(value) || value instanceof Uint8Array ? Buffer3.from(value).toString("utf8") : value;
882
946
  if (typeof source !== "number" && (typeof source !== "string" || !/^\d+$/u.test(source))) {
883
947
  return void 0;
884
948
  }
@@ -1112,10 +1176,10 @@ var NativeHeartbeat = class {
1112
1176
  };
1113
1177
 
1114
1178
  // src/protocol.ts
1115
- import { Buffer as Buffer19 } from "buffer";
1179
+ import { Buffer as Buffer22 } from "buffer";
1116
1180
 
1117
1181
  // src/command-grammar.ts
1118
- import { Buffer as Buffer5 } from "buffer";
1182
+ import { Buffer as Buffer4 } from "buffer";
1119
1183
 
1120
1184
  // src/command-metadata-flow.ts
1121
1185
  var flowStateIdCommands = /* @__PURE__ */ new Set([
@@ -1562,8 +1626,8 @@ var secondKeySubcommands = /* @__PURE__ */ new Map([
1562
1626
  ]);
1563
1627
  function commandToken(value) {
1564
1628
  if (typeof value === "string") return value.toUpperCase();
1565
- if (Buffer5.isBuffer(value) || value instanceof Uint8Array) {
1566
- return Buffer5.from(value).toString("utf8").toUpperCase();
1629
+ if (Buffer4.isBuffer(value) || value instanceof Uint8Array) {
1630
+ return Buffer4.from(value).toString("utf8").toUpperCase();
1567
1631
  }
1568
1632
  return void 0;
1569
1633
  }
@@ -1666,7 +1730,7 @@ function safeIntegerArgument(value) {
1666
1730
  if (typeof value === "bigint") {
1667
1731
  return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
1668
1732
  }
1669
- const source = typeof value === "string" ? value : Buffer5.isBuffer(value) || value instanceof Uint8Array ? Buffer5.from(value).toString("utf8") : void 0;
1733
+ const source = typeof value === "string" ? value : Buffer4.isBuffer(value) || value instanceof Uint8Array ? Buffer4.from(value).toString("utf8") : void 0;
1670
1734
  if (source == null || !/^[+-]?\d+$/u.test(source)) return void 0;
1671
1735
  const parsed = BigInt(source);
1672
1736
  return parsed >= BigInt(Number.MIN_SAFE_INTEGER) && parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : void 0;
@@ -1719,7 +1783,7 @@ function hasOwnCommandArgument(args, index, end, section) {
1719
1783
  }
1720
1784
 
1721
1785
  // src/protocol-core.ts
1722
- import { Buffer as Buffer9 } from "buffer";
1786
+ import { Buffer as Buffer8 } from "buffer";
1723
1787
 
1724
1788
  // src/protocol-constants.ts
1725
1789
  import "buffer";
@@ -1927,6 +1991,7 @@ var OPCODES = {
1927
1991
  flowFail: COMMAND_OPCODES["FLOW.FAIL"],
1928
1992
  flowValuePut: COMMAND_OPCODES["FLOW.VALUE.PUT"],
1929
1993
  flowValueMGet: COMMAND_OPCODES["FLOW.VALUE.MGET"],
1994
+ flowSignal: COMMAND_OPCODES["FLOW.SIGNAL"],
1930
1995
  flowCreateMany: COMMAND_OPCODES["FLOW.CREATE_MANY"],
1931
1996
  flowCompleteMany: COMMAND_OPCODES["FLOW.COMPLETE_MANY"],
1932
1997
  flowTransitionMany: COMMAND_OPCODES["FLOW.TRANSITION_MANY"],
@@ -1939,68 +2004,15 @@ var OPCODES = {
1939
2004
  flowRunStepsMany: COMMAND_OPCODES["FLOW.RUN_STEPS_MANY"],
1940
2005
  flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
1941
2006
  };
1942
- var COMPACT_RESPONSE_OPCODES = {
1943
- flow_claim_jobs_v1: [COMMAND_OPCODES["FLOW.CLAIM_DUE"]],
1944
- flow_record_list_v1: [
1945
- COMMAND_OPCODES["FLOW.LIST"],
1946
- COMMAND_OPCODES["FLOW.TERMINALS"],
1947
- COMMAND_OPCODES["FLOW.FAILURES"],
1948
- COMMAND_OPCODES["FLOW.BY_PARENT"],
1949
- COMMAND_OPCODES["FLOW.BY_ROOT"],
1950
- COMMAND_OPCODES["FLOW.BY_CORRELATION"],
1951
- COMMAND_OPCODES["FLOW.STUCK"]
1952
- ],
1953
- flow_record_v1: [COMMAND_OPCODES["FLOW.GET"]],
1954
- kv_get_v1: [COMMAND_OPCODES.GET],
1955
- kv_mget_v1: [COMMAND_OPCODES.MGET, COMMAND_OPCODES["FLOW.VALUE.MGET"]],
1956
- ok_list_v1: [
1957
- COMMAND_OPCODES.SET,
1958
- COMMAND_OPCODES.MSET,
1959
- COMMAND_OPCODES["FLOW.CREATE_MANY"],
1960
- COMMAND_OPCODES["FLOW.COMPLETE_MANY"],
1961
- COMMAND_OPCODES["FLOW.RETRY_MANY"],
1962
- COMMAND_OPCODES["FLOW.FAIL_MANY"],
1963
- COMMAND_OPCODES["FLOW.CANCEL_MANY"]
1964
- ],
1965
- pipeline_v1: [COMMAND_OPCODES.PIPELINE]
1966
- };
1967
- var COMPACT_KIND_FLOW_CLAIM_JOBS = 1 << 0;
1968
- var COMPACT_KIND_FLOW_RECORD = 1 << 1;
1969
- var COMPACT_KIND_FLOW_RECORD_LIST = 1 << 2;
1970
- var COMPACT_KIND_KV_GET = 1 << 3;
1971
- var COMPACT_KIND_KV_MGET = 1 << 4;
1972
- var COMPACT_KIND_OK_LIST = 1 << 5;
1973
- var COMPACT_KIND_PIPELINE = 1 << 6;
1974
- var compactResponseOpcodeKinds = new Uint8Array(
1975
- Math.max(...Object.values(COMPACT_RESPONSE_OPCODES).flat()) + 1
1976
- );
1977
- registerCompactResponseOpcodes(COMPACT_KIND_FLOW_CLAIM_JOBS, COMPACT_RESPONSE_OPCODES.flow_claim_jobs_v1);
1978
- registerCompactResponseOpcodes(COMPACT_KIND_FLOW_RECORD, COMPACT_RESPONSE_OPCODES.flow_record_v1);
1979
- registerCompactResponseOpcodes(COMPACT_KIND_FLOW_RECORD_LIST, COMPACT_RESPONSE_OPCODES.flow_record_list_v1);
1980
- registerCompactResponseOpcodes(COMPACT_KIND_KV_GET, COMPACT_RESPONSE_OPCODES.kv_get_v1);
1981
- registerCompactResponseOpcodes(COMPACT_KIND_KV_MGET, [
1982
- ...COMPACT_RESPONSE_OPCODES.kv_mget_v1,
1983
- COMMAND_OPCODES.PIPELINE
1984
- ]);
1985
- registerCompactResponseOpcodes(COMPACT_KIND_OK_LIST, [
1986
- ...COMPACT_RESPONSE_OPCODES.ok_list_v1,
1987
- COMMAND_OPCODES.PIPELINE
1988
- ]);
1989
- registerCompactResponseOpcodes(COMPACT_KIND_PIPELINE, COMPACT_RESPONSE_OPCODES.pipeline_v1);
1990
- function registerCompactResponseOpcodes(kind, opcodes) {
1991
- for (const opcode of opcodes) {
1992
- compactResponseOpcodeKinds[opcode] = (compactResponseOpcodeKinds[opcode] ?? 0) | kind;
1993
- }
1994
- }
1995
- function compactResponseOpcodeSupports(opcode, kind) {
1996
- return ((compactResponseOpcodeKinds[opcode] ?? 0) & kind) !== 0;
1997
- }
1998
2007
  var COMPACT_FLOW_CLAIM_JOBS = 128;
1999
2008
  var COMPACT_OK_LIST = 129;
2000
2009
  var COMPACT_KV_GET = 130;
2001
2010
  var COMPACT_KV_MGET = 131;
2002
2011
  var COMPACT_FLOW_RECORD = 132;
2003
2012
  var COMPACT_FLOW_RECORD_LIST = 133;
2013
+ var COMPACT_BINARY_LIST_LIST = 134;
2014
+ var COMPACT_BINARY_MAP_LIST = 135;
2015
+ var COMPACT_INTEGER_LIST = 136;
2004
2016
  var COMPACT_KV_MGET_FIXED = 137;
2005
2017
  var COMPACT_FLOW_CREATE_MANY_REQUEST = 144;
2006
2018
  var COMPACT_FLOW_CLAIM_DUE_REQUEST = 145;
@@ -2070,16 +2082,16 @@ var FLOW_RECORD_FIELD_KEYS = [
2070
2082
  ];
2071
2083
 
2072
2084
  // src/protocol-text.ts
2073
- import { Buffer as Buffer7 } from "buffer";
2085
+ import { Buffer as Buffer6 } from "buffer";
2074
2086
  function toBuffer(value) {
2075
- if (Buffer7.isBuffer(value)) return value;
2076
- if (value instanceof Uint8Array) return Buffer7.from(value);
2077
- if (typeof value === "string") return Buffer7.from(value);
2087
+ if (Buffer6.isBuffer(value)) return value;
2088
+ if (value instanceof Uint8Array) return Buffer6.from(value);
2089
+ if (typeof value === "string") return Buffer6.from(value);
2078
2090
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2079
- return Buffer7.from(String(value));
2091
+ return Buffer6.from(String(value));
2080
2092
  }
2081
- if (typeof value === "symbol") return Buffer7.from(value.description ?? value.toString());
2082
- if (value == null) return Buffer7.alloc(0);
2093
+ if (typeof value === "symbol") return Buffer6.from(value.description ?? value.toString());
2094
+ if (value == null) return Buffer6.alloc(0);
2083
2095
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2084
2096
  }
2085
2097
  function asText(value) {
@@ -2087,14 +2099,14 @@ function asText(value) {
2087
2099
  }
2088
2100
  function optionalText(value) {
2089
2101
  if (value == null || value === "") return void 0;
2090
- if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2102
+ if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || Buffer6.isBuffer(value) || value instanceof Uint8Array) {
2091
2103
  return asText(value);
2092
2104
  }
2093
2105
  return void 0;
2094
2106
  }
2095
2107
  function commandTokenIs(value, expected) {
2096
2108
  if (typeof value === "string") return value.toUpperCase() === expected;
2097
- if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2109
+ if (Buffer6.isBuffer(value) || value instanceof Uint8Array) {
2098
2110
  return asText(value).toUpperCase() === expected;
2099
2111
  }
2100
2112
  return false;
@@ -2108,7 +2120,7 @@ function commandNameIs(value, expected) {
2108
2120
  }
2109
2121
 
2110
2122
  // src/request-context.ts
2111
- import { Buffer as Buffer8 } from "buffer";
2123
+ import { Buffer as Buffer7 } from "buffer";
2112
2124
  var requestContextCommands = /* @__PURE__ */ new Set([
2113
2125
  "INVOCATION.CREATE",
2114
2126
  "INVOCATION.DEFINITION.GET",
@@ -2163,9 +2175,9 @@ function requestContextCommandToken(value) {
2163
2175
  const upper = value.toUpperCase();
2164
2176
  return isRequestContextCommand(upper) ? upper : void 0;
2165
2177
  }
2166
- if (Buffer8.isBuffer(value) || value instanceof Uint8Array) {
2178
+ if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2167
2179
  if (value[0] !== 73 && value[0] !== 105) return void 0;
2168
- const command = Buffer8.from(value).toString("utf8").toUpperCase();
2180
+ const command = Buffer7.from(value).toString("utf8").toUpperCase();
2169
2181
  return isRequestContextCommand(command) ? command : void 0;
2170
2182
  }
2171
2183
  return void 0;
@@ -2196,12 +2208,12 @@ function requestContextText(context, fieldName) {
2196
2208
  return value;
2197
2209
  }
2198
2210
  function isPlainObject(value) {
2199
- return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer8.isBuffer(value) && !(value instanceof Uint8Array);
2211
+ return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer7.isBuffer(value) && !(value instanceof Uint8Array);
2200
2212
  }
2201
2213
  function commandToken2(value) {
2202
2214
  if (typeof value === "string") return value.toUpperCase();
2203
- if (Buffer8.isBuffer(value) || value instanceof Uint8Array) {
2204
- return Buffer8.from(value).toString("utf8").toUpperCase();
2215
+ if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
2216
+ return Buffer7.from(value).toString("utf8").toUpperCase();
2205
2217
  }
2206
2218
  return "";
2207
2219
  }
@@ -2291,17 +2303,17 @@ function requestFrameTooLarge(maxBytes) {
2291
2303
  );
2292
2304
  }
2293
2305
  function binaryValueByteLength(value) {
2294
- if (Buffer9.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2295
- if (typeof value === "string") return Buffer9.byteLength(value);
2306
+ if (Buffer8.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
2307
+ if (typeof value === "string") return Buffer8.byteLength(value);
2296
2308
  if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2297
- return Buffer9.byteLength(String(value));
2309
+ return Buffer8.byteLength(String(value));
2298
2310
  }
2299
- if (typeof value === "symbol") return Buffer9.byteLength(value.description ?? value.toString());
2311
+ if (typeof value === "symbol") return Buffer8.byteLength(value.description ?? value.toString());
2300
2312
  if (value == null) return 0;
2301
2313
  return toBuffer(value).byteLength;
2302
2314
  }
2303
2315
  function writeCustomPayload(output, offset, value, knownByteLength) {
2304
- if (Buffer9.isBuffer(value)) {
2316
+ if (Buffer8.isBuffer(value)) {
2305
2317
  value.copy(output, offset);
2306
2318
  return;
2307
2319
  }
@@ -2310,17 +2322,17 @@ function writeCustomPayload(output, offset, value, knownByteLength) {
2310
2322
  return;
2311
2323
  }
2312
2324
  if (value == null) return;
2313
- let text2;
2325
+ let text3;
2314
2326
  if (typeof value === "string") {
2315
- text2 = value;
2327
+ text3 = value;
2316
2328
  } else if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
2317
- text2 = String(value);
2329
+ text3 = String(value);
2318
2330
  } else if (typeof value === "symbol") {
2319
- text2 = value.description ?? value.toString();
2331
+ text3 = value.description ?? value.toString();
2320
2332
  } else {
2321
2333
  throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
2322
2334
  }
2323
- output.write(text2, offset, knownByteLength ?? Buffer9.byteLength(text2), "utf8");
2335
+ output.write(text3, offset, knownByteLength ?? Buffer8.byteLength(text3), "utf8");
2324
2336
  }
2325
2337
  function compactBinaryEncodedLength(value) {
2326
2338
  return 4 + compactBinaryByteLength(value);
@@ -2333,10 +2345,10 @@ function compactBinaryByteLength(value) {
2333
2345
  return byteLength;
2334
2346
  }
2335
2347
  function isCompactBinaryArgument(value) {
2336
- return typeof value === "string" || Buffer9.isBuffer(value) || value instanceof Uint8Array;
2348
+ return typeof value === "string" || Buffer8.isBuffer(value) || value instanceof Uint8Array;
2337
2349
  }
2338
2350
  function isCompactBinaryScalar(value) {
2339
- return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" || Buffer9.isBuffer(value) || value instanceof Uint8Array;
2351
+ return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" || Buffer8.isBuffer(value) || value instanceof Uint8Array;
2340
2352
  }
2341
2353
  function compactOptionalBinaryEncodedLength(value) {
2342
2354
  return value == null ? 4 : compactBinaryEncodedLength(value);
@@ -2419,13 +2431,13 @@ function i64Arg(value) {
2419
2431
  }
2420
2432
  function boolArg(value) {
2421
2433
  if (typeof value === "boolean") return value;
2422
- const text2 = asText(value).toUpperCase();
2423
- return text2 === "1" || text2 === "TRUE" || text2 === "YES" || text2 === "ON";
2434
+ const text3 = asText(value).toUpperCase();
2435
+ return text3 === "1" || text3 === "TRUE" || text3 === "YES" || text3 === "ON";
2424
2436
  }
2425
2437
  function isBoolToken(value) {
2426
2438
  if (typeof value === "boolean") return true;
2427
- const text2 = asText(value).toUpperCase();
2428
- return text2 === "1" || text2 === "0" || text2 === "TRUE" || text2 === "FALSE" || text2 === "YES" || text2 === "NO" || text2 === "ON" || text2 === "OFF";
2439
+ const text3 = asText(value).toUpperCase();
2440
+ return text3 === "1" || text3 === "0" || text3 === "TRUE" || text3 === "FALSE" || text3 === "YES" || text3 === "NO" || text3 === "ON" || text3 === "OFF";
2429
2441
  }
2430
2442
  function independentMode(value) {
2431
2443
  if (value === true) return 2;
@@ -2467,7 +2479,23 @@ function setOwnValue2(target, key, value) {
2467
2479
  }
2468
2480
 
2469
2481
  // src/protocol-flow-options.ts
2470
- import { Buffer as Buffer10 } from "buffer";
2482
+ import { Buffer as Buffer9 } from "buffer";
2483
+
2484
+ // src/protocol-flow-option-value.ts
2485
+ function setFlowOptionValue(payload, field2, value, repeat) {
2486
+ if (!repeat || !Object.hasOwn(payload, field2)) {
2487
+ setOwnValue2(payload, field2, value);
2488
+ return;
2489
+ }
2490
+ const previous = payload[field2];
2491
+ setOwnValue2(
2492
+ payload,
2493
+ field2,
2494
+ Array.isArray(previous) ? [...previous, value] : [previous, value]
2495
+ );
2496
+ }
2497
+
2498
+ // src/protocol-flow-options.ts
2471
2499
  var OPTION_FIELDS = {
2472
2500
  CONSISTENT_PROJECTION: "consistent_projection",
2473
2501
  COUNT: "count",
@@ -2542,7 +2570,7 @@ function normalizeFlowSearchStateMeta(payload) {
2542
2570
  payload.state_meta = { [asText(state)]: stateMeta };
2543
2571
  }
2544
2572
  function isPlainObject2(value) {
2545
- return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer10.isBuffer(value) && !(value instanceof Uint8Array);
2573
+ return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer9.isBuffer(value) && !(value instanceof Uint8Array);
2546
2574
  }
2547
2575
  function parseFlowOptions(args, start, end, config) {
2548
2576
  const payload = {};
@@ -2636,8 +2664,9 @@ function parseFlowOptions(args, start, end, config) {
2636
2664
  case "TRANSITION_TO":
2637
2665
  case "TO_EVENT":
2638
2666
  case "EXPECT_STATE": {
2639
- const field2 = token.toLowerCase();
2640
- if (!putScalar(payload, field2, args, index + 1, end)) return void 0;
2667
+ const field2 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
2668
+ if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
2669
+ setFlowOptionValue(payload, field2, args[index + 1], token === "IF_STATE");
2641
2670
  index += 2;
2642
2671
  break;
2643
2672
  }
@@ -2927,6 +2956,7 @@ var FLOW_ADMIN_FIELDS = {
2927
2956
  LEASE_MS: "lease_ms",
2928
2957
  LEASE_TOKEN: "lease_token",
2929
2958
  LIMIT: "limit",
2959
+ MAX_ACTIVE_MS: "max_active_ms",
2930
2960
  MAX_FIRES: "max_fires",
2931
2961
  MAXBYTES: "payload_max_bytes",
2932
2962
  NOW: "now_ms",
@@ -2936,7 +2966,6 @@ var FLOW_ADMIN_FIELDS = {
2936
2966
  OVERLAP_RETRY_MS: "overlap_retry_ms",
2937
2967
  OVERWRITE: "overwrite",
2938
2968
  PARENT_FLOW_ID: "parent_flow_id",
2939
- PARENT_ID: "parent_id",
2940
2969
  PARTITION: "partition_key",
2941
2970
  PAYLOAD: "payload",
2942
2971
  PAYLOAD_MAX_BYTES: "payload_max_bytes",
@@ -2951,7 +2980,6 @@ var FLOW_ADMIN_FIELDS = {
2951
2980
  REV: "rev",
2952
2981
  RETURN: "return",
2953
2982
  ROOT_FLOW_ID: "root_flow_id",
2954
- ROOT_ID: "root_id",
2955
2983
  SCOPE: "scope",
2956
2984
  SHARD_ID: "shard_id",
2957
2985
  START_AT_MS: "start_at_ms",
@@ -3088,7 +3116,7 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
3088
3116
  }
3089
3117
 
3090
3118
  // src/protocol-flow-compact.ts
3091
- import { Buffer as Buffer12 } from "buffer";
3119
+ import { Buffer as Buffer11 } from "buffer";
3092
3120
 
3093
3121
  // src/protocol-flow-compact-common.ts
3094
3122
  function compactManyRequestTag(value, regularTag, okOnSuccessTag) {
@@ -3197,7 +3225,7 @@ function parseNamedCountMap(values, start) {
3197
3225
  }
3198
3226
 
3199
3227
  // src/protocol-flow-compact-transition.ts
3200
- import { Buffer as Buffer11 } from "buffer";
3228
+ import { Buffer as Buffer10 } from "buffer";
3201
3229
  function compactFlowTransitionManyPayload(partition, fromState, toState, rawItems, mixed, options, maxBodyBytes) {
3202
3230
  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) {
3203
3231
  return void 0;
@@ -3249,7 +3277,7 @@ function compactFlowTransitionManyPayload(partition, fromState, toState, rawItem
3249
3277
  total += 4 + idLength + 4 + itemPartitionLength + 8 + 4 + leaseLength;
3250
3278
  }
3251
3279
  assertCompactPayloadFits(total, maxBodyBytes);
3252
- const out = Buffer11.allocUnsafe(total);
3280
+ const out = Buffer10.allocUnsafe(total);
3253
3281
  let offset = 0;
3254
3282
  out.writeUInt8(tag, offset);
3255
3283
  offset += 1;
@@ -3307,7 +3335,7 @@ function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options,
3307
3335
  }
3308
3336
  assertCompactPayloadFits(total, maxBodyBytes);
3309
3337
  const tag = mixed ? COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST : auto ? COMPACT_FLOW_CREATE_MANY_REQUEST : COMPACT_FLOW_CREATE_MANY_PARTITION_REQUEST;
3310
- const out = Buffer12.allocUnsafe(total);
3338
+ const out = Buffer11.allocUnsafe(total);
3311
3339
  let offset = 0;
3312
3340
  out.writeUInt8(tag, offset++);
3313
3341
  offset = writeBinary(out, offset, toBuffer(options.type));
@@ -3352,7 +3380,7 @@ function compactFlowClaimDuePayload(type, options, maxBodyBytes) {
3352
3380
  total += 1;
3353
3381
  }
3354
3382
  assertCompactPayloadFits(total, maxBodyBytes);
3355
- const out = Buffer12.allocUnsafe(total);
3383
+ const out = Buffer11.allocUnsafe(total);
3356
3384
  let offset = 0;
3357
3385
  out.writeUInt8(COMPACT_FLOW_CLAIM_DUE_REQUEST, offset++);
3358
3386
  offset = writeBinary(out, offset, toBuffer(type));
@@ -3406,7 +3434,7 @@ function compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto
3406
3434
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3407
3435
  }
3408
3436
  assertCompactPayloadFits(total, maxBodyBytes);
3409
- const out = Buffer12.allocUnsafe(total);
3437
+ const out = Buffer11.allocUnsafe(total);
3410
3438
  let offset = 0;
3411
3439
  out.writeUInt8(
3412
3440
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_COMPLETE_MANY_OK_REQUEST : COMPACT_FLOW_COMPLETE_MANY_REQUEST,
@@ -3453,7 +3481,7 @@ function compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options,
3453
3481
  total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
3454
3482
  }
3455
3483
  assertCompactPayloadFits(total, maxBodyBytes);
3456
- const out = Buffer12.allocUnsafe(total);
3484
+ const out = Buffer11.allocUnsafe(total);
3457
3485
  let offset = 0;
3458
3486
  out.writeUInt8(
3459
3487
  returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_RETRY_MANY_OK_REQUEST : COMPACT_FLOW_RETRY_MANY_REQUEST,
@@ -3541,7 +3569,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
3541
3569
  total += 4 + idLength + 4 + itemPartitionLength + 8;
3542
3570
  }
3543
3571
  assertCompactPayloadFits(total, maxBodyBytes);
3544
- const out = Buffer12.allocUnsafe(total);
3572
+ const out = Buffer11.allocUnsafe(total);
3545
3573
  let offset = 0;
3546
3574
  out.writeUInt8(tag, offset);
3547
3575
  offset += 1;
@@ -3577,7 +3605,7 @@ function isOptionalSafeIntegerNumber(value) {
3577
3605
  }
3578
3606
 
3579
3607
  // src/protocol-flow-compact-single.ts
3580
- import { Buffer as Buffer13 } from "buffer";
3608
+ import { Buffer as Buffer12 } from "buffer";
3581
3609
  function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3582
3610
  if (refs.length > 4294967295 || maxBytes != null && (typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 0)) return void 0;
3583
3611
  const minimum = 13 + refs.length * 4;
@@ -3594,7 +3622,7 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
3594
3622
  total += 4 + byteLength;
3595
3623
  }
3596
3624
  assertCompactPayloadFits(total, maxBodyBytes);
3597
- const out = Buffer13.allocUnsafe(total);
3625
+ const out = Buffer12.allocUnsafe(total);
3598
3626
  let offset = 0;
3599
3627
  out.writeUInt8(COMPACT_FLOW_VALUE_MGET_REQUEST, offset);
3600
3628
  offset += 1;
@@ -3637,7 +3665,7 @@ function compactFlowListPayload(args, maxBodyBytes) {
3637
3665
  const stateLength = state == null ? 0 : compactBinaryByteLength(state);
3638
3666
  const total = 1 + 4 + typeLength + 4 + stateLength + 8 + 1;
3639
3667
  assertCompactPayloadFits(total, maxBodyBytes);
3640
- const out = Buffer13.allocUnsafe(total);
3668
+ const out = Buffer12.allocUnsafe(total);
3641
3669
  let offset = 0;
3642
3670
  out.writeUInt8(COMPACT_FLOW_LIST_REQUEST, offset);
3643
3671
  offset += 1;
@@ -4080,6 +4108,7 @@ function flowSpawnChildrenPayload(args) {
4080
4108
  "FROM_STATE",
4081
4109
  "ON_CHILD_FAILED",
4082
4110
  "ON_PARENT_CLOSED",
4111
+ "MAX_ACTIVE_MS",
4083
4112
  "VALUE",
4084
4113
  "VALUE_REF"
4085
4114
  ])
@@ -4110,6 +4139,29 @@ function flowSearchPayload(args) {
4110
4139
  return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
4111
4140
  }
4112
4141
 
4142
+ // src/protocol-flow-signal.ts
4143
+ function flowSignalPayload(args) {
4144
+ if (args.length < 3) return void 0;
4145
+ const options = parseFlowOptions(args, 1, args.length, {
4146
+ allowed: /* @__PURE__ */ new Set([
4147
+ "SIGNAL",
4148
+ "PARTITION",
4149
+ "IDEMPOTENCY",
4150
+ "IF_STATE",
4151
+ "TRANSITION_TO",
4152
+ "RUN_AT",
4153
+ "NOW",
4154
+ "VALUE",
4155
+ "VALUE_REF",
4156
+ "DROP_VALUE",
4157
+ "OVERRIDE_VALUE"
4158
+ ]),
4159
+ required: /* @__PURE__ */ new Set(["SIGNAL"])
4160
+ });
4161
+ if (options == null) return void 0;
4162
+ return { opcode: OPCODES.flowSignal, payload: { id: args[0], ...options } };
4163
+ }
4164
+
4113
4165
  // src/protocol-connection-policy.ts
4114
4166
  function assertCommandDoesNotRequirePinnedConnection(args) {
4115
4167
  const outer = commandName(args[0]);
@@ -4157,7 +4209,7 @@ function commandRequiresOrderedPipelineExecution(args) {
4157
4209
  }
4158
4210
 
4159
4211
  // src/protocol-compact-request.ts
4160
- import { Buffer as Buffer14 } from "buffer";
4212
+ import { Buffer as Buffer13 } from "buffer";
4161
4213
  function compactMsetPayload(args, maxBodyBytes) {
4162
4214
  if (args.length % 2 !== 0) throw new FerricStoreError("MSET requires key/value pairs");
4163
4215
  const minimum = 6 + args.length * 4;
@@ -4176,7 +4228,7 @@ function compactMsetPayload(args, maxBodyBytes) {
4176
4228
  total += 4 + byteLength;
4177
4229
  }
4178
4230
  assertCompactPayloadFits(total, maxBodyBytes);
4179
- const out = Buffer14.allocUnsafe(total);
4231
+ const out = Buffer13.allocUnsafe(total);
4180
4232
  let offset = writeCompactPipelineHeader(out, 1, args.length / 2);
4181
4233
  for (let index = 0; index < args.length; index += 1) {
4182
4234
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4200,7 +4252,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4200
4252
  total += 4 + byteLength;
4201
4253
  }
4202
4254
  assertCompactPayloadFits(total, maxBodyBytes);
4203
- const out = Buffer14.allocUnsafe(total);
4255
+ const out = Buffer13.allocUnsafe(total);
4204
4256
  let offset = writeCompactPipelineHeader(out, mode, args.length);
4205
4257
  for (let index = 0; index < args.length; index += 1) {
4206
4258
  offset = writeBinaryValue(out, offset, args[index], byteLengths[index] ?? 0);
@@ -4210,7 +4262,7 @@ function compactKeyPipelinePayload(opcode, args, mode, maxBodyBytes) {
4210
4262
  function compactPipelinePayload(commands, maxBodyBytes) {
4211
4263
  if (commands.length === 0) {
4212
4264
  assertCompactPayloadFits(6, maxBodyBytes);
4213
- const out = Buffer14.allocUnsafe(6);
4265
+ const out = Buffer13.allocUnsafe(6);
4214
4266
  writeCompactPipelineHeader(out, 128 | 2, 0);
4215
4267
  return out;
4216
4268
  }
@@ -4252,7 +4304,7 @@ function compactSetPipelinePayload(commands, maxBodyBytes) {
4252
4304
  total += 8 + keyByteLength + valueByteLength;
4253
4305
  }
4254
4306
  assertCompactPayloadFits(total, maxBodyBytes);
4255
- const out = Buffer14.allocUnsafe(total);
4307
+ const out = Buffer13.allocUnsafe(total);
4256
4308
  let offset = writeCompactPipelineHeader(out, 128 | 1, commands.length);
4257
4309
  for (let index = 0; index < commands.length; index += 1) {
4258
4310
  offset = writeBinaryValue(out, offset, argumentValues[index * 2], argumentByteLengths[index * 2] ?? 0);
@@ -4287,7 +4339,7 @@ function compactGetPipelinePayload(commands, maxBodyBytes) {
4287
4339
  total += 4 + keyByteLength;
4288
4340
  }
4289
4341
  assertCompactPayloadFits(total, maxBodyBytes);
4290
- const out = Buffer14.allocUnsafe(total);
4342
+ const out = Buffer13.allocUnsafe(total);
4291
4343
  let offset = writeCompactPipelineHeader(out, 128 | 2, commands.length);
4292
4344
  for (let index = 0; index < commands.length; index += 1) {
4293
4345
  offset = writeBinaryValue(out, offset, keys[index], keyByteLengths[index] ?? 0);
@@ -4328,7 +4380,7 @@ function writeCompactPipelineHeader(out, mode, count) {
4328
4380
  }
4329
4381
 
4330
4382
  // src/protocol-kv.ts
4331
- import { Buffer as Buffer15 } from "buffer";
4383
+ import { Buffer as Buffer14 } from "buffer";
4332
4384
  function collectionProtocolCommand(command, args) {
4333
4385
  switch (command) {
4334
4386
  case "CAS":
@@ -4476,15 +4528,20 @@ function fetchOrComputeCommand(args) {
4476
4528
  };
4477
4529
  }
4478
4530
  function fetchOrComputeResultCommand(args) {
4479
- if (args.length !== 4 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1])) return void 0;
4531
+ if (args.length !== 4 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1])) {
4532
+ throw new FerricStoreError("FETCH_OR_COMPUTE_RESULT requires key, ownership token, value, and ttl_ms");
4533
+ }
4480
4534
  const ttlMs = positiveSafeInteger2(args[3]);
4481
- return ttlMs == null ? void 0 : {
4535
+ if (ttlMs == null) throw new FerricStoreError("FETCH_OR_COMPUTE_RESULT ttl_ms must be positive");
4536
+ return {
4482
4537
  opcode: COMMAND_OPCODES.FETCH_OR_COMPUTE_RESULT,
4483
4538
  payload: { key: args[0], token: args[1], ttl_ms: ttlMs, value: args[2] }
4484
4539
  };
4485
4540
  }
4486
4541
  function fetchOrComputeErrorCommand(args) {
4487
- if (args.length !== 3 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1]) || !isBinaryCommandArgument(args[2])) return void 0;
4542
+ if (args.length !== 3 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1]) || !isBinaryCommandArgument(args[2])) {
4543
+ throw new FerricStoreError("FETCH_OR_COMPUTE_ERROR requires key, ownership token, and message");
4544
+ }
4488
4545
  return {
4489
4546
  opcode: COMMAND_OPCODES.FETCH_OR_COMPUTE_ERROR,
4490
4547
  payload: { key: args[0], message: args[2], token: args[1] }
@@ -4570,17 +4627,17 @@ function parsedNumber(value) {
4570
4627
  }
4571
4628
  }
4572
4629
  function isBinaryCommandArgument(value) {
4573
- return typeof value === "string" || Buffer15.isBuffer(value);
4630
+ return typeof value === "string" || Buffer14.isBuffer(value);
4574
4631
  }
4575
4632
  function isDirectKvValueArgument(value) {
4576
4633
  return isBinaryCommandArgument(value) || typeof value === "object" && value != null;
4577
4634
  }
4578
4635
  function binaryToken(value) {
4579
- return typeof value === "string" ? value.toUpperCase() : Buffer15.isBuffer(value) ? value.toString("utf8").toUpperCase() : void 0;
4636
+ return typeof value === "string" ? value.toUpperCase() : Buffer14.isBuffer(value) ? value.toString("utf8").toUpperCase() : void 0;
4580
4637
  }
4581
4638
 
4582
4639
  // src/protocol-value.ts
4583
- import { Buffer as Buffer16 } from "buffer";
4640
+ import { Buffer as Buffer15 } from "buffer";
4584
4641
  function planValueWithLimit(value, maxBytes) {
4585
4642
  const budget = {
4586
4643
  maxBytes,
@@ -4635,7 +4692,7 @@ function planContainerValue(value, budget, ancestors, depth) {
4635
4692
  let byteLength = 5;
4636
4693
  let index = 0;
4637
4694
  for (const [key, item] of entries) {
4638
- const keyByteLength = Buffer16.byteLength(key);
4695
+ const keyByteLength = Buffer15.byteLength(key);
4639
4696
  consumeEncodeBytes(budget, 4 + keyByteLength);
4640
4697
  const valuePlan = planValueAt(item, budget, ancestors, depth + 1);
4641
4698
  entryPlans[index] = { key, keyByteLength, value: valuePlan };
@@ -4684,7 +4741,7 @@ function planScalarValue(value, budget) {
4684
4741
  consumeEncodeBytes(budget, 9);
4685
4742
  return { byteLength: 9, tag: 7, value };
4686
4743
  }
4687
- if (typeof value === "string" || Buffer16.isBuffer(value) || value instanceof Uint8Array) {
4744
+ if (typeof value === "string" || Buffer15.isBuffer(value) || value instanceof Uint8Array) {
4688
4745
  const valueByteLength = binaryValueByteLength(value);
4689
4746
  const byteLength = 5 + valueByteLength;
4690
4747
  consumeEncodeBytes(budget, byteLength);
@@ -4708,7 +4765,7 @@ function writeValuePlan(output, start, plan) {
4708
4765
  offset += 4;
4709
4766
  if (typeof plan.value === "string") {
4710
4767
  output.write(plan.value, offset, plan.valueByteLength, "utf8");
4711
- } else if (Buffer16.isBuffer(plan.value)) {
4768
+ } else if (Buffer15.isBuffer(plan.value)) {
4712
4769
  plan.value.copy(output, offset);
4713
4770
  } else {
4714
4771
  output.set(plan.value, offset);
@@ -4841,58 +4898,458 @@ function requireAvailable(data, offset, size) {
4841
4898
  }
4842
4899
  }
4843
4900
 
4901
+ // src/key-slot-validation.ts
4902
+ import { Buffer as Buffer17 } from "buffer";
4903
+
4904
+ // src/topology-utilities.ts
4905
+ import { Buffer as Buffer16 } from "buffer";
4906
+ function isPlainObject3(value) {
4907
+ return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer16.isBuffer(value);
4908
+ }
4909
+ function getField(source, ...keys) {
4910
+ if (source instanceof Map) {
4911
+ for (const key of keys) {
4912
+ if (source.has(key)) return source.get(key);
4913
+ const bufferKey = Buffer16.from(key);
4914
+ for (const [itemKey, value] of source.entries()) {
4915
+ if (Buffer16.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
4916
+ }
4917
+ }
4918
+ return void 0;
4919
+ }
4920
+ if (isPlainObject3(source)) {
4921
+ for (const key of keys) {
4922
+ if (Object.hasOwn(source, key)) return source[key];
4923
+ }
4924
+ }
4925
+ return void 0;
4926
+ }
4927
+ function textOrUndefined(value) {
4928
+ if (typeof value === "string") return value;
4929
+ if (Buffer16.isBuffer(value)) return value.toString("utf8");
4930
+ return void 0;
4931
+ }
4932
+ function numberOrUndefined(value) {
4933
+ return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
4934
+ }
4935
+ function nativeEventName(event) {
4936
+ return textOrUndefined(getField(event.value, "event"))?.toUpperCase();
4937
+ }
4938
+ function endpointFromRange(item) {
4939
+ const endpointValue = getField(item, "endpoint");
4940
+ if (endpointValue != null && !isPlainObject3(endpointValue) && !(endpointValue instanceof Map)) {
4941
+ throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
4942
+ }
4943
+ const raw = endpointValue ?? item;
4944
+ const host = textOrUndefined(getField(raw, "host", "native_host"));
4945
+ const nativePort = numberOrUndefined(getField(raw, "native_port"));
4946
+ if (host == null || !validEndpointHost(host) || nativePort == null || nativePort <= 0 || nativePort > 65535) {
4947
+ throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
4948
+ }
4949
+ const nativeTlsPortValue = getField(raw, "native_tls_port");
4950
+ const nativeTlsPort = numberOrUndefined(nativeTlsPortValue);
4951
+ if (nativeTlsPortValue != null && (nativeTlsPort == null || nativeTlsPort <= 0 || nativeTlsPort > 65535)) {
4952
+ throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
4953
+ }
4954
+ return {
4955
+ host,
4956
+ nativePort,
4957
+ node: textOrUndefined(getField(raw, "node", "leader_node", "owner_node")) ?? host,
4958
+ ...nativeTlsPort == null ? {} : { nativeTlsPort }
4959
+ };
4960
+ }
4961
+ function validEndpointHost(host) {
4962
+ if (host.length === 0 || host.trim() !== host || /[\s\\/?#@]/u.test(host)) return false;
4963
+ const authorityHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
4964
+ try {
4965
+ const url = new URL(`ferric://${authorityHost}:6388`);
4966
+ return url.hostname !== "" && url.port === "6388" && url.username === "" && url.password === "";
4967
+ } catch {
4968
+ return false;
4969
+ }
4970
+ }
4971
+ function sameEndpoint(left, right) {
4972
+ return normalizedEndpointHost(left.host) === normalizedEndpointHost(right.host) && left.nativePort === right.nativePort && left.nativeTlsPort === right.nativeTlsPort && left.node === right.node;
4973
+ }
4974
+ function parseFerricUrl2(value) {
4975
+ const url = new URL(value);
4976
+ if (url.protocol !== "ferric:" && url.protocol !== "ferrics:") {
4977
+ throw new FerricStoreError(`unsupported FerricStore URL scheme: ${url.protocol}`);
4978
+ }
4979
+ return {
4980
+ host: normalizeFerricUrlHost(url.hostname),
4981
+ ...url.password === "" ? {} : { password: decodeURIComponent(url.password) },
4982
+ port: Number(url.port || (url.protocol === "ferrics:" ? 6389 : 6388)),
4983
+ tls: url.protocol === "ferrics:",
4984
+ ...url.username === "" ? {} : { username: decodeURIComponent(url.username) }
4985
+ };
4986
+ }
4987
+ function endpointKeyFor(endpoint) {
4988
+ return `${normalizedEndpointHost(endpoint.host)}:${endpoint.nativePort}`;
4989
+ }
4990
+ function connectionKeyForEndpoint(endpoint, useTls) {
4991
+ const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
4992
+ return `${useTls ? "ferrics" : "ferric"}://${normalizedEndpointHost(endpoint.host)}:${port}`;
4993
+ }
4994
+ function connectionKeyFromUrl(url) {
4995
+ const parsed = parseFerricUrl2(url);
4996
+ return `${parsed.tls ? "ferrics" : "ferric"}://${normalizedEndpointHost(parsed.host)}:${parsed.port}`;
4997
+ }
4998
+ function normalizedEndpointHost(host) {
4999
+ const lower = host.toLowerCase();
5000
+ return lower.startsWith("[") && lower.endsWith("]") ? lower.slice(1, -1) : lower;
5001
+ }
5002
+ function urlFromEndpoint(endpoint, useTls) {
5003
+ const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
5004
+ const host = endpoint.host.includes(":") && !endpoint.host.startsWith("[") ? `[${endpoint.host}]` : endpoint.host;
5005
+ return `${useTls ? "ferrics" : "ferric"}://${host}:${port}`;
5006
+ }
5007
+ async function mapSettledWithConcurrency(items, concurrency, operation) {
5008
+ const results = new Array(items.length);
5009
+ let nextIndex = 0;
5010
+ const worker = async () => {
5011
+ while (nextIndex < items.length) {
5012
+ const index = nextIndex++;
5013
+ const item = items[index];
5014
+ try {
5015
+ results[index] = { status: "fulfilled", value: await operation(item, index) };
5016
+ } catch (reason) {
5017
+ results[index] = { status: "rejected", reason };
5018
+ }
5019
+ }
5020
+ };
5021
+ await Promise.all(Array.from(
5022
+ { length: Math.min(concurrency, items.length) },
5023
+ async () => await worker()
5024
+ ));
5025
+ return results;
5026
+ }
5027
+ function throwFirstRejected(results) {
5028
+ for (const result of results) {
5029
+ if (result.status === "rejected") throw result.reason;
5030
+ }
5031
+ }
5032
+ var TaskConcurrencyLimiter = class {
5033
+ constructor(concurrency) {
5034
+ this.concurrency = concurrency;
5035
+ }
5036
+ concurrency;
5037
+ active = 0;
5038
+ head = 0;
5039
+ pending = [];
5040
+ async run(operation) {
5041
+ await this.acquire();
5042
+ try {
5043
+ return await operation();
5044
+ } finally {
5045
+ this.release();
5046
+ }
5047
+ }
5048
+ acquire() {
5049
+ if (this.active < this.concurrency) {
5050
+ this.active += 1;
5051
+ return Promise.resolve();
5052
+ }
5053
+ return new Promise((resolve) => this.pending.push(resolve));
5054
+ }
5055
+ release() {
5056
+ const next = this.pending[this.head];
5057
+ if (next == null) {
5058
+ this.active -= 1;
5059
+ return;
5060
+ }
5061
+ this.head += 1;
5062
+ next();
5063
+ if (this.head === this.pending.length) {
5064
+ this.pending.length = 0;
5065
+ this.head = 0;
5066
+ } else if (this.head >= 1024 && this.head * 2 >= this.pending.length) {
5067
+ this.pending.splice(0, this.head);
5068
+ this.head = 0;
5069
+ }
5070
+ }
5071
+ };
5072
+ function normalizedHostSet(hosts) {
5073
+ return new Set(
5074
+ hosts.filter((host) => host != null && host !== "").map((host) => normalizedEndpointHost(host))
5075
+ );
5076
+ }
5077
+ var OPEN_BRACE = "{".charCodeAt(0);
5078
+ var CLOSE_BRACE = "}".charCodeAt(0);
5079
+ function hashTagOrKey(key) {
5080
+ const start = key.indexOf(OPEN_BRACE);
5081
+ if (start < 0) return key;
5082
+ const end = key.indexOf(CLOSE_BRACE, start + 1);
5083
+ return end > start + 1 ? key.subarray(start + 1, end) : key;
5084
+ }
5085
+ var ROUTE_SLOT_MASK = 1023;
5086
+ function routingSlotForKey(key) {
5087
+ if (typeof key === "string") {
5088
+ const [start, end] = stringHashRange(key);
5089
+ return crc32Utf8(key, start, end) & ROUTE_SLOT_MASK;
5090
+ }
5091
+ const keyBytes = key;
5092
+ return crc32(hashTagOrKey(keyBytes)) & ROUTE_SLOT_MASK;
5093
+ }
5094
+ function stringHashRange(key) {
5095
+ const startBrace = key.indexOf("{");
5096
+ const endBrace = startBrace < 0 ? -1 : key.indexOf("}", startBrace + 1);
5097
+ return endBrace > startBrace + 1 ? [startBrace + 1, endBrace] : [0, key.length];
5098
+ }
5099
+
5100
+ // src/key-slot-validation.ts
5101
+ var validatedCommands = /* @__PURE__ */ new WeakSet();
5102
+ function assertAtomicKeyValueCommandSharesSlot(args) {
5103
+ const value = args[0];
5104
+ const command = (typeof value === "string" ? value : Buffer17.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
5105
+ if (command === "MSET" || command === "MSETNX") {
5106
+ assertKeyValueCommandSharesSlot(args, command);
5107
+ }
5108
+ }
5109
+ function assertKeyValueCommandSharesSlot(args, command) {
5110
+ if (validatedCommands.has(args) || args.length < 3 || args.length % 2 === 0) return;
5111
+ let expectedSlot;
5112
+ for (let index = 1; index < args.length; index += 2) {
5113
+ const key = args[index];
5114
+ if (typeof key !== "string" && !Buffer17.isBuffer(key)) return;
5115
+ const slot = routingSlotForKey(key);
5116
+ expectedSlot ??= slot;
5117
+ if (slot !== expectedSlot) {
5118
+ throw new TypeError(`${command} keys must share a slot`);
5119
+ }
5120
+ }
5121
+ validatedCommands.add(args);
5122
+ }
5123
+
4844
5124
  // src/protocol-response.ts
5125
+ import { Buffer as Buffer21 } from "buffer";
5126
+
5127
+ // src/protocol-compact-response.ts
5128
+ import { Buffer as Buffer20 } from "buffer";
5129
+
5130
+ // src/native-negotiation.ts
4845
5131
  import { Buffer as Buffer18 } from "buffer";
5132
+ var EMPTY_COMPACT_RESPONSE_OPCODES = /* @__PURE__ */ new Map();
5133
+ function nativeNegotiation(value) {
5134
+ const capabilities = field(value, "capabilities") ?? value;
5135
+ const limits = field(capabilities, "limits");
5136
+ const responseCodecs = field(capabilities, "response_codecs");
5137
+ const maxResponseBytes = positiveSafeInteger3(field(limits, "max_response_bytes"));
5138
+ return {
5139
+ compactResponseOpcodes: parseCompactResponseOpcodes(
5140
+ field(responseCodecs, "compact_response_opcodes")
5141
+ ),
5142
+ ...maxResponseBytes == null ? {} : { maxResponseBytes }
5143
+ };
5144
+ }
5145
+ function compactResponseOpcodeSupports(capabilities, codec, opcode) {
5146
+ return capabilities?.get(codec)?.has(opcode) === true;
5147
+ }
5148
+ function parseCompactResponseOpcodes(value) {
5149
+ const entries = mapEntries(value);
5150
+ if (entries == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
5151
+ const result = /* @__PURE__ */ new Map();
5152
+ for (const [rawName, rawOpcodes] of entries) {
5153
+ const name = text2(rawName);
5154
+ if (name == null || name.length === 0 || !Array.isArray(rawOpcodes)) continue;
5155
+ const opcodes = /* @__PURE__ */ new Set();
5156
+ let valid = true;
5157
+ for (let index = 0; index < rawOpcodes.length; index += 1) {
5158
+ if (!Object.hasOwn(rawOpcodes, index)) {
5159
+ valid = false;
5160
+ break;
5161
+ }
5162
+ const opcode = unsigned16(rawOpcodes[index]);
5163
+ if (opcode == null) {
5164
+ valid = false;
5165
+ break;
5166
+ }
5167
+ opcodes.add(opcode);
5168
+ }
5169
+ if (valid) result.set(name, opcodes);
5170
+ }
5171
+ return result;
5172
+ }
5173
+ function mapEntries(value) {
5174
+ if (value instanceof Map) return [...value.entries()];
5175
+ if (typeof value !== "object" || value == null || Array.isArray(value)) return void 0;
5176
+ return Object.entries(value);
5177
+ }
5178
+ function unsigned16(value) {
5179
+ const parsed = nonNegativeSafeInteger2(value);
5180
+ return parsed != null && parsed <= 65535 ? parsed : void 0;
5181
+ }
5182
+ function positiveSafeInteger3(value) {
5183
+ const parsed = nonNegativeSafeInteger2(value);
5184
+ return parsed != null && parsed > 0 ? parsed : void 0;
5185
+ }
5186
+ function nonNegativeSafeInteger2(value) {
5187
+ if (typeof value === "bigint") {
5188
+ return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
5189
+ }
5190
+ const source = text2(value) ?? value;
5191
+ if (typeof source !== "number" && (typeof source !== "string" || !/^\d+$/u.test(source))) {
5192
+ return void 0;
5193
+ }
5194
+ const parsed = Number(source);
5195
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
5196
+ }
5197
+ function text2(value) {
5198
+ if (typeof value === "string") return value;
5199
+ if (Buffer18.isBuffer(value) || value instanceof Uint8Array) {
5200
+ return Buffer18.from(value).toString("utf8");
5201
+ }
5202
+ return void 0;
5203
+ }
5204
+
5205
+ // src/protocol-compact-collections.ts
5206
+ import "buffer";
5207
+ function decodeCompactIntegerList(data, budget) {
5208
+ requireAvailable(data, 0, 5);
5209
+ const count = data.readUInt32BE(1);
5210
+ requireCompactContainer(count, budget);
5211
+ if (data.byteLength !== 5 + count * 8) {
5212
+ throw new FerricStoreError("invalid compact integer list response");
5213
+ }
5214
+ const values = new Array(count);
5215
+ for (let index = 0, offset = 5; index < count; index += 1, offset += 8) {
5216
+ const value = data.readBigInt64BE(offset);
5217
+ values[index] = value <= MAX_SAFE_INTEGER_BIGINT && value >= MIN_SAFE_INTEGER_BIGINT ? Number(value) : value;
5218
+ }
5219
+ return values;
5220
+ }
5221
+ function decodeCompactBinaryListList(data, budget) {
5222
+ requireAvailable(data, 0, 5);
5223
+ const count = data.readUInt32BE(1);
5224
+ requireCompactContainer(count, budget);
5225
+ let offset = 5;
5226
+ const values = new Array(count);
5227
+ for (let index = 0; index < count; index += 1) {
5228
+ const read = readCompactBinaryList(data, offset, budget);
5229
+ values[index] = read.value;
5230
+ offset = read.offset;
5231
+ }
5232
+ if (offset !== data.byteLength) throw new FerricStoreError("trailing compact binary list-list bytes");
5233
+ return values;
5234
+ }
5235
+ function decodeCompactBinaryMapList(data, budget) {
5236
+ requireAvailable(data, 0, 5);
5237
+ const count = data.readUInt32BE(1);
5238
+ requireCompactContainer(count, budget);
5239
+ let offset = 5;
5240
+ const values = new Array(count);
5241
+ for (let index = 0; index < count; index += 1) {
5242
+ const read = readCompactBinaryMap(data, offset, budget);
5243
+ values[index] = read.value;
5244
+ offset = read.offset;
5245
+ }
5246
+ if (offset !== data.byteLength) throw new FerricStoreError("trailing compact binary map-list bytes");
5247
+ return values;
5248
+ }
5249
+ function readCompactBinaryList(data, offset, budget) {
5250
+ requireAvailable(data, offset, 4);
5251
+ const count = data.readUInt32BE(offset);
5252
+ requireCompactContainer(count, budget);
5253
+ offset += 4;
5254
+ const values = new Array(count);
5255
+ for (let index = 0; index < count; index += 1) {
5256
+ const read = readBinary(data, offset);
5257
+ values[index] = read.value;
5258
+ offset = read.offset;
5259
+ }
5260
+ return { value: values, offset };
5261
+ }
5262
+ function readCompactBinaryMap(data, offset, budget) {
5263
+ requireAvailable(data, offset, 4);
5264
+ const count = data.readUInt32BE(offset);
5265
+ requireCompactContainer(count, budget);
5266
+ offset += 4;
5267
+ const values = {};
5268
+ for (let index = 0; index < count; index += 1) {
5269
+ const key = readBinary(data, offset);
5270
+ const value = readBinary(data, key.offset);
5271
+ setOwnValue2(values, key.value.toString("utf8"), value.value);
5272
+ offset = value.offset;
5273
+ }
5274
+ return { value: values, offset };
5275
+ }
5276
+ function markCompactPipelineDecoded(values) {
5277
+ Object.defineProperty(values, COMPACT_PIPELINE_DECODED, { value: true });
5278
+ return values;
5279
+ }
5280
+ function requireCompactContainer(count, budget) {
5281
+ if (count > DEFAULT_MAX_VALUE_ITEMS) {
5282
+ throw new FerricStoreError("native compact response container exceeds max items");
5283
+ }
5284
+ consumeDecodeItems(count, budget);
5285
+ }
4846
5286
 
4847
5287
  // src/protocol-compact-response.ts
4848
- import { Buffer as Buffer17 } from "buffer";
4849
5288
  function tryDecodeCompactResponse(opcode, body, hints) {
4850
5289
  if (body.byteLength === 0) return { found: false, value: void 0 };
4851
5290
  const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
4852
5291
  const tag = body.readUInt8(0);
4853
- if (tag === COMPACT_OK_LIST && isOkListOpcode(opcode)) {
5292
+ const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
5293
+ if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
4854
5294
  const values = decodeCompactOkList(body, budget);
4855
- return { found: true, value: opcode === OPCODES.pipeline ? values : values.length === 1 ? "OK" : values };
5295
+ return {
5296
+ found: true,
5297
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values.length === 1 ? "OK" : values
5298
+ };
4856
5299
  }
4857
- if (tag === COMPACT_KV_GET && compactResponseOpcodeSupports(opcode, COMPACT_KIND_KV_GET)) {
5300
+ if (tag === COMPACT_KV_GET && supports(hints, "kv_get_v1", opcode)) {
4858
5301
  return { found: true, value: decodeCompactKvGet(body) };
4859
5302
  }
4860
- if ((tag === COMPACT_KV_MGET || tag === COMPACT_KV_MGET_FIXED) && compactResponseOpcodeSupports(opcode, COMPACT_KIND_KV_MGET)) {
5303
+ if ((tag === COMPACT_KV_MGET || tag === COMPACT_KV_MGET_FIXED) && (supports(hints, "kv_mget_v1", opcode) || pipelineValues)) {
5304
+ const values = tag === COMPACT_KV_MGET ? decodeCompactMget(body, budget) : decodeCompactMgetFixed(body, budget);
4861
5305
  return {
4862
5306
  found: true,
4863
- value: tag === COMPACT_KV_MGET ? decodeCompactMget(body, budget) : decodeCompactMgetFixed(body, budget)
5307
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
4864
5308
  };
4865
5309
  }
4866
- if (tag === COMPACT_PIPELINE_RESPONSE && compactResponseOpcodeSupports(opcode, COMPACT_KIND_PIPELINE)) {
5310
+ if (tag === COMPACT_INTEGER_LIST && pipelineValues) {
5311
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactIntegerList(body, budget)) };
5312
+ }
5313
+ if (tag === COMPACT_BINARY_LIST_LIST && pipelineValues) {
5314
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryListList(body, budget)) };
5315
+ }
5316
+ if (tag === COMPACT_BINARY_MAP_LIST && pipelineValues) {
5317
+ return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryMapList(body, budget)) };
5318
+ }
5319
+ if (tag === COMPACT_PIPELINE_RESPONSE && pipelineValues) {
4867
5320
  return { found: true, value: decodeCompactPipeline(body, budget, hints.pipelineClaimModes) };
4868
5321
  }
4869
- if (tag === COMPACT_FLOW_CLAIM_JOBS && compactResponseOpcodeSupports(opcode, COMPACT_KIND_FLOW_CLAIM_JOBS)) {
4870
- return { found: true, value: decodeCompactClaimJobs(body, budget, hints.compactClaimMode) };
5322
+ if (tag === COMPACT_FLOW_CLAIM_JOBS && (supports(hints, "flow_claim_jobs_v1", opcode) || pipelineValues)) {
5323
+ const values = decodeCompactClaimJobs(body, budget, hints.compactClaimMode);
5324
+ return {
5325
+ found: true,
5326
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
5327
+ };
4871
5328
  }
4872
- if (tag === COMPACT_FLOW_RECORD && compactResponseOpcodeSupports(opcode, COMPACT_KIND_FLOW_RECORD)) {
5329
+ if (tag === COMPACT_FLOW_RECORD && supports(hints, "flow_record_v1", opcode)) {
4873
5330
  const read = readCompactFlowRecord(body, 0, budget);
4874
5331
  if (read.offset !== body.byteLength) throw new FerricStoreError("trailing compact Flow record bytes");
4875
5332
  return { found: true, value: read.value };
4876
5333
  }
4877
- if (tag === COMPACT_FLOW_RECORD_LIST && isFlowRecordListOpcode(opcode)) {
5334
+ if (tag === COMPACT_FLOW_RECORD_LIST && (supports(hints, "flow_record_list_v1", opcode) || pipelineValues)) {
4878
5335
  const read = readCompactFlowRecordList(body, 0, budget);
4879
5336
  if (read.offset !== body.byteLength) throw new FerricStoreError("trailing compact Flow record list bytes");
4880
- return { found: true, value: read.value };
5337
+ return {
5338
+ found: true,
5339
+ value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(read.value) : read.value
5340
+ };
4881
5341
  }
4882
5342
  return { found: false, value: void 0 };
4883
5343
  }
4884
- function isOkListOpcode(opcode) {
4885
- return compactResponseOpcodeSupports(opcode, COMPACT_KIND_OK_LIST);
4886
- }
4887
- function isFlowRecordListOpcode(opcode) {
4888
- return compactResponseOpcodeSupports(opcode, COMPACT_KIND_FLOW_RECORD_LIST);
5344
+ function supports(hints, codec, opcode) {
5345
+ return compactResponseOpcodeSupports(hints.compactResponseOpcodes, codec, opcode);
4889
5346
  }
4890
5347
  function decodeCompactOkList(data, budget) {
4891
5348
  requireAvailable(data, 0, 5);
4892
5349
  const count = data.readUInt32BE(1);
4893
- requireCompactContainer(count, budget);
5350
+ requireCompactContainer2(count, budget);
4894
5351
  if (data.byteLength !== 5) throw new FerricStoreError("invalid compact OK list response");
4895
- return Array.from({ length: count }, () => Buffer17.from("OK"));
5352
+ return Array.from({ length: count }, () => Buffer20.from("OK"));
4896
5353
  }
4897
5354
  function decodeCompactKvGet(data) {
4898
5355
  requireAvailable(data, 0, 2);
@@ -4909,7 +5366,7 @@ function decodeCompactKvGet(data) {
4909
5366
  function decodeCompactMget(data, budget) {
4910
5367
  requireAvailable(data, 0, 5);
4911
5368
  const count = data.readUInt32BE(1);
4912
- requireCompactContainer(count, budget);
5369
+ requireCompactContainer2(count, budget);
4913
5370
  let offset = 5;
4914
5371
  const values = [];
4915
5372
  for (let index = 0; index < count; index += 1) {
@@ -4933,12 +5390,12 @@ function decodeCompactMgetFixed(data, budget) {
4933
5390
  requireAvailable(data, 0, 9);
4934
5391
  const count = data.readUInt32BE(1);
4935
5392
  const size = data.readUInt32BE(5);
4936
- requireCompactContainer(count, budget);
5393
+ requireCompactContainer2(count, budget);
4937
5394
  const expected = 9 + count * size;
4938
5395
  if (size === NULL_U32 || data.byteLength !== expected) {
4939
5396
  throw new FerricStoreError("invalid compact fixed MGET response");
4940
5397
  }
4941
- if (size === 0) return new Array(count).fill(Buffer17.alloc(0));
5398
+ if (size === 0) return new Array(count).fill(Buffer20.alloc(0));
4942
5399
  const values = new Array(count);
4943
5400
  for (let index = 0, offset = 9; index < count; index += 1, offset += size) {
4944
5401
  values[index] = data.subarray(offset, offset + size);
@@ -4948,7 +5405,7 @@ function decodeCompactMgetFixed(data, budget) {
4948
5405
  function decodeCompactPipeline(data, budget, claimModes) {
4949
5406
  requireAvailable(data, 0, 5);
4950
5407
  const count = data.readUInt32BE(1);
4951
- requireCompactContainer(count, budget);
5408
+ requireCompactContainer2(count, budget);
4952
5409
  if (count > Math.floor((data.byteLength - 5) / 2)) {
4953
5410
  throw new FerricStoreError("compact pipeline item count exceeds response bytes");
4954
5411
  }
@@ -5010,13 +5467,12 @@ function decodeCompactPipeline(data, budget, claimModes) {
5010
5467
  }
5011
5468
  }
5012
5469
  if (offset !== data.byteLength) throw new FerricStoreError("trailing compact pipeline bytes");
5013
- Object.defineProperty(values, COMPACT_PIPELINE_DECODED, { value: true });
5014
- return values;
5470
+ return markCompactPipelineDecoded(values);
5015
5471
  }
5016
5472
  function decodeCompactClaimJobs(data, budget, mode) {
5017
5473
  requireAvailable(data, 0, 5);
5018
5474
  const count = data.readUInt32BE(1);
5019
- requireCompactContainer(count, budget);
5475
+ requireCompactContainer2(count, budget);
5020
5476
  if (mode != null) {
5021
5477
  const values = [];
5022
5478
  let offset = 5;
@@ -5100,7 +5556,7 @@ function readCompactFlowRecord(data, offset, budget = { remainingItems: DEFAULT_
5100
5556
  if (data.readUInt8(offset) !== COMPACT_FLOW_RECORD) throw new FerricStoreError("expected compact Flow record");
5101
5557
  offset += 1;
5102
5558
  const count = data.readUInt32BE(offset);
5103
- requireCompactContainer(count, budget);
5559
+ requireCompactContainer2(count, budget);
5104
5560
  offset += 4;
5105
5561
  const record = {};
5106
5562
  for (let index = 0; index < count; index += 1) {
@@ -5128,7 +5584,7 @@ function readCompactFlowRecordList(data, offset, budget = { remainingItems: DEFA
5128
5584
  }
5129
5585
  offset += 1;
5130
5586
  const count = data.readUInt32BE(offset);
5131
- requireCompactContainer(count, budget);
5587
+ requireCompactContainer2(count, budget);
5132
5588
  offset += 4;
5133
5589
  const records = [];
5134
5590
  for (let index = 0; index < count; index += 1) {
@@ -5136,34 +5592,7 @@ function readCompactFlowRecordList(data, offset, budget = { remainingItems: DEFA
5136
5592
  records.push(read.value);
5137
5593
  offset = read.offset;
5138
5594
  }
5139
- return { value: records, offset };
5140
- }
5141
- function readCompactBinaryList(data, offset, budget) {
5142
- requireAvailable(data, offset, 4);
5143
- const count = data.readUInt32BE(offset);
5144
- requireCompactContainer(count, budget);
5145
- offset += 4;
5146
- const values = [];
5147
- for (let index = 0; index < count; index += 1) {
5148
- const read = readBinary(data, offset);
5149
- values.push(read.value);
5150
- offset = read.offset;
5151
- }
5152
- return { value: values, offset };
5153
- }
5154
- function readCompactBinaryMap(data, offset, budget) {
5155
- requireAvailable(data, offset, 4);
5156
- const count = data.readUInt32BE(offset);
5157
- requireCompactContainer(count, budget);
5158
- offset += 4;
5159
- const values = {};
5160
- for (let index = 0; index < count; index += 1) {
5161
- const key = readBinary(data, offset);
5162
- const value = readBinary(data, key.offset);
5163
- setOwnValue2(values, key.value.toString("utf8"), value.value);
5164
- offset = value.offset;
5165
- }
5166
- return { value: values, offset };
5595
+ return { value: records, offset };
5167
5596
  }
5168
5597
  function readOptionalBinary(data, offset) {
5169
5598
  requireAvailable(data, offset, 4);
@@ -5173,7 +5602,7 @@ function readOptionalBinary(data, offset) {
5173
5602
  requireAvailable(data, offset, size);
5174
5603
  return { value: data.subarray(offset, offset + size), offset: offset + size };
5175
5604
  }
5176
- function requireCompactContainer(count, budget) {
5605
+ function requireCompactContainer2(count, budget) {
5177
5606
  if (count > DEFAULT_MAX_VALUE_ITEMS) {
5178
5607
  throw new FerricStoreError("native compact response container exceeds max items");
5179
5608
  }
@@ -5181,7 +5610,7 @@ function requireCompactContainer(count, budget) {
5181
5610
  }
5182
5611
  function errorMessage(status, value) {
5183
5612
  if (typeof value === "string") return value;
5184
- if (Buffer17.isBuffer(value)) return value.toString("utf8");
5613
+ if (Buffer20.isBuffer(value)) return value.toString("utf8");
5185
5614
  if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5186
5615
  const message = value.message;
5187
5616
  return typeof message === "string" ? message : String(message);
@@ -5261,7 +5690,7 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
5261
5690
  return out;
5262
5691
  }
5263
5692
  function pipelineStatus(value) {
5264
- if (typeof value !== "string" && !Buffer18.isBuffer(value) && !(value instanceof Uint8Array)) return null;
5693
+ if (typeof value !== "string" && !Buffer21.isBuffer(value) && !(value instanceof Uint8Array)) return null;
5265
5694
  const status = asText(value).toLowerCase();
5266
5695
  return status === "ok" || status === "busy" || status === "error" ? status : null;
5267
5696
  }
@@ -5276,7 +5705,7 @@ function decodeResponseValue(opcode, body, hints) {
5276
5705
  }
5277
5706
  function errorMessage2(status, value) {
5278
5707
  if (typeof value === "string") return value;
5279
- if (Buffer18.isBuffer(value)) return value.toString("utf8");
5708
+ if (Buffer21.isBuffer(value)) return value.toString("utf8");
5280
5709
  if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
5281
5710
  const message = value.message;
5282
5711
  return typeof message === "string" ? message : String(message);
@@ -5292,7 +5721,7 @@ function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGE
5292
5721
  const bodyLength = customPayload ? binaryValueByteLength(command.payload) : plan?.byteLength ?? 0;
5293
5722
  if (bodyLength > bodyLimit) throw requestFrameTooLarge(bodyLimit);
5294
5723
  const flags = command.flags ?? 0;
5295
- const frame = Buffer19.allocUnsafe(HEADER_SIZE + bodyLength);
5724
+ const frame = Buffer22.allocUnsafe(HEADER_SIZE + bodyLength);
5296
5725
  frame.write(MAGIC, 0, "ascii");
5297
5726
  frame.writeUInt8(REQUEST_VERSION, 4);
5298
5727
  frame.writeUInt8(flags, 5);
@@ -5343,6 +5772,9 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5343
5772
  }
5344
5773
  const command = asText(args[0]).toUpperCase();
5345
5774
  assertNormalizedCommandDoesNotRequirePinnedConnection(args, command);
5775
+ if (command === "MSET" || command === "MSETNX") {
5776
+ assertKeyValueCommandSharesSlot(args, command);
5777
+ }
5346
5778
  const commandArgs2 = args.slice(1);
5347
5779
  if (command === "COMMAND_EXEC" && commandArgs2.length >= 1) {
5348
5780
  return commandExec(commandArgs2);
@@ -5480,20 +5912,7 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
5480
5912
  ])) ?? commandExec(args);
5481
5913
  }
5482
5914
  if (command === "FLOW.SIGNAL") {
5483
- return flowCommandExecWithRouting(command, commandArgs2, 1, /* @__PURE__ */ new Set([
5484
- "SIGNAL",
5485
- "PARTITION",
5486
- "IDEMPOTENCY",
5487
- "IF_STATE",
5488
- "TRANSITION_TO",
5489
- "RUN_AT",
5490
- "NOW",
5491
- "PRIORITY",
5492
- "VALUE",
5493
- "VALUE_REF",
5494
- "DROP_VALUE",
5495
- "OVERRIDE_VALUE"
5496
- ]));
5915
+ return flowSignalPayload(commandArgs2) ?? commandExec(args);
5497
5916
  }
5498
5917
  if (command === "FLOW.CANCEL") {
5499
5918
  return flowCommandExecWithRouting(command, commandArgs2, 1, /* @__PURE__ */ new Set([
@@ -5662,6 +6081,7 @@ var DEFAULT_MAX_PENDING_CONTROL_REQUESTS = 4096;
5662
6081
  var DEFAULT_MAX_RESPONSE_BYTES = 64 * 1024 * 1024;
5663
6082
  var DEFAULT_MAX_QUEUED_REQUESTS = 65536;
5664
6083
  var DEFAULT_MAX_QUEUED_WRITE_BYTES = 64 * 1024 * 1024;
6084
+ var UNAUTHENTICATED_MAX_FRAME_BYTES = 64 * 1024;
5665
6085
  function assertNativeAdapterOptions(options) {
5666
6086
  const supplied = options;
5667
6087
  for (const name of ["autoReconnect", "haRouting", "seeds"]) {
@@ -5681,7 +6101,7 @@ import "net";
5681
6101
  import "tls";
5682
6102
 
5683
6103
  // src/client-native-options.ts
5684
- import { Buffer as Buffer20 } from "buffer";
6104
+ import { Buffer as Buffer23 } from "buffer";
5685
6105
 
5686
6106
  // src/string-array-snapshot.ts
5687
6107
  function snapshotOwnStringArray(values, name) {
@@ -5764,7 +6184,7 @@ function snapshotTlsOptions(options) {
5764
6184
  return Object.freeze(snapshot);
5765
6185
  }
5766
6186
  function snapshotTlsValue(value, name) {
5767
- if (Buffer20.isBuffer(value)) return Buffer20.from(value);
6187
+ if (Buffer23.isBuffer(value)) return Buffer23.from(value);
5768
6188
  if (value instanceof Uint8Array) return value.slice();
5769
6189
  if (Array.isArray(value)) {
5770
6190
  const snapshot = new Array(value.length);
@@ -6234,6 +6654,9 @@ var NativeChunkAssembler = class {
6234
6654
  framesByKey = /* @__PURE__ */ new Map();
6235
6655
  totalBytes = 0;
6236
6656
  totalFrames = 0;
6657
+ updateMaxResponseBytes(limit) {
6658
+ this.maxResponseBytes = Math.min(this.maxResponseBytes, limit);
6659
+ }
6237
6660
  assemble(frame) {
6238
6661
  const key = `${frame.requestId}:${frame.opcode}:${frame.laneId}`;
6239
6662
  const previous = this.chunks.get(key);
@@ -6478,12 +6901,18 @@ var NativeReceiveBuffer = class {
6478
6901
  var NativeResponseHandler = class {
6479
6902
  constructor(options) {
6480
6903
  this.options = options;
6904
+ this.maxResponseBytes = options.maxResponseBytes;
6481
6905
  }
6482
6906
  options;
6483
6907
  receiveBuffer = new NativeReceiveBuffer();
6484
6908
  drainScheduled = false;
6485
6909
  paused = false;
6486
6910
  stopped = false;
6911
+ maxResponseBytes;
6912
+ updateMaxResponseBytes(limit) {
6913
+ this.maxResponseBytes = Math.min(this.maxResponseBytes, limit);
6914
+ this.options.chunkAssembler.updateMaxResponseBytes(this.maxResponseBytes);
6915
+ }
6487
6916
  onData(chunk) {
6488
6917
  if (this.stopped) return;
6489
6918
  try {
@@ -6565,15 +6994,18 @@ var NativeResponseHandler = class {
6565
6994
  }
6566
6995
  const completeFrame = this.options.chunkAssembler.assemble(frame);
6567
6996
  if (completeFrame == null) return;
6568
- if (completeFrame.body.byteLength > this.options.maxResponseBytes) {
6997
+ if (completeFrame.body.byteLength > this.maxResponseBytes) {
6569
6998
  throw new FerricStoreError(
6570
- `native protocol response exceeded ${this.options.maxResponseBytes} bytes`
6999
+ `native protocol response exceeded ${this.maxResponseBytes} bytes`
6571
7000
  );
6572
7001
  }
6573
7002
  let value;
6574
7003
  let responseError;
6575
7004
  try {
6576
- value = decodeResponse(completeFrame, pending.opcode, pending);
7005
+ value = decodeResponse(completeFrame, pending.opcode, {
7006
+ ...pending,
7007
+ compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
7008
+ });
6577
7009
  if (pending.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
6578
7010
  } catch (error) {
6579
7011
  responseError = error;
@@ -6589,7 +7021,7 @@ var NativeResponseHandler = class {
6589
7021
  pending.discardedResponseBytes = discardedResponseBytes;
6590
7022
  pending.discardedResponseFrames = discardedResponseFrames;
6591
7023
  const chunked = discardedResponseFrames > 1 || (frame.flags & FLAG_MORE_CHUNKS) !== 0;
6592
- if (discardedResponseBytes > this.options.maxResponseBytes || chunked && discardedResponseBytes > this.options.maxChunkBytes) {
7024
+ if (discardedResponseBytes > this.maxResponseBytes || chunked && discardedResponseBytes > this.options.maxChunkBytes) {
6593
7025
  throw new FerricStoreError("native protocol discarded response exceeded configured byte limits");
6594
7026
  }
6595
7027
  if (discardedResponseFrames > this.options.maxChunkFrames) {
@@ -6598,12 +7030,14 @@ var NativeResponseHandler = class {
6598
7030
  if ((frame.flags & FLAG_MORE_CHUNKS) === 0) this.options.takePending(frame.requestId);
6599
7031
  }
6600
7032
  handleManagementFrame(frame) {
6601
- if (frame.body.byteLength > this.options.maxResponseBytes) {
7033
+ if (frame.body.byteLength > this.maxResponseBytes) {
6602
7034
  throw new FerricStoreError(
6603
- `native protocol response exceeded ${this.options.maxResponseBytes} bytes`
7035
+ `native protocol response exceeded ${this.maxResponseBytes} bytes`
6604
7036
  );
6605
7037
  }
6606
- const value = decodeResponse(frame, frame.opcode);
7038
+ const value = decodeResponse(frame, frame.opcode, {
7039
+ compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
7040
+ });
6607
7041
  if (frame.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
6608
7042
  const event = {
6609
7043
  flags: frame.flags,
@@ -6768,6 +7202,40 @@ var NativeWriteQueue = class {
6768
7202
  }
6769
7203
  };
6770
7204
 
7205
+ // src/native-connection-capabilities.ts
7206
+ var NativeConnectionCapabilities = class {
7207
+ constructor(configuredRequestFrameBytes) {
7208
+ this.configuredRequestFrameBytes = configuredRequestFrameBytes;
7209
+ this.negotiatedRequestFrameBytes = configuredRequestFrameBytes;
7210
+ this.requestFrameBytes = Math.min(configuredRequestFrameBytes, UNAUTHENTICATED_MAX_FRAME_BYTES);
7211
+ }
7212
+ configuredRequestFrameBytes;
7213
+ compactResponseOpcodes = EMPTY_COMPACT_RESPONSE_OPCODES;
7214
+ requestFrameBytes;
7215
+ negotiatedRequestFrameBytes;
7216
+ apply(value) {
7217
+ const limits = startupLimits(value);
7218
+ const negotiation = nativeNegotiation(value);
7219
+ this.compactResponseOpcodes = negotiation.compactResponseOpcodes;
7220
+ if (limits.frameBytes != null) {
7221
+ this.negotiatedRequestFrameBytes = Math.min(
7222
+ this.configuredRequestFrameBytes,
7223
+ limits.frameBytes
7224
+ );
7225
+ this.requestFrameBytes = Math.min(this.requestFrameBytes, this.negotiatedRequestFrameBytes);
7226
+ }
7227
+ return {
7228
+ ...limits.laneQueue == null ? {} : { laneQueue: limits.laneQueue },
7229
+ ...limits.lanes == null ? {} : { lanes: limits.lanes },
7230
+ ...negotiation.maxResponseBytes == null ? {} : { maxResponseBytes: negotiation.maxResponseBytes },
7231
+ ...limits.pipelineCommands == null ? {} : { pipelineCommands: limits.pipelineCommands }
7232
+ };
7233
+ }
7234
+ activateAuthenticated() {
7235
+ this.requestFrameBytes = this.negotiatedRequestFrameBytes;
7236
+ }
7237
+ };
7238
+
6771
7239
  // src/native-adapter.ts
6772
7240
  var NativeAdapter = class _NativeAdapter {
6773
7241
  socket;
@@ -6776,9 +7244,9 @@ var NativeAdapter = class _NativeAdapter {
6776
7244
  closedWaiters = /* @__PURE__ */ new Set();
6777
7245
  chunkAssembler;
6778
7246
  closed = false;
7247
+ capabilities;
6779
7248
  protocolLanes;
6780
7249
  maxPipelineCommands = Number.MAX_SAFE_INTEGER;
6781
- maxRequestFrameBytes;
6782
7250
  pendingControlRequests = 0;
6783
7251
  maxPendingControlRequests;
6784
7252
  heartbeat;
@@ -6793,7 +7261,7 @@ var NativeAdapter = class _NativeAdapter {
6793
7261
  const normalizedMaxChunkBytes = normalizePositiveLimit(maxChunkBytes, DEFAULT_MAX_CHUNK_BYTES);
6794
7262
  const normalizedMaxChunkFrames = normalizePositiveLimit(maxChunkFrames, DEFAULT_MAX_CHUNK_FRAMES);
6795
7263
  const normalizedMaxFrameBytes = normalizePositiveLimit(maxFrameBytes, DEFAULT_MAX_FRAME_BYTES);
6796
- this.maxRequestFrameBytes = normalizedMaxFrameBytes;
7264
+ this.capabilities = new NativeConnectionCapabilities(normalizedMaxFrameBytes);
6797
7265
  const normalizedMaxResponseBytes = normalizePositiveLimit(maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES);
6798
7266
  this.chunkAssembler = new NativeChunkAssembler(
6799
7267
  normalizedMaxChunkBytes,
@@ -6820,7 +7288,7 @@ var NativeAdapter = class _NativeAdapter {
6820
7288
  this.heartbeat = new NativeHeartbeat(
6821
7289
  this.heartbeatIntervalMs,
6822
7290
  async () => {
6823
- await this.request(buildProtocolCommand(["PING"], this.maxRequestFrameBytes), true);
7291
+ await this.request(buildProtocolCommand(["PING"], this.capabilities.requestFrameBytes), true);
6824
7292
  },
6825
7293
  (error) => {
6826
7294
  this.failAll(new FerricStoreError("FerricStore protocol heartbeat failed", { cause: error }), true);
@@ -6831,6 +7299,7 @@ var NativeAdapter = class _NativeAdapter {
6831
7299
  applyFlowControlLimits: (value) => this.applyFlowControlLimits(value),
6832
7300
  beginDraining: () => this.beginDraining(),
6833
7301
  chunkAssembler: this.chunkAssembler,
7302
+ compactResponseOpcodes: () => this.capabilities.compactResponseOpcodes,
6834
7303
  destroy: (error) => this.socket.destroy(error),
6835
7304
  failAll: (reason, connectionClosed, message) => this.failAll(reason, connectionClosed, message),
6836
7305
  heartbeat: this.heartbeat,
@@ -6856,6 +7325,7 @@ var NativeAdapter = class _NativeAdapter {
6856
7325
  adapter,
6857
7326
  auth: async (username, password) => {
6858
7327
  await adapter.request({ laneId: 0, opcode: OPCODES.auth, payload: { password, username } });
7328
+ adapter.capabilities.activateAuthenticated();
6859
7329
  },
6860
7330
  close: async () => {
6861
7331
  await adapter.close();
@@ -6873,13 +7343,13 @@ var NativeAdapter = class _NativeAdapter {
6873
7343
  return await this.executeCommandArgs(args);
6874
7344
  }
6875
7345
  async executeCommandArgs(args) {
6876
- const command = buildProtocolCommand(args, this.maxRequestFrameBytes);
7346
+ const command = buildProtocolCommand(args, this.capabilities.requestFrameBytes);
6877
7347
  return await this.request(command);
6878
7348
  }
6879
7349
  /** @internal Execute raw command arguments on a topology-selected lane. */
6880
7350
  async executeCommandOnLane(args, laneId) {
6881
7351
  return await this.executeProtocolCommand(
6882
- buildProtocolCommand(args, this.maxRequestFrameBytes),
7352
+ buildProtocolCommand(args, this.capabilities.requestFrameBytes),
6883
7353
  laneId
6884
7354
  );
6885
7355
  }
@@ -6901,7 +7371,7 @@ var NativeAdapter = class _NativeAdapter {
6901
7371
  laneId,
6902
7372
  options,
6903
7373
  this.maxPipelineCommands,
6904
- this.maxRequestFrameBytes
7374
+ this.capabilities.requestFrameBytes
6905
7375
  );
6906
7376
  }
6907
7377
  /** @internal Execute an ordered pipeline on a topology-selected lane. */
@@ -6912,13 +7382,11 @@ var NativeAdapter = class _NativeAdapter {
6912
7382
  laneId,
6913
7383
  options,
6914
7384
  this.maxPipelineCommands,
6915
- this.maxRequestFrameBytes
7385
+ this.capabilities.requestFrameBytes
6916
7386
  );
6917
7387
  }
6918
7388
  async close() {
6919
- if (this.closed) {
6920
- return;
6921
- }
7389
+ if (this.closed) return;
6922
7390
  this.failAll(new FerricStoreError("FerricStore connection closed"), true);
6923
7391
  this.socket.destroy();
6924
7392
  }
@@ -6936,7 +7404,9 @@ var NativeAdapter = class _NativeAdapter {
6936
7404
  });
6937
7405
  this.applyStartupLimits(response);
6938
7406
  const authRequired = field(response, "auth_required");
6939
- return authRequired == null ? false : booleanResponse(authRequired);
7407
+ const required = authRequired == null ? false : booleanResponse(authRequired);
7408
+ if (authRequired != null && !required) this.capabilities.activateAuthenticated();
7409
+ return required;
6940
7410
  }
6941
7411
  request(command, allowWhileDraining = false) {
6942
7412
  if (this.closed || this.draining && !allowWhileDraining) {
@@ -6977,7 +7447,7 @@ var NativeAdapter = class _NativeAdapter {
6977
7447
  let frame;
6978
7448
  try {
6979
7449
  requestId = this.requestScheduler.nextRequestId();
6980
- frame = encodeRequest(command, requestId, this.maxRequestFrameBytes);
7450
+ frame = encodeRequest(command, requestId, this.capabilities.requestFrameBytes);
6981
7451
  } catch (error) {
6982
7452
  if (hasFlowControlCredit) this.flowControl.release(laneId);
6983
7453
  return Promise.reject(error instanceof Error ? error : new FerricStoreError(String(error), { raw: error }));
@@ -7031,9 +7501,7 @@ var NativeAdapter = class _NativeAdapter {
7031
7501
  this.resolveClosedWaiters();
7032
7502
  }
7033
7503
  failAll(reason, connectionClosed = false, dispatchedMessage) {
7034
- if (this.closed) {
7035
- return;
7036
- }
7504
+ if (this.closed) return;
7037
7505
  this.closed = true;
7038
7506
  this.responseHandler.stop();
7039
7507
  this.resolveClosedWaiters();
@@ -7099,18 +7567,18 @@ var NativeAdapter = class _NativeAdapter {
7099
7567
  }
7100
7568
  applyStartupLimits(value) {
7101
7569
  this.applyFlowControlLimits(value);
7102
- const limits = startupLimits(value);
7103
- if (limits.laneQueue != null) {
7104
- this.flowControl.updateLaneQueueLimit(limits.laneQueue);
7570
+ const capabilities = this.capabilities.apply(value);
7571
+ if (capabilities.maxResponseBytes != null) {
7572
+ this.responseHandler.updateMaxResponseBytes(capabilities.maxResponseBytes);
7105
7573
  }
7106
- if (limits.lanes != null) {
7107
- this.protocolLanes = Math.min(this.protocolLanes, limits.lanes);
7574
+ if (capabilities.laneQueue != null) {
7575
+ this.flowControl.updateLaneQueueLimit(capabilities.laneQueue);
7108
7576
  }
7109
- if (limits.pipelineCommands != null) {
7110
- this.maxPipelineCommands = limits.pipelineCommands;
7577
+ if (capabilities.lanes != null) {
7578
+ this.protocolLanes = Math.min(this.protocolLanes, capabilities.lanes);
7111
7579
  }
7112
- if (limits.frameBytes != null) {
7113
- this.maxRequestFrameBytes = Math.min(this.maxRequestFrameBytes, limits.frameBytes);
7580
+ if (capabilities.pipelineCommands != null) {
7581
+ this.maxPipelineCommands = capabilities.pipelineCommands;
7114
7582
  }
7115
7583
  }
7116
7584
  };
@@ -7321,214 +7789,8 @@ function normalizeNonNegativeInteger2(value, fallback) {
7321
7789
  import "buffer";
7322
7790
 
7323
7791
  // src/topology-routing.ts
7324
- import { Buffer as Buffer26 } from "buffer";
7792
+ import { Buffer as Buffer28 } from "buffer";
7325
7793
  import { createHash } from "crypto";
7326
-
7327
- // src/topology-utilities.ts
7328
- import { Buffer as Buffer25 } from "buffer";
7329
- function isPlainObject3(value) {
7330
- return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer25.isBuffer(value);
7331
- }
7332
- function getField(source, ...keys) {
7333
- if (source instanceof Map) {
7334
- for (const key of keys) {
7335
- if (source.has(key)) return source.get(key);
7336
- const bufferKey = Buffer25.from(key);
7337
- for (const [itemKey, value] of source.entries()) {
7338
- if (Buffer25.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
7339
- }
7340
- }
7341
- return void 0;
7342
- }
7343
- if (isPlainObject3(source)) {
7344
- for (const key of keys) {
7345
- if (Object.hasOwn(source, key)) return source[key];
7346
- }
7347
- }
7348
- return void 0;
7349
- }
7350
- function textOrUndefined(value) {
7351
- if (typeof value === "string") return value;
7352
- if (Buffer25.isBuffer(value)) return value.toString("utf8");
7353
- return void 0;
7354
- }
7355
- function numberOrUndefined(value) {
7356
- return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
7357
- }
7358
- function nativeEventName(event) {
7359
- return textOrUndefined(getField(event.value, "event"))?.toUpperCase();
7360
- }
7361
- function endpointFromRange(item) {
7362
- const endpointValue = getField(item, "endpoint");
7363
- if (endpointValue != null && !isPlainObject3(endpointValue) && !(endpointValue instanceof Map)) {
7364
- throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
7365
- }
7366
- const raw = endpointValue ?? item;
7367
- const host = textOrUndefined(getField(raw, "host", "native_host"));
7368
- const nativePort = numberOrUndefined(getField(raw, "native_port"));
7369
- if (host == null || !validEndpointHost(host) || nativePort == null || nativePort <= 0 || nativePort > 65535) {
7370
- throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
7371
- }
7372
- const nativeTlsPortValue = getField(raw, "native_tls_port");
7373
- const nativeTlsPort = numberOrUndefined(nativeTlsPortValue);
7374
- if (nativeTlsPortValue != null && (nativeTlsPort == null || nativeTlsPort <= 0 || nativeTlsPort > 65535)) {
7375
- throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
7376
- }
7377
- return {
7378
- host,
7379
- nativePort,
7380
- node: textOrUndefined(getField(raw, "node", "leader_node", "owner_node")) ?? host,
7381
- ...nativeTlsPort == null ? {} : { nativeTlsPort }
7382
- };
7383
- }
7384
- function validEndpointHost(host) {
7385
- if (host.length === 0 || host.trim() !== host || /[\s\\/?#@]/u.test(host)) return false;
7386
- const authorityHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
7387
- try {
7388
- const url = new URL(`ferric://${authorityHost}:6388`);
7389
- return url.hostname !== "" && url.port === "6388" && url.username === "" && url.password === "";
7390
- } catch {
7391
- return false;
7392
- }
7393
- }
7394
- function sameEndpoint(left, right) {
7395
- return normalizedEndpointHost(left.host) === normalizedEndpointHost(right.host) && left.nativePort === right.nativePort && left.nativeTlsPort === right.nativeTlsPort && left.node === right.node;
7396
- }
7397
- function parseFerricUrl2(value) {
7398
- const url = new URL(value);
7399
- if (url.protocol !== "ferric:" && url.protocol !== "ferrics:") {
7400
- throw new FerricStoreError(`unsupported FerricStore URL scheme: ${url.protocol}`);
7401
- }
7402
- return {
7403
- host: normalizeFerricUrlHost(url.hostname),
7404
- ...url.password === "" ? {} : { password: decodeURIComponent(url.password) },
7405
- port: Number(url.port || (url.protocol === "ferrics:" ? 6389 : 6388)),
7406
- tls: url.protocol === "ferrics:",
7407
- ...url.username === "" ? {} : { username: decodeURIComponent(url.username) }
7408
- };
7409
- }
7410
- function endpointKeyFor(endpoint) {
7411
- return `${normalizedEndpointHost(endpoint.host)}:${endpoint.nativePort}`;
7412
- }
7413
- function connectionKeyForEndpoint(endpoint, useTls) {
7414
- const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
7415
- return `${useTls ? "ferrics" : "ferric"}://${normalizedEndpointHost(endpoint.host)}:${port}`;
7416
- }
7417
- function connectionKeyFromUrl(url) {
7418
- const parsed = parseFerricUrl2(url);
7419
- return `${parsed.tls ? "ferrics" : "ferric"}://${normalizedEndpointHost(parsed.host)}:${parsed.port}`;
7420
- }
7421
- function normalizedEndpointHost(host) {
7422
- const lower = host.toLowerCase();
7423
- return lower.startsWith("[") && lower.endsWith("]") ? lower.slice(1, -1) : lower;
7424
- }
7425
- function urlFromEndpoint(endpoint, useTls) {
7426
- const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
7427
- const host = endpoint.host.includes(":") && !endpoint.host.startsWith("[") ? `[${endpoint.host}]` : endpoint.host;
7428
- return `${useTls ? "ferrics" : "ferric"}://${host}:${port}`;
7429
- }
7430
- async function mapSettledWithConcurrency(items, concurrency, operation) {
7431
- const results = new Array(items.length);
7432
- let nextIndex = 0;
7433
- const worker = async () => {
7434
- while (nextIndex < items.length) {
7435
- const index = nextIndex++;
7436
- const item = items[index];
7437
- try {
7438
- results[index] = { status: "fulfilled", value: await operation(item, index) };
7439
- } catch (reason) {
7440
- results[index] = { status: "rejected", reason };
7441
- }
7442
- }
7443
- };
7444
- await Promise.all(Array.from(
7445
- { length: Math.min(concurrency, items.length) },
7446
- async () => await worker()
7447
- ));
7448
- return results;
7449
- }
7450
- function throwFirstRejected(results) {
7451
- for (const result of results) {
7452
- if (result.status === "rejected") throw result.reason;
7453
- }
7454
- }
7455
- var TaskConcurrencyLimiter = class {
7456
- constructor(concurrency) {
7457
- this.concurrency = concurrency;
7458
- }
7459
- concurrency;
7460
- active = 0;
7461
- head = 0;
7462
- pending = [];
7463
- async run(operation) {
7464
- await this.acquire();
7465
- try {
7466
- return await operation();
7467
- } finally {
7468
- this.release();
7469
- }
7470
- }
7471
- acquire() {
7472
- if (this.active < this.concurrency) {
7473
- this.active += 1;
7474
- return Promise.resolve();
7475
- }
7476
- return new Promise((resolve) => this.pending.push(resolve));
7477
- }
7478
- release() {
7479
- const next = this.pending[this.head];
7480
- if (next == null) {
7481
- this.active -= 1;
7482
- return;
7483
- }
7484
- this.head += 1;
7485
- next();
7486
- if (this.head === this.pending.length) {
7487
- this.pending.length = 0;
7488
- this.head = 0;
7489
- } else if (this.head >= 1024 && this.head * 2 >= this.pending.length) {
7490
- this.pending.splice(0, this.head);
7491
- this.head = 0;
7492
- }
7493
- }
7494
- };
7495
- function normalizedHostSet(hosts) {
7496
- return new Set(
7497
- hosts.filter((host) => host != null && host !== "").map((host) => normalizedEndpointHost(host))
7498
- );
7499
- }
7500
- function bufferStartsWith(value, prefix) {
7501
- return value.byteLength >= prefix.byteLength && value.subarray(0, prefix.byteLength).equals(prefix);
7502
- }
7503
- var OPEN_BRACE = "{".charCodeAt(0);
7504
- var CLOSE_BRACE = "}".charCodeAt(0);
7505
- function hashTagOrKey(key) {
7506
- const start = key.indexOf(OPEN_BRACE);
7507
- if (start < 0) return key;
7508
- const end = key.indexOf(CLOSE_BRACE, start + 1);
7509
- return end > start + 1 ? key.subarray(start + 1, end) : key;
7510
- }
7511
- function flowHashTag(rest, fallbackKey) {
7512
- const end = rest.indexOf(CLOSE_BRACE);
7513
- return end > 0 ? rest.subarray(0, end) : hashTagOrKey(fallbackKey);
7514
- }
7515
- var ROUTE_SLOT_MASK = 1023;
7516
- var FLOW_KEY_PREFIX = Buffer25.from("f:{");
7517
- var VALUE_REF_FLOW_KEY_PREFIX = Buffer25.from("X:f:{");
7518
- function routingSlotForKey(key) {
7519
- const keyBytes = Buffer25.isBuffer(key) ? key : Buffer25.from(key);
7520
- let hashInput;
7521
- if (bufferStartsWith(keyBytes, FLOW_KEY_PREFIX)) {
7522
- hashInput = flowHashTag(keyBytes.subarray(FLOW_KEY_PREFIX.byteLength), keyBytes);
7523
- } else if (bufferStartsWith(keyBytes, VALUE_REF_FLOW_KEY_PREFIX)) {
7524
- hashInput = flowHashTag(keyBytes.subarray(VALUE_REF_FLOW_KEY_PREFIX.byteLength), keyBytes);
7525
- } else {
7526
- hashInput = hashTagOrKey(keyBytes);
7527
- }
7528
- return crc32(hashInput) & ROUTE_SLOT_MASK;
7529
- }
7530
-
7531
- // src/topology-routing.ts
7532
7794
  var FLOW_PARTITION_ROUTE_CACHE_MAX = 1024;
7533
7795
  var flowPartitionRouteCache = /* @__PURE__ */ new Map();
7534
7796
  function routingKeyFromProtocolPayload(name, command) {
@@ -7536,9 +7798,18 @@ function routingKeyFromProtocolPayload(name, command) {
7536
7798
  return void 0;
7537
7799
  }
7538
7800
  if (isPlainObject3(command.payload)) {
7539
- for (const field2 of ["key", "partition_key", "id", "owner_flow_id", "parent_id", "root_id", "correlation_id", "scope"]) {
7801
+ for (const field2 of [
7802
+ "key",
7803
+ "partition_key",
7804
+ "id",
7805
+ "owner_flow_id",
7806
+ "parent_flow_id",
7807
+ "root_flow_id",
7808
+ "correlation_id",
7809
+ "scope"
7810
+ ]) {
7540
7811
  const value = getField(command.payload, field2);
7541
- if (typeof value === "string" || Buffer26.isBuffer(value)) {
7812
+ if (typeof value === "string" || Buffer28.isBuffer(value)) {
7542
7813
  return value;
7543
7814
  }
7544
7815
  }
@@ -7585,9 +7856,9 @@ function flowRoutingData(name, args) {
7585
7856
  if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
7586
7857
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
7587
7858
  }
7588
- if (Buffer26.isBuffer(partition)) {
7589
- const text2 = partition.toString("utf8").toUpperCase();
7590
- if (text2 !== "AUTO" && text2 !== "MIXED") {
7859
+ if (Buffer28.isBuffer(partition)) {
7860
+ const text3 = partition.toString("utf8").toUpperCase();
7861
+ if (text3 !== "AUTO" && text3 !== "MIXED") {
7591
7862
  return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
7592
7863
  }
7593
7864
  }
@@ -7676,22 +7947,22 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
7676
7947
  return { handled: false };
7677
7948
  }
7678
7949
  function isRoutingKey(value) {
7679
- return typeof value === "string" || Buffer26.isBuffer(value);
7950
+ return typeof value === "string" || Buffer28.isBuffer(value);
7680
7951
  }
7681
7952
  function flowLogicalPartitionRoutingKey(value) {
7682
- if (typeof value !== "string" && !Buffer26.isBuffer(value)) {
7953
+ if (typeof value !== "string" && !Buffer28.isBuffer(value)) {
7683
7954
  return void 0;
7684
7955
  }
7685
- const bytes2 = Buffer26.isBuffer(value) ? value : Buffer26.from(value);
7686
- const text2 = bytes2.toString("utf8");
7687
- const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(text2);
7956
+ const bytes2 = Buffer28.isBuffer(value) ? value : Buffer28.from(value);
7957
+ const text3 = bytes2.toString("utf8");
7958
+ const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(text3);
7688
7959
  if (autoMatch != null) {
7689
7960
  const bucket = Number(autoMatch[1]);
7690
7961
  if (bucket < 256) {
7691
- return `f:{fa:${bucket}}:route`;
7962
+ return `{fa:${bucket}}`;
7692
7963
  }
7693
7964
  }
7694
- const cacheKey = `${Buffer26.isBuffer(value) ? "b" : "s"}:${bytes2.toString("base64")}`;
7965
+ const cacheKey = `${Buffer28.isBuffer(value) ? "b" : "s"}:${bytes2.toString("base64")}`;
7695
7966
  const cached = flowPartitionRouteCache.get(cacheKey);
7696
7967
  if (cached != null) {
7697
7968
  flowPartitionRouteCache.delete(cacheKey);
@@ -7699,7 +7970,7 @@ function flowLogicalPartitionRoutingKey(value) {
7699
7970
  return cached;
7700
7971
  }
7701
7972
  const digest = createHash("sha256").update(bytes2).digest("base64url");
7702
- const routeKey = `f:{f:${digest}}:route`;
7973
+ const routeKey = `{f:${digest}}`;
7703
7974
  if (flowPartitionRouteCache.size >= FLOW_PARTITION_ROUTE_CACHE_MAX) {
7704
7975
  const oldest = flowPartitionRouteCache.keys().next().value;
7705
7976
  if (oldest != null) flowPartitionRouteCache.delete(oldest);
@@ -7708,18 +7979,17 @@ function flowLogicalPartitionRoutingKey(value) {
7708
7979
  return routeKey;
7709
7980
  }
7710
7981
  function flowAutoIdRoutingKey(value) {
7711
- if (typeof value !== "string" && !Buffer26.isBuffer(value)) {
7982
+ if (typeof value !== "string" && !Buffer28.isBuffer(value)) {
7712
7983
  return void 0;
7713
7984
  }
7714
- const bytes2 = Buffer26.isBuffer(value) ? value : Buffer26.from(value);
7715
- const bucket = crc32(bytes2) & 255;
7716
- return `f:{fa:${bucket}}:route`;
7985
+ const bucket = (Buffer28.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
7986
+ return `{fa:${bucket}}`;
7717
7987
  }
7718
7988
  function flowClaimLogicalPartitionRoutingKey(value) {
7719
- if (typeof value !== "string" && !Buffer26.isBuffer(value)) return void 0;
7989
+ if (typeof value !== "string" && !Buffer28.isBuffer(value)) return void 0;
7720
7990
  const selector = commandPart(value);
7721
7991
  if (selector === "AUTO" || selector === "ANY") return void 0;
7722
- if (selector === "GLOBAL") return "f:{f}:route";
7992
+ if (selector === "GLOBAL") return "{f}";
7723
7993
  return flowLogicalPartitionRoutingKey(value);
7724
7994
  }
7725
7995
  function singleShardFlowPartitionKey(values) {
@@ -7731,7 +8001,7 @@ function singleShardFlowClaimPartitionKey(values) {
7731
8001
  return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
7732
8002
  }
7733
8003
  function singleShardKey(keys) {
7734
- if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer26.isBuffer(key))) {
8004
+ if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer28.isBuffer(key))) {
7735
8005
  return void 0;
7736
8006
  }
7737
8007
  const usable = keys;
@@ -7764,7 +8034,7 @@ function routedKeyGroups(keys, routeKey) {
7764
8034
  const groups = /* @__PURE__ */ new Map();
7765
8035
  for (let index = 0; index < keys.length; index += 1) {
7766
8036
  const key = keys[index];
7767
- if (typeof key !== "string" && !Buffer26.isBuffer(key)) return void 0;
8037
+ if (typeof key !== "string" && !Buffer28.isBuffer(key)) return void 0;
7768
8038
  const route = routeKey(key);
7769
8039
  const groupKey = `${route.endpointKey}\0${route.laneId}`;
7770
8040
  const group = groups.get(groupKey);
@@ -8005,7 +8275,16 @@ function isExplicitlySafeReroute(error) {
8005
8275
  if (error instanceof ConnectionClosedError) {
8006
8276
  return error.requestDisposition === "unsent";
8007
8277
  }
8008
- return error instanceof RerouteError && getField(error.raw, "safe_to_retry") === true;
8278
+ return error instanceof RerouteError && error.retryable === true && error.safeToRetry === true;
8279
+ }
8280
+ function retryAfterMs(error) {
8281
+ return error instanceof FerricStoreError ? error.retryAfterMs ?? 0 : 0;
8282
+ }
8283
+ async function waitForExplicitlySafeReroute(error) {
8284
+ if (!isExplicitlySafeReroute(error)) return false;
8285
+ const delayMs = retryAfterMs(error);
8286
+ if (delayMs > 0) await sleep(delayMs);
8287
+ return true;
8009
8288
  }
8010
8289
 
8011
8290
  // src/topology-endpoint-trust.ts
@@ -8739,7 +9018,9 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8739
9018
  () => true,
8740
9019
  () => false
8741
9020
  );
8742
- return refreshed && isExplicitlySafeReroute(error);
9021
+ if (!refreshed || !await waitForExplicitlySafeReroute(error)) return false;
9022
+ this.assertOpen();
9023
+ return true;
8743
9024
  }
8744
9025
  async executePipelineOnRoute(commands, route, options) {
8745
9026
  const adapter = await this.adapterForCurrentRoute(route);
@@ -8829,7 +9110,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
8829
9110
  };
8830
9111
 
8831
9112
  // src/response-map-preservation.ts
8832
- import { Buffer as Buffer28 } from "buffer";
9113
+ import { Buffer as Buffer30 } from "buffer";
8833
9114
  function toStringKeyMapPreservingValues(value) {
8834
9115
  if (value == null) return void 0;
8835
9116
  const result = {};
@@ -8839,7 +9120,7 @@ function toStringKeyMapPreservingValues(value) {
8839
9120
  }
8840
9121
  return result;
8841
9122
  }
8842
- if (typeof value === "object" && !Array.isArray(value) && !Buffer28.isBuffer(value) && !(value instanceof Uint8Array)) {
9123
+ if (typeof value === "object" && !Array.isArray(value) && !Buffer30.isBuffer(value) && !(value instanceof Uint8Array)) {
8843
9124
  for (const [key, item] of Object.entries(value)) {
8844
9125
  setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
8845
9126
  }
@@ -8848,7 +9129,7 @@ function toStringKeyMapPreservingValues(value) {
8848
9129
  return void 0;
8849
9130
  }
8850
9131
  function normalizeMapStructurePreservingBytes(value) {
8851
- if (Buffer28.isBuffer(value) || value instanceof Uint8Array) return value;
9132
+ if (Buffer30.isBuffer(value) || value instanceof Uint8Array) return value;
8852
9133
  if (value instanceof Map) {
8853
9134
  const result = {};
8854
9135
  for (const [key, item] of value.entries()) {
@@ -8870,7 +9151,7 @@ function normalizeMapStructurePreservingBytes(value) {
8870
9151
  }
8871
9152
 
8872
9153
  // src/native-kv-responses.ts
8873
- import { Buffer as Buffer29 } from "buffer";
9154
+ import { Buffer as Buffer31 } from "buffer";
8874
9155
  function rateLimitResultFromResp(value) {
8875
9156
  if (!Array.isArray(value) || value.length !== 4) {
8876
9157
  throw new TypeError("RATELIMIT.ADD returned an unexpected response");
@@ -8913,30 +9194,27 @@ function fetchOrComputeResultFromResp(value, codec) {
8913
9194
  shouldCompute: false
8914
9195
  };
8915
9196
  }
8916
- if (status !== "compute") throw new TypeError("FETCH_OR_COMPUTE returned an unexpected response");
9197
+ if (status !== "compute" || value.length !== 3) {
9198
+ throw new TypeError("FETCH_OR_COMPUTE returned an unexpected response");
9199
+ }
8917
9200
  return {
8918
9201
  status,
8919
9202
  computeHint: responseBytes(value[1], "FETCH_OR_COMPUTE"),
8920
- ...value.length === 3 ? {
8921
- computeMode: "fenced",
8922
- computeToken: responseBytes(value[2], "FETCH_OR_COMPUTE")
8923
- } : {
8924
- computeMode: "legacy",
8925
- computeToken: null
8926
- },
9203
+ computeMode: "fenced",
9204
+ computeToken: responseBytes(value[2], "FETCH_OR_COMPUTE"),
8927
9205
  hit: false,
8928
9206
  shouldCompute: true
8929
9207
  };
8930
9208
  }
8931
9209
  function decodePayload(codec, value) {
8932
9210
  if (value == null) return null;
8933
- if (Buffer29.isBuffer(value)) return codec.decode(value);
8934
- if (value instanceof Uint8Array) return codec.decode(Buffer29.from(value));
8935
- if (typeof value === "string") return codec.decode(Buffer29.from(value));
9211
+ if (Buffer31.isBuffer(value)) return codec.decode(value);
9212
+ if (value instanceof Uint8Array) return codec.decode(Buffer31.from(value));
9213
+ if (typeof value === "string") return codec.decode(Buffer31.from(value));
8936
9214
  return normalizeRefMeta(value);
8937
9215
  }
8938
9216
  function requiredResponseString(value, context) {
8939
- if (typeof value !== "string" && !Buffer29.isBuffer(value) && !(value instanceof Uint8Array)) {
9217
+ if (typeof value !== "string" && !Buffer31.isBuffer(value) && !(value instanceof Uint8Array)) {
8940
9218
  throw new TypeError(`${context} returned an unexpected response`);
8941
9219
  }
8942
9220
  const result = text(value);
@@ -8953,7 +9231,7 @@ function requiredNonNegativeInteger(value, context) {
8953
9231
  return result;
8954
9232
  }
8955
9233
  function responseBytes(value, context) {
8956
- if (typeof value !== "string" && !Buffer29.isBuffer(value) && !(value instanceof Uint8Array)) {
9234
+ if (typeof value !== "string" && !Buffer31.isBuffer(value) && !(value instanceof Uint8Array)) {
8957
9235
  throw new TypeError(`${context} returned an unexpected response`);
8958
9236
  }
8959
9237
  return bytes(value);
@@ -9038,6 +9316,9 @@ function flowRecordFromResp(value, codec) {
9038
9316
  field(value, "max_active_ms"),
9039
9317
  "FLOW record max_active_ms"
9040
9318
  );
9319
+ const rawError = field(value, "error");
9320
+ const error = flowError(rawError, codec);
9321
+ const failureReason = optionalResponseString(field(rawError, "reason"), "FLOW record error reason");
9041
9322
  return {
9042
9323
  id: requiredTextField(value, "id", "FLOW record"),
9043
9324
  type: requiredTextField(value, "type", "FLOW record"),
@@ -9052,6 +9333,8 @@ function flowRecordFromResp(value, codec) {
9052
9333
  rootFlowId: optionalResponseString(field(value, "root_flow_id"), "FLOW record root_flow_id"),
9053
9334
  correlationId: optionalResponseString(field(value, "correlation_id"), "FLOW record correlation_id"),
9054
9335
  ...maxActiveMs == null ? {} : { maxActiveMs },
9336
+ ...error == null ? {} : { error },
9337
+ ...failureReason == null ? {} : { failureReason },
9055
9338
  valueRefs: optionalMapField(value, "value_refs", "FLOW record"),
9056
9339
  values,
9057
9340
  valueSizes: optionalMapField(value, "value_sizes", "FLOW record"),
@@ -9063,6 +9346,21 @@ function flowRecordFromResp(value, codec) {
9063
9346
  raw: value
9064
9347
  };
9065
9348
  }
9349
+ function flowError(value, codec) {
9350
+ if (value == null) return void 0;
9351
+ const reason = optionalResponseString(field(value, "reason"), "FLOW record error reason");
9352
+ if (reason === "max_active_ms") {
9353
+ const maxActiveMs = optionalPositiveResponseInteger(
9354
+ field(value, "max_active_ms"),
9355
+ "FLOW record error max_active_ms"
9356
+ );
9357
+ if (maxActiveMs == null) {
9358
+ throw new TypeError("FLOW record error max_active_ms returned an unexpected response");
9359
+ }
9360
+ return { maxActiveMs, reason };
9361
+ }
9362
+ return decodePayload2(codec, value);
9363
+ }
9066
9364
  function decodePayload2(codec, value) {
9067
9365
  if (value == null) {
9068
9366
  return null;
@@ -9643,7 +9941,7 @@ function groupAutoPartitionItems(items) {
9643
9941
  }
9644
9942
 
9645
9943
  // src/client-values.ts
9646
- import { Buffer as Buffer30 } from "buffer";
9944
+ import { Buffer as Buffer32 } from "buffer";
9647
9945
  async function valueMGetEntries(client, refs, options = {}) {
9648
9946
  const refCount = refs.length;
9649
9947
  if (refCount === 0) {
@@ -9678,12 +9976,12 @@ async function valueMGetEntries(client, refs, options = {}) {
9678
9976
  const item = response[index];
9679
9977
  if (item == null) {
9680
9978
  entries[index] = { found: false };
9681
- } else if (Buffer30.isBuffer(item)) {
9979
+ } else if (Buffer32.isBuffer(item)) {
9682
9980
  entries[index] = { found: true, value: client.codec.decode(item) };
9683
9981
  } else if (item instanceof Uint8Array) {
9684
- entries[index] = { found: true, value: client.codec.decode(Buffer30.from(item)) };
9982
+ entries[index] = { found: true, value: client.codec.decode(Buffer32.from(item)) };
9685
9983
  } else if (typeof item === "string") {
9686
- entries[index] = { found: true, value: client.codec.decode(Buffer30.from(item)) };
9984
+ entries[index] = { found: true, value: client.codec.decode(Buffer32.from(item)) };
9687
9985
  } else {
9688
9986
  entries[index] = { found: true, value: item };
9689
9987
  }
@@ -9695,7 +9993,7 @@ async function valueMGetEntries(client, refs, options = {}) {
9695
9993
  import "buffer";
9696
9994
 
9697
9995
  // src/auto-batch-ordering.ts
9698
- import { Buffer as Buffer31 } from "buffer";
9996
+ import { Buffer as Buffer33 } from "buffer";
9699
9997
  function autoBatchOrderingPlan(batch) {
9700
9998
  const accesses = /* @__PURE__ */ new Map();
9701
9999
  const fallbackDependencies = [];
@@ -9810,13 +10108,13 @@ function flowManyAutoBatchIds(command, name) {
9810
10108
  return fixedFlowItemIds(
9811
10109
  command,
9812
10110
  mixed ? 4 : 3,
9813
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && Buffer31.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
10111
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && Buffer33.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
9814
10112
  );
9815
10113
  }
9816
10114
  return fixedFlowItemIds(
9817
10115
  command,
9818
10116
  mixed ? 4 : 3,
9819
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer31.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
10117
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer33.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
9820
10118
  );
9821
10119
  }
9822
10120
  function createManyAutoBatchIds(command) {
@@ -9829,7 +10127,7 @@ function createManyAutoBatchIds(command) {
9829
10127
  const ids = fixedFlowItemIds(
9830
10128
  command,
9831
10129
  width,
9832
- (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer31.isBuffer(command[itemIndex + width - 1]),
10130
+ (itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer33.isBuffer(command[itemIndex + width - 1]),
9833
10131
  markerIndex
9834
10132
  );
9835
10133
  if (ids != null) return ids;
@@ -9847,7 +10145,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
9847
10145
  let cursor = markerIndex + 2;
9848
10146
  for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
9849
10147
  const id = command[cursor];
9850
- if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer31.isBuffer(command[cursor + 2])) return void 0;
10148
+ if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer33.isBuffer(command[cursor + 2])) return void 0;
9851
10149
  ids.push(id);
9852
10150
  cursor += 3;
9853
10151
  const afterValues = skipExtendedNamedItems(command, cursor, true);
@@ -9866,7 +10164,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
9866
10164
  for (let index = 0; index < count; index += 1) {
9867
10165
  const name = command[firstItem + index * 2];
9868
10166
  const value = command[firstItem + index * 2 + 1];
9869
- if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer31.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
10167
+ if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer33.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
9870
10168
  }
9871
10169
  return firstItem + count * 2;
9872
10170
  }
@@ -9881,7 +10179,7 @@ function runStepsManyAutoBatchIds(command) {
9881
10179
  ids.push(item);
9882
10180
  continue;
9883
10181
  }
9884
- if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer31.isBuffer(item)) return void 0;
10182
+ if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer33.isBuffer(item)) return void 0;
9885
10183
  const id = item.id;
9886
10184
  if (!isAutoBatchResourceValue(id)) return void 0;
9887
10185
  ids.push(id);
@@ -9922,7 +10220,7 @@ function flowValuePutOwner(command, start) {
9922
10220
  }
9923
10221
  var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
9924
10222
  function isAutoBatchResourceValue(value) {
9925
- return typeof value === "string" || Buffer31.isBuffer(value);
10223
+ return typeof value === "string" || Buffer33.isBuffer(value);
9926
10224
  }
9927
10225
  function isFencingToken(value) {
9928
10226
  return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
@@ -9931,7 +10229,7 @@ function nonNegativeItemCount(value) {
9931
10229
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
9932
10230
  }
9933
10231
  function autoBatchResourceKey(namespace, value) {
9934
- return `${namespace}:${Buffer31.from(value).toString("base64")}`;
10232
+ return `${namespace}:${Buffer33.from(value).toString("base64")}`;
9935
10233
  }
9936
10234
  function autoBatchCommandName(command) {
9937
10235
  return commandView(command).name ?? null;
@@ -10346,9 +10644,9 @@ import "buffer";
10346
10644
  import "buffer";
10347
10645
 
10348
10646
  // src/client-core-helpers.ts
10349
- import { Buffer as Buffer33 } from "buffer";
10647
+ import { Buffer as Buffer35 } from "buffer";
10350
10648
  function bgsaveResponse(response) {
10351
- if ((typeof response === "string" || Buffer33.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
10649
+ if ((typeof response === "string" || Buffer35.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
10352
10650
  return true;
10353
10651
  }
10354
10652
  return okResponse(response);
@@ -10359,11 +10657,11 @@ function clientNameResponse(response) {
10359
10657
  function fetchOrComputeCompletionToken(options) {
10360
10658
  if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
10361
10659
  throw new TypeError(
10362
- "fetch-or-compute completion requires computeToken; pass null only for a legacy tokenless lease"
10660
+ "fetch-or-compute completion requires computeToken"
10363
10661
  );
10364
10662
  }
10365
- if (options.computeToken !== null && !Buffer33.isBuffer(options.computeToken)) {
10366
- throw new TypeError("fetch-or-compute computeToken must be a Buffer or explicit null for a legacy lease");
10663
+ if (!Buffer35.isBuffer(options.computeToken)) {
10664
+ throw new TypeError("fetch-or-compute computeToken must be a Buffer");
10367
10665
  }
10368
10666
  return options.computeToken;
10369
10667
  }
@@ -10485,14 +10783,17 @@ var FerricStoreClientBase = class {
10485
10783
  };
10486
10784
  }
10487
10785
  async command(...args) {
10786
+ assertAtomicKeyValueCommandSharesSlot(args);
10488
10787
  return await executeCommandArgs(this.executor, args);
10489
10788
  }
10490
10789
  /** Execute an already-built command without a JavaScript variadic-call limit. */
10491
10790
  async commandArgs(args) {
10791
+ assertAtomicKeyValueCommandSharesSlot(args);
10492
10792
  return await executeCommandArgs(this.executor, args);
10493
10793
  }
10494
10794
  async pipeline(commands, options) {
10495
10795
  const snapshot = snapshotPipelineCommands(commands);
10796
+ for (const command of snapshot) assertAtomicKeyValueCommandSharesSlot(command);
10496
10797
  const snapshotOptions = snapshotPipelineOptions(options);
10497
10798
  const results = this.executor.executePipeline != null ? await this.executor.executePipeline(snapshot, snapshotOptions) : await executeCommandArraysIndividually(
10498
10799
  async (command) => await this.commandArgs(command),
@@ -10719,14 +11020,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
10719
11020
  };
10720
11021
 
10721
11022
  // src/store-utilities.ts
10722
- import { Buffer as Buffer36 } from "buffer";
11023
+ import { Buffer as Buffer38 } from "buffer";
10723
11024
  function encode(codec, value) {
10724
11025
  return codec.encode(value);
10725
11026
  }
10726
11027
  function decode(codec, value) {
10727
11028
  if (value == null) return null;
10728
- if (Buffer36.isBuffer(value)) return codec.decode(value);
10729
- if (value instanceof Uint8Array) return codec.decode(Buffer36.from(value));
11029
+ if (Buffer38.isBuffer(value)) return codec.decode(value);
11030
+ if (value instanceof Uint8Array) return codec.decode(Buffer38.from(value));
10730
11031
  return value;
10731
11032
  }
10732
11033
  function number(value) {
@@ -11132,12 +11433,15 @@ var TopKStore = class {
11132
11433
  const width = ownOption(options, "width");
11133
11434
  const depth = ownOption(options, "depth");
11134
11435
  const decay = ownOption(options, "decay");
11135
- const tuningCount = [width, depth, decay].filter((value) => value != null).length;
11136
- if (tuningCount !== 0 && tuningCount !== 3) {
11137
- throw new TypeError("TOPK.RESERVE width, depth, and decay must be provided together");
11436
+ if (decay != null || Object.hasOwn(options, "decay")) {
11437
+ throw new TypeError("TOPK.RESERVE decay is not supported by FerricStore 0.8");
11138
11438
  }
11139
- if (tuningCount === 3) {
11140
- args.push(width, depth, decay);
11439
+ const tuningCount = [width, depth].filter((value) => value != null).length;
11440
+ if (tuningCount !== 0 && tuningCount !== 2) {
11441
+ throw new TypeError("TOPK.RESERVE width and depth must be provided together");
11442
+ }
11443
+ if (tuningCount === 2) {
11444
+ args.push(width, depth);
11141
11445
  }
11142
11446
  return okResponse(await commandArgs(this.client, args));
11143
11447
  }
@@ -11543,10 +11847,14 @@ var KeyValueStore = class {
11543
11847
  );
11544
11848
  }
11545
11849
  async mset(entries) {
11546
- return okResponse(await commandArgs(this.client, keyValueArgs(["MSET"], this.client.codec, entries)));
11850
+ const args = keyValueArgs(["MSET"], this.client.codec, entries);
11851
+ assertKeyValueCommandSharesSlot(args, "MSET");
11852
+ return okResponse(await commandArgs(this.client, args));
11547
11853
  }
11548
11854
  async msetnx(entries) {
11549
- return binaryBooleanResponse(await commandArgs(this.client, keyValueArgs(["MSETNX"], this.client.codec, entries)));
11855
+ const args = keyValueArgs(["MSETNX"], this.client.codec, entries);
11856
+ assertKeyValueCommandSharesSlot(args, "MSETNX");
11857
+ return binaryBooleanResponse(await commandArgs(this.client, args));
11550
11858
  }
11551
11859
  async incr(key) {
11552
11860
  return integerReply(await this.client.command("INCR", key));
@@ -12616,7 +12924,8 @@ var FerricStoreClientCore = class extends FerricStoreAdministrationClient {
12616
12924
  return okResponse(await this.command(
12617
12925
  "FETCH_OR_COMPUTE_RESULT",
12618
12926
  key,
12619
- ...computeToken === null ? [encoded] : [computeToken, encoded],
12927
+ computeToken,
12928
+ encoded,
12620
12929
  options.ttlMs
12621
12930
  ));
12622
12931
  }
@@ -12625,7 +12934,7 @@ var FerricStoreClientCore = class extends FerricStoreAdministrationClient {
12625
12934
  return okResponse(await this.command(
12626
12935
  "FETCH_OR_COMPUTE_ERROR",
12627
12936
  key,
12628
- ...computeToken === null ? [] : [computeToken],
12937
+ computeToken,
12629
12938
  message
12630
12939
  ));
12631
12940
  }
@@ -12751,7 +13060,7 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
12751
13060
  }
12752
13061
  async effectGet(id, effectKey, options = {}) {
12753
13062
  const args = ["FLOW.EFFECT.GET", id, "EFFECT_KEY", effectKey];
12754
- append(args, "PARTITION", options.partitionKey ?? autoPartitionKeyForId(id));
13063
+ append(args, "PARTITION", options.partitionKey);
12755
13064
  return optionalAdminRecord(await this.commandArgs(args), "FLOW.EFFECT.GET");
12756
13065
  }
12757
13066
  async effectStatus(command, id, effectKey, options) {
@@ -12923,7 +13232,7 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
12923
13232
  }
12924
13233
  async governanceLedger(id, options = {}) {
12925
13234
  const args = ["FLOW.GOVERNANCE.LEDGER", id];
12926
- append(args, "PARTITION", options.partitionKey ?? autoPartitionKeyForId(id));
13235
+ append(args, "PARTITION", options.partitionKey);
12927
13236
  append(args, "LIMIT", options.limit);
12928
13237
  append(args, "FROM_MS", options.fromMs);
12929
13238
  append(args, "TO_MS", options.toMs);
@@ -12939,7 +13248,7 @@ async function executeProducerWriteWithBackpressure(execute, policy, signal) {
12939
13248
  try {
12940
13249
  return await execute();
12941
13250
  } catch (error) {
12942
- if (!(error instanceof OverloadedError) || attempt >= policy.maxRetries) throw error;
13251
+ if (!(error instanceof OverloadedError) || error.retryable !== true || error.safeToRetry !== true || attempt >= policy.maxRetries) throw error;
12943
13252
  const exponential = Math.min(policy.maxDelayMs, policy.baseDelayMs * 2 ** attempt);
12944
13253
  const base = Math.min(policy.maxDelayMs, error.retryAfterMs ?? exponential);
12945
13254
  const jitter = base * (policy.jitterPct / 100) * Math.random();
@@ -13204,7 +13513,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
13204
13513
  };
13205
13514
 
13206
13515
  // src/flow-many-snapshot.ts
13207
- import { Buffer as Buffer39 } from "buffer";
13516
+ import { Buffer as Buffer41 } from "buffer";
13208
13517
  var encodedOptionFields = ["error", "payload", "reason", "result"];
13209
13518
  function snapshotCreateItem(item, codec) {
13210
13519
  const snapshot = {
@@ -13244,7 +13553,7 @@ function snapshotFlowManyOptions(options, codec) {
13244
13553
  }
13245
13554
  function snapshotClaimedItem(item) {
13246
13555
  const wire = item[CLAIMED_ITEM_WIRE];
13247
- const leaseToken = Buffer39.from(wire?.leaseToken ?? item.leaseToken);
13556
+ const leaseToken = Buffer41.from(wire?.leaseToken ?? item.leaseToken);
13248
13557
  const snapshot = {
13249
13558
  ...item,
13250
13559
  fencingToken: wire?.fencingToken ?? item.fencingToken,
@@ -13261,15 +13570,15 @@ function snapshotClaimedItem(item) {
13261
13570
  function snapshotFencedItem(item) {
13262
13571
  return Object.freeze({
13263
13572
  ...item,
13264
- ...item.leaseToken == null ? {} : { leaseToken: Buffer39.from(item.leaseToken) }
13573
+ ...item.leaseToken == null ? {} : { leaseToken: Buffer41.from(item.leaseToken) }
13265
13574
  });
13266
13575
  }
13267
13576
  function snapshotClaimedItemWire(wire, leaseToken) {
13268
13577
  return Object.freeze({
13269
13578
  fencingToken: wire.fencingToken,
13270
- id: Buffer39.from(wire.id),
13579
+ id: Buffer41.from(wire.id),
13271
13580
  leaseToken,
13272
- partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer39.from(wire.partitionKey)
13581
+ partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer41.from(wire.partitionKey)
13273
13582
  });
13274
13583
  }
13275
13584
  function snapshotArray(values) {
@@ -13280,7 +13589,7 @@ function snapshotArray(values) {
13280
13589
  return Object.freeze(snapshot);
13281
13590
  }
13282
13591
  function snapshotStateMeta(stateMeta) {
13283
- return snapshotRecord(stateMeta, (value) => Buffer39.isBuffer(value) ? Buffer39.from(value) : value);
13592
+ return snapshotRecord(stateMeta, (value) => Buffer41.isBuffer(value) ? Buffer41.from(value) : value);
13284
13593
  }
13285
13594
  function snapshotCommandRecord(values) {
13286
13595
  const seen = /* @__PURE__ */ new WeakMap();
@@ -13298,7 +13607,7 @@ function snapshotRecord(values, capture) {
13298
13607
  }
13299
13608
  function snapshotCommandArgument(value, seen) {
13300
13609
  if (typeof value !== "object" || value == null) return value;
13301
- if (Buffer39.isBuffer(value) || value instanceof Uint8Array) return Buffer39.from(value);
13610
+ if (Buffer41.isBuffer(value) || value instanceof Uint8Array) return Buffer41.from(value);
13302
13611
  const objectValue = value;
13303
13612
  const existing = seen.get(objectValue);
13304
13613
  if (existing != null) return existing;
@@ -14096,6 +14405,9 @@ var FerricStoreClient = class _FerricStoreClient extends FerricStoreProducerClie
14096
14405
  return new _FerricStoreClient(executor, clientOptions);
14097
14406
  }
14098
14407
  async valuePut(value, options = {}) {
14408
+ if (options.ownerFlowId != null && options.name != null && options.ttlMs != null) {
14409
+ throw new TypeError("named Flow values cannot have a TTL");
14410
+ }
14099
14411
  const args = ["FLOW.VALUE.PUT", this.codec.encode(value), "NOW", options.nowMs ?? nowMs()];
14100
14412
  append(args, "PARTITION", options.partitionKey);
14101
14413
  append(args, "OWNER_FLOW_ID", options.ownerFlowId);
@@ -14127,7 +14439,6 @@ var FerricStoreClient = class _FerricStoreClient extends FerricStoreProducerClie
14127
14439
  append(args, "TRANSITION_TO", options.transitionTo);
14128
14440
  append(args, "RUN_AT", options.runAtMs);
14129
14441
  append(args, "NOW", options.nowMs ?? nowMs());
14130
- append(args, "PRIORITY", options.priority);
14131
14442
  appendNamedValues(args, this.codec, options);
14132
14443
  return await this.commandArgs(args);
14133
14444
  }
@@ -14157,6 +14468,7 @@ var FerricStoreClient = class _FerricStoreClient extends FerricStoreProducerClie
14157
14468
  append(args, "CORRELATION_ID", options.correlationId);
14158
14469
  append(args, "PRIORITY", options.priority);
14159
14470
  append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
14471
+ append(args, "MAX_ACTIVE_MS", options.maxActiveMs);
14160
14472
  appendAttributes(args, options.attributes);
14161
14473
  appendStateMeta(args, options.stateMeta);
14162
14474
  appendNamedValues(args, this.codec, options);
@@ -16262,15 +16574,22 @@ var WorkflowWorker = class {
16262
16574
  );
16263
16575
  }
16264
16576
  };
16577
+
16578
+ // src/version.ts
16579
+ var FERRICSTORE_SDK_VERSION = "0.2.0";
16580
+ var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.8.0";
16581
+ var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
16265
16582
  export {
16266
16583
  BitmapStore,
16267
16584
  BloomFilterStore,
16268
16585
  COMMAND_OPCODES,
16269
- COMPACT_RESPONSE_OPCODES,
16270
16586
  ClaimHydrationError,
16271
16587
  ConnectionClosedError,
16272
16588
  CountMinSketchStore,
16273
16589
  CuckooFilterStore,
16590
+ FERRICSTORE_MINIMUM_SERVER_VERSION,
16591
+ FERRICSTORE_NATIVE_PROTOCOL_VERSION,
16592
+ FERRICSTORE_SDK_VERSION,
16274
16593
  FerricStoreClient,
16275
16594
  FerricStoreError,
16276
16595
  FlowAlreadyExistsError,