@ferricstore/ferricstore 0.1.7 → 0.3.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.
- package/README.md +35 -6
- package/dist/index.cjs +1379 -667
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -33
- package/dist/index.d.ts +83 -33
- package/dist/index.js +1384 -676
- package/dist/index.js.map +1 -1
- package/docs/api/assets/hierarchy.js +1 -1
- package/docs/api/assets/navigation.js +1 -1
- package/docs/api/assets/search.js +1 -1
- package/docs/api/classes/ClaimHydrationError.html +6 -3
- package/docs/api/classes/ConnectionClosedError.html +6 -3
- package/docs/api/classes/FerricStoreClient.html +4 -4
- package/docs/api/classes/FerricStoreError.html +6 -3
- package/docs/api/classes/FlowAlreadyExistsError.html +6 -3
- package/docs/api/classes/FlowBatchError.html +6 -3
- package/docs/api/classes/FlowNotFoundError.html +6 -3
- package/docs/api/classes/FlowWrongStateError.html +6 -3
- package/docs/api/classes/InvalidCommandError.html +6 -3
- package/docs/api/classes/KeyValueStore.html +2 -2
- package/docs/api/classes/LeaseRenewalError.html +1 -1
- package/docs/api/classes/LockHeldError.html +6 -3
- package/docs/api/classes/LockNotOwnedError.html +6 -3
- package/docs/api/classes/NativeAdapter.html +2 -2
- package/docs/api/classes/OverloadedError.html +6 -4
- package/docs/api/classes/QueueCompletionError.html +1 -1
- package/docs/api/classes/ReconnectingExecutor.html +4 -4
- package/docs/api/classes/RequestTimeoutError.html +6 -3
- package/docs/api/classes/RerouteError.html +6 -3
- package/docs/api/classes/StaleLeaseError.html +6 -3
- package/docs/api/classes/StalePolicyGenerationError.html +39 -0
- package/docs/api/classes/TDigestStore.html +2 -2
- package/docs/api/classes/TopKStore.html +1 -1
- package/docs/api/classes/TopologyNativeAdapterPool.html +3 -3
- package/docs/api/classes/Workflow.html +1 -1
- package/docs/api/classes/WorkflowWorker.html +2 -2
- package/docs/api/functions/classifyServerError.html +1 -1
- package/docs/api/functions/isReconnectableClosedConnectionError.html +1 -1
- package/docs/api/functions/mapException.html +1 -1
- package/docs/api/hierarchy.html +1 -1
- package/docs/api/index.html +22 -8
- package/docs/api/interfaces/AdminListOptions.html +1 -1
- package/docs/api/interfaces/CancelOptions.html +2 -2
- package/docs/api/interfaces/ClaimDueOptions.html +3 -3
- package/docs/api/interfaces/CompleteJobsAndClaimJobsResult.html +6 -6
- package/docs/api/interfaces/CompleteManyOptions.html +2 -2
- package/docs/api/interfaces/CompleteOptions.html +2 -2
- package/docs/api/interfaces/CompleteOutcome.html +1 -1
- package/docs/api/interfaces/CreateManyOptions.html +1 -1
- package/docs/api/interfaces/EffectCompensateOptions.html +1 -1
- package/docs/api/interfaces/EffectConfirmOptions.html +1 -1
- package/docs/api/interfaces/EffectFailOptions.html +1 -1
- package/docs/api/interfaces/EffectStatusOptions.html +1 -1
- package/docs/api/interfaces/ExtendLeaseOptions.html +2 -2
- package/docs/api/interfaces/FailOptions.html +2 -2
- package/docs/api/interfaces/FailOutcome.html +1 -1
- package/docs/api/interfaces/FerricStoreClientFromUrlOptions.html +1 -1
- package/docs/api/interfaces/FerricStoreClientOptions.html +1 -1
- package/docs/api/interfaces/{FetchOrComputeLegacyResult.html → FetchOrComputeComputeResult.html} +2 -2
- package/docs/api/interfaces/FlowMaxActiveFailure.html +3 -0
- package/docs/api/interfaces/FlowPolicyBackoffSnapshot.html +5 -0
- package/docs/api/interfaces/FlowPolicyOptions.html +8 -4
- package/docs/api/interfaces/FlowPolicyRetentionSnapshot.html +3 -0
- package/docs/api/interfaces/FlowPolicyRetrySnapshot.html +4 -0
- package/docs/api/interfaces/FlowPolicySnapshot.html +17 -0
- package/docs/api/interfaces/FlowPolicyStateSnapshot.html +6 -0
- package/docs/api/interfaces/FlowRecord.html +4 -2
- package/docs/api/interfaces/FlowStatePolicy.html +2 -2
- package/docs/api/interfaces/HistoryOptions.html +2 -2
- package/docs/api/interfaces/InvocationCreateOptions.html +2 -2
- package/docs/api/interfaces/LeaseMutationOptions.html +2 -2
- package/docs/api/interfaces/LimitListOptions.html +1 -1
- package/docs/api/interfaces/MutateOptions.html +2 -2
- package/docs/api/interfaces/NamedValueMutation.html +1 -1
- package/docs/api/interfaces/ProtocolCommand.html +2 -2
- package/docs/api/interfaces/ReadOptions.html +2 -2
- package/docs/api/interfaces/ReclaimOptions.html +2 -2
- package/docs/api/interfaces/RequestContext.html +2 -2
- package/docs/api/interfaces/RequestContextOptions.html +2 -2
- package/docs/api/interfaces/RetryOptions.html +2 -2
- package/docs/api/interfaces/RetryOutcome.html +1 -1
- package/docs/api/interfaces/RunStepsItem.html +2 -2
- package/docs/api/interfaces/RunStepsManyOptions.html +2 -2
- package/docs/api/interfaces/SearchOptions.html +2 -2
- package/docs/api/interfaces/StartAndClaimOptions.html +4 -2
- package/docs/api/interfaces/StepContinueOptions.html +3 -3
- package/docs/api/interfaces/TDigestCreateOptions.html +1 -1
- package/docs/api/interfaces/TDigestMergeOptions.html +1 -1
- package/docs/api/interfaces/TransitionOptions.html +2 -2
- package/docs/api/interfaces/TransitionOutcome.html +1 -1
- package/docs/api/modules.html +1 -1
- package/docs/api/types/ConnectionRequestDisposition.html +1 -1
- package/docs/api/types/FetchOrComputeFencedResult.html +1 -0
- package/docs/api/types/FetchOrComputeResult.html +1 -1
- package/docs/api/types/FlowPolicyBackoffKind.html +1 -0
- package/docs/api/types/FlowStateMode.html +1 -1
- package/docs/api/types/FlowStatePolicyLike.html +1 -1
- package/docs/api/types/ManagementPairs.html +1 -1
- package/docs/api/types/RequestDisposition.html +1 -1
- package/docs/api/types/SearchStateMeta.html +1 -1
- package/docs/api/types/TopKReserveOptions.html +1 -1
- package/docs/api/variables/COMMAND_OPCODES.html +1 -1
- package/docs/api/variables/FERRICSTORE_MINIMUM_SERVER_VERSION.html +2 -0
- package/docs/api/variables/FERRICSTORE_NATIVE_PROTOCOL_VERSION.html +2 -0
- package/docs/api/variables/FERRICSTORE_SDK_VERSION.html +2 -0
- package/docs/api/variables/MAX_FLOW_POLICY_GENERATION.html +1 -0
- package/package.json +6 -1
- package/docs/api/interfaces/FetchOrComputeFencedResult.html +0 -9
- package/docs/api/types/FetchOrComputeComputeResult.html +0 -1
- 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 {
|
|
@@ -52,6 +58,9 @@ var FlowWrongStateError = class extends FerricStoreError {
|
|
|
52
58
|
var StaleLeaseError = class extends FerricStoreError {
|
|
53
59
|
code = "stale_lease";
|
|
54
60
|
};
|
|
61
|
+
var StalePolicyGenerationError = class extends FerricStoreError {
|
|
62
|
+
code = "stale_policy_generation";
|
|
63
|
+
};
|
|
55
64
|
var FlowAlreadyExistsError = class extends FerricStoreError {
|
|
56
65
|
code = "flow_already_exists";
|
|
57
66
|
};
|
|
@@ -66,11 +75,14 @@ var InvalidCommandError = class extends FerricStoreError {
|
|
|
66
75
|
};
|
|
67
76
|
var OverloadedError = class extends FerricStoreError {
|
|
68
77
|
code = "overloaded";
|
|
69
|
-
retryAfterMs;
|
|
70
78
|
reason;
|
|
71
79
|
constructor(message, options = {}) {
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
const local = options.raw == null;
|
|
81
|
+
super(message, {
|
|
82
|
+
...options,
|
|
83
|
+
retryable: options.retryable ?? (local ? true : void 0),
|
|
84
|
+
safeToRetry: options.safeToRetry ?? (local ? true : void 0)
|
|
85
|
+
});
|
|
74
86
|
this.reason = options.reason;
|
|
75
87
|
}
|
|
76
88
|
};
|
|
@@ -88,15 +100,21 @@ function classifyServerError(message, raw, cause, status) {
|
|
|
88
100
|
const lower = message.toLowerCase();
|
|
89
101
|
const structuredCode = structuredStringField(raw, "code");
|
|
90
102
|
const code = structuredCode?.toLowerCase();
|
|
103
|
+
const retry2 = {
|
|
104
|
+
retryable: structuredBooleanField(raw, "retryable"),
|
|
105
|
+
safeToRetry: structuredBooleanField(raw, "safe_to_retry"),
|
|
106
|
+
retryAfterMs: structuredIntegerField(raw, "retry_after_ms") ?? intField(lower, "retry_after_ms")
|
|
107
|
+
};
|
|
91
108
|
if (isRerouteStatus(status) || code === "reroute") {
|
|
92
|
-
return new RerouteError(message, { cause, raw });
|
|
109
|
+
return new RerouteError(message, { cause, raw, ...definedRetryMetadata(retry2) });
|
|
93
110
|
}
|
|
94
111
|
if (isBusyStatus(status) || isOverloadCode(structuredCode) || overloadMessage(lower)) {
|
|
95
112
|
return new OverloadedError(message, {
|
|
96
113
|
cause,
|
|
97
114
|
raw,
|
|
115
|
+
...definedRetryMetadata(retry2),
|
|
98
116
|
reason: structuredStringField(raw, "reason") ?? structuredCode ?? stringField(lower, "reason"),
|
|
99
|
-
retryAfterMs:
|
|
117
|
+
retryAfterMs: retry2.retryAfterMs
|
|
100
118
|
});
|
|
101
119
|
}
|
|
102
120
|
if (code === "flow_already_exists" || lower.includes("flow") && lower.includes("already exists")) {
|
|
@@ -108,6 +126,9 @@ function classifyServerError(message, raw, cause, status) {
|
|
|
108
126
|
if (code === "stale_lease" || code === "stale_flow_lease" || lower.includes("stale flow lease") || lower.includes("stale lease") || lower.includes("stale token")) {
|
|
109
127
|
return new StaleLeaseError(message, { cause, raw });
|
|
110
128
|
}
|
|
129
|
+
if (code === "stale_generation" || code === "stale_policy_generation" || code === "stale_flow_policy_generation" || lower.includes("stale flow policy generation") || lower.includes("stale policy generation")) {
|
|
130
|
+
return new StalePolicyGenerationError(message, { cause, raw });
|
|
131
|
+
}
|
|
111
132
|
if (code === "flow_not_found" || lower.includes("flow") && (lower.includes("not found") || lower.includes("does not exist"))) {
|
|
112
133
|
return new FlowNotFoundError(message, { cause, raw });
|
|
113
134
|
}
|
|
@@ -120,7 +141,7 @@ function classifyServerError(message, raw, cause, status) {
|
|
|
120
141
|
if (code === "invalid_command" || lower.includes("wrong number of arguments") || lower.includes("syntax error")) {
|
|
121
142
|
return new InvalidCommandError(message, { cause, raw });
|
|
122
143
|
}
|
|
123
|
-
return new FerricStoreError(message, { cause, raw });
|
|
144
|
+
return new FerricStoreError(message, { cause, raw, ...definedRetryMetadata(retry2) });
|
|
124
145
|
}
|
|
125
146
|
function mapException(error) {
|
|
126
147
|
if (error instanceof FerricStoreError) {
|
|
@@ -160,8 +181,23 @@ function structuredIntegerField(raw, name) {
|
|
|
160
181
|
if (typeof value === "bigint") {
|
|
161
182
|
return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
|
|
162
183
|
}
|
|
163
|
-
const
|
|
164
|
-
return
|
|
184
|
+
const text3 = binaryText(value);
|
|
185
|
+
return text3 == null ? void 0 : nonNegativeSafeIntegerText(text3);
|
|
186
|
+
}
|
|
187
|
+
function structuredBooleanField(raw, name) {
|
|
188
|
+
const value = structuredField(raw, name);
|
|
189
|
+
if (typeof value === "boolean") return value;
|
|
190
|
+
const text3 = binaryText(value)?.toLowerCase();
|
|
191
|
+
if (text3 === "true" || text3 === "1") return true;
|
|
192
|
+
if (text3 === "false" || text3 === "0") return false;
|
|
193
|
+
return void 0;
|
|
194
|
+
}
|
|
195
|
+
function definedRetryMetadata(metadata) {
|
|
196
|
+
return {
|
|
197
|
+
...metadata.retryable == null ? {} : { retryable: metadata.retryable },
|
|
198
|
+
...metadata.safeToRetry == null ? {} : { safeToRetry: metadata.safeToRetry },
|
|
199
|
+
...metadata.retryAfterMs == null ? {} : { retryAfterMs: metadata.retryAfterMs }
|
|
200
|
+
};
|
|
165
201
|
}
|
|
166
202
|
function nonNegativeSafeIntegerText(value) {
|
|
167
203
|
if (!/^[0-9]+$/u.test(value)) return void 0;
|
|
@@ -334,9 +370,6 @@ function mapDenseResponseArray(value, transform) {
|
|
|
334
370
|
return result;
|
|
335
371
|
}
|
|
336
372
|
|
|
337
|
-
// src/auto-partition.ts
|
|
338
|
-
import { Buffer as Buffer3 } from "buffer";
|
|
339
|
-
|
|
340
373
|
// src/crc32.ts
|
|
341
374
|
import "buffer";
|
|
342
375
|
var table = new Uint32Array(256);
|
|
@@ -354,12 +387,49 @@ function crc32(buffer) {
|
|
|
354
387
|
}
|
|
355
388
|
return (value ^ 4294967295) >>> 0;
|
|
356
389
|
}
|
|
390
|
+
function crc32Utf8(text3, start = 0, end = text3.length) {
|
|
391
|
+
let value = 4294967295;
|
|
392
|
+
for (let index = start; index < end; index += 1) {
|
|
393
|
+
const first = text3.charCodeAt(index);
|
|
394
|
+
let point = first;
|
|
395
|
+
if (first >= 55296 && first <= 56319) {
|
|
396
|
+
const second = index + 1 < end ? text3.charCodeAt(index + 1) : 0;
|
|
397
|
+
if (second >= 56320 && second <= 57343) {
|
|
398
|
+
point = 65536 + (first - 55296 << 10) + second - 56320;
|
|
399
|
+
index += 1;
|
|
400
|
+
} else {
|
|
401
|
+
point = 65533;
|
|
402
|
+
}
|
|
403
|
+
} else if (first >= 56320 && first <= 57343) {
|
|
404
|
+
point = 65533;
|
|
405
|
+
}
|
|
406
|
+
if (point < 128) {
|
|
407
|
+
value = updateCrc32(value, point);
|
|
408
|
+
} else if (point < 2048) {
|
|
409
|
+
value = updateCrc32(value, 192 | point >>> 6);
|
|
410
|
+
value = updateCrc32(value, 128 | point & 63);
|
|
411
|
+
} else if (point < 65536) {
|
|
412
|
+
value = updateCrc32(value, 224 | point >>> 12);
|
|
413
|
+
value = updateCrc32(value, 128 | point >>> 6 & 63);
|
|
414
|
+
value = updateCrc32(value, 128 | point & 63);
|
|
415
|
+
} else {
|
|
416
|
+
value = updateCrc32(value, 240 | point >>> 18);
|
|
417
|
+
value = updateCrc32(value, 128 | point >>> 12 & 63);
|
|
418
|
+
value = updateCrc32(value, 128 | point >>> 6 & 63);
|
|
419
|
+
value = updateCrc32(value, 128 | point & 63);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return (value ^ 4294967295) >>> 0;
|
|
423
|
+
}
|
|
424
|
+
function updateCrc32(value, byte) {
|
|
425
|
+
return value >>> 8 ^ (table[(value ^ byte) & 255] ?? 0);
|
|
426
|
+
}
|
|
357
427
|
|
|
358
428
|
// src/auto-partition.ts
|
|
359
429
|
var AUTO_PARTITION_PREFIX = "__flow_auto__:";
|
|
360
430
|
var AUTO_PARTITION_BUCKETS = 256;
|
|
361
431
|
function autoPartitionKeyForId(id) {
|
|
362
|
-
return `${AUTO_PARTITION_PREFIX}${
|
|
432
|
+
return `${AUTO_PARTITION_PREFIX}${crc32Utf8(id) % AUTO_PARTITION_BUCKETS}`;
|
|
363
433
|
}
|
|
364
434
|
|
|
365
435
|
// src/flow-argument-helpers.ts
|
|
@@ -752,7 +822,7 @@ function coerceDiagnosticValue(value) {
|
|
|
752
822
|
// src/native-connection.ts
|
|
753
823
|
import net from "net";
|
|
754
824
|
import tls from "tls";
|
|
755
|
-
import { Buffer as
|
|
825
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
756
826
|
function parseFerricUrl(value) {
|
|
757
827
|
const url = new URL(value);
|
|
758
828
|
if (url.protocol !== "ferric:" && url.protocol !== "ferrics:") {
|
|
@@ -878,7 +948,7 @@ function nonNegativeSafeInteger(value) {
|
|
|
878
948
|
if (typeof value === "bigint") {
|
|
879
949
|
return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
|
|
880
950
|
}
|
|
881
|
-
const source =
|
|
951
|
+
const source = Buffer3.isBuffer(value) || value instanceof Uint8Array ? Buffer3.from(value).toString("utf8") : value;
|
|
882
952
|
if (typeof source !== "number" && (typeof source !== "string" || !/^\d+$/u.test(source))) {
|
|
883
953
|
return void 0;
|
|
884
954
|
}
|
|
@@ -1112,10 +1182,10 @@ var NativeHeartbeat = class {
|
|
|
1112
1182
|
};
|
|
1113
1183
|
|
|
1114
1184
|
// src/protocol.ts
|
|
1115
|
-
import { Buffer as
|
|
1185
|
+
import { Buffer as Buffer23 } from "buffer";
|
|
1116
1186
|
|
|
1117
1187
|
// src/command-grammar.ts
|
|
1118
|
-
import { Buffer as
|
|
1188
|
+
import { Buffer as Buffer4 } from "buffer";
|
|
1119
1189
|
|
|
1120
1190
|
// src/command-metadata-flow.ts
|
|
1121
1191
|
var flowStateIdCommands = /* @__PURE__ */ new Set([
|
|
@@ -1562,8 +1632,8 @@ var secondKeySubcommands = /* @__PURE__ */ new Map([
|
|
|
1562
1632
|
]);
|
|
1563
1633
|
function commandToken(value) {
|
|
1564
1634
|
if (typeof value === "string") return value.toUpperCase();
|
|
1565
|
-
if (
|
|
1566
|
-
return
|
|
1635
|
+
if (Buffer4.isBuffer(value) || value instanceof Uint8Array) {
|
|
1636
|
+
return Buffer4.from(value).toString("utf8").toUpperCase();
|
|
1567
1637
|
}
|
|
1568
1638
|
return void 0;
|
|
1569
1639
|
}
|
|
@@ -1666,7 +1736,7 @@ function safeIntegerArgument(value) {
|
|
|
1666
1736
|
if (typeof value === "bigint") {
|
|
1667
1737
|
return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
|
|
1668
1738
|
}
|
|
1669
|
-
const source = typeof value === "string" ? value :
|
|
1739
|
+
const source = typeof value === "string" ? value : Buffer4.isBuffer(value) || value instanceof Uint8Array ? Buffer4.from(value).toString("utf8") : void 0;
|
|
1670
1740
|
if (source == null || !/^[+-]?\d+$/u.test(source)) return void 0;
|
|
1671
1741
|
const parsed = BigInt(source);
|
|
1672
1742
|
return parsed >= BigInt(Number.MIN_SAFE_INTEGER) && parsed <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(parsed) : void 0;
|
|
@@ -1719,7 +1789,7 @@ function hasOwnCommandArgument(args, index, end, section) {
|
|
|
1719
1789
|
}
|
|
1720
1790
|
|
|
1721
1791
|
// src/protocol-core.ts
|
|
1722
|
-
import { Buffer as
|
|
1792
|
+
import { Buffer as Buffer8 } from "buffer";
|
|
1723
1793
|
|
|
1724
1794
|
// src/protocol-constants.ts
|
|
1725
1795
|
import "buffer";
|
|
@@ -1927,80 +1997,30 @@ var OPCODES = {
|
|
|
1927
1997
|
flowFail: COMMAND_OPCODES["FLOW.FAIL"],
|
|
1928
1998
|
flowValuePut: COMMAND_OPCODES["FLOW.VALUE.PUT"],
|
|
1929
1999
|
flowValueMGet: COMMAND_OPCODES["FLOW.VALUE.MGET"],
|
|
2000
|
+
flowSignal: COMMAND_OPCODES["FLOW.SIGNAL"],
|
|
1930
2001
|
flowCreateMany: COMMAND_OPCODES["FLOW.CREATE_MANY"],
|
|
1931
2002
|
flowCompleteMany: COMMAND_OPCODES["FLOW.COMPLETE_MANY"],
|
|
1932
2003
|
flowTransitionMany: COMMAND_OPCODES["FLOW.TRANSITION_MANY"],
|
|
1933
2004
|
flowRetryMany: COMMAND_OPCODES["FLOW.RETRY_MANY"],
|
|
1934
2005
|
flowFailMany: COMMAND_OPCODES["FLOW.FAIL_MANY"],
|
|
1935
2006
|
flowReclaim: COMMAND_OPCODES["FLOW.RECLAIM"],
|
|
2007
|
+
flowPolicySet: COMMAND_OPCODES["FLOW.POLICY.SET"],
|
|
2008
|
+
flowPolicyGet: COMMAND_OPCODES["FLOW.POLICY.GET"],
|
|
1936
2009
|
flowSpawnChildren: COMMAND_OPCODES["FLOW.SPAWN_CHILDREN"],
|
|
1937
2010
|
flowStepContinue: COMMAND_OPCODES["FLOW.STEP_CONTINUE"],
|
|
1938
2011
|
flowStartAndClaim: COMMAND_OPCODES["FLOW.START_AND_CLAIM"],
|
|
1939
2012
|
flowRunStepsMany: COMMAND_OPCODES["FLOW.RUN_STEPS_MANY"],
|
|
1940
2013
|
flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
|
|
1941
2014
|
};
|
|
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
2015
|
var COMPACT_FLOW_CLAIM_JOBS = 128;
|
|
1999
2016
|
var COMPACT_OK_LIST = 129;
|
|
2000
2017
|
var COMPACT_KV_GET = 130;
|
|
2001
2018
|
var COMPACT_KV_MGET = 131;
|
|
2002
2019
|
var COMPACT_FLOW_RECORD = 132;
|
|
2003
2020
|
var COMPACT_FLOW_RECORD_LIST = 133;
|
|
2021
|
+
var COMPACT_BINARY_LIST_LIST = 134;
|
|
2022
|
+
var COMPACT_BINARY_MAP_LIST = 135;
|
|
2023
|
+
var COMPACT_INTEGER_LIST = 136;
|
|
2004
2024
|
var COMPACT_KV_MGET_FIXED = 137;
|
|
2005
2025
|
var COMPACT_FLOW_CREATE_MANY_REQUEST = 144;
|
|
2006
2026
|
var COMPACT_FLOW_CLAIM_DUE_REQUEST = 145;
|
|
@@ -2070,16 +2090,16 @@ var FLOW_RECORD_FIELD_KEYS = [
|
|
|
2070
2090
|
];
|
|
2071
2091
|
|
|
2072
2092
|
// src/protocol-text.ts
|
|
2073
|
-
import { Buffer as
|
|
2093
|
+
import { Buffer as Buffer6 } from "buffer";
|
|
2074
2094
|
function toBuffer(value) {
|
|
2075
|
-
if (
|
|
2076
|
-
if (value instanceof Uint8Array) return
|
|
2077
|
-
if (typeof value === "string") return
|
|
2095
|
+
if (Buffer6.isBuffer(value)) return value;
|
|
2096
|
+
if (value instanceof Uint8Array) return Buffer6.from(value);
|
|
2097
|
+
if (typeof value === "string") return Buffer6.from(value);
|
|
2078
2098
|
if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
2079
|
-
return
|
|
2099
|
+
return Buffer6.from(String(value));
|
|
2080
2100
|
}
|
|
2081
|
-
if (typeof value === "symbol") return
|
|
2082
|
-
if (value == null) return
|
|
2101
|
+
if (typeof value === "symbol") return Buffer6.from(value.description ?? value.toString());
|
|
2102
|
+
if (value == null) return Buffer6.alloc(0);
|
|
2083
2103
|
throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
|
|
2084
2104
|
}
|
|
2085
2105
|
function asText(value) {
|
|
@@ -2087,14 +2107,14 @@ function asText(value) {
|
|
|
2087
2107
|
}
|
|
2088
2108
|
function optionalText(value) {
|
|
2089
2109
|
if (value == null || value === "") return void 0;
|
|
2090
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" ||
|
|
2110
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || Buffer6.isBuffer(value) || value instanceof Uint8Array) {
|
|
2091
2111
|
return asText(value);
|
|
2092
2112
|
}
|
|
2093
2113
|
return void 0;
|
|
2094
2114
|
}
|
|
2095
2115
|
function commandTokenIs(value, expected) {
|
|
2096
2116
|
if (typeof value === "string") return value.toUpperCase() === expected;
|
|
2097
|
-
if (
|
|
2117
|
+
if (Buffer6.isBuffer(value) || value instanceof Uint8Array) {
|
|
2098
2118
|
return asText(value).toUpperCase() === expected;
|
|
2099
2119
|
}
|
|
2100
2120
|
return false;
|
|
@@ -2108,7 +2128,7 @@ function commandNameIs(value, expected) {
|
|
|
2108
2128
|
}
|
|
2109
2129
|
|
|
2110
2130
|
// src/request-context.ts
|
|
2111
|
-
import { Buffer as
|
|
2131
|
+
import { Buffer as Buffer7 } from "buffer";
|
|
2112
2132
|
var requestContextCommands = /* @__PURE__ */ new Set([
|
|
2113
2133
|
"INVOCATION.CREATE",
|
|
2114
2134
|
"INVOCATION.DEFINITION.GET",
|
|
@@ -2163,9 +2183,9 @@ function requestContextCommandToken(value) {
|
|
|
2163
2183
|
const upper = value.toUpperCase();
|
|
2164
2184
|
return isRequestContextCommand(upper) ? upper : void 0;
|
|
2165
2185
|
}
|
|
2166
|
-
if (
|
|
2186
|
+
if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
|
|
2167
2187
|
if (value[0] !== 73 && value[0] !== 105) return void 0;
|
|
2168
|
-
const command =
|
|
2188
|
+
const command = Buffer7.from(value).toString("utf8").toUpperCase();
|
|
2169
2189
|
return isRequestContextCommand(command) ? command : void 0;
|
|
2170
2190
|
}
|
|
2171
2191
|
return void 0;
|
|
@@ -2196,12 +2216,12 @@ function requestContextText(context, fieldName) {
|
|
|
2196
2216
|
return value;
|
|
2197
2217
|
}
|
|
2198
2218
|
function isPlainObject(value) {
|
|
2199
|
-
return typeof value === "object" && value != null && !Array.isArray(value) && !
|
|
2219
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer7.isBuffer(value) && !(value instanceof Uint8Array);
|
|
2200
2220
|
}
|
|
2201
2221
|
function commandToken2(value) {
|
|
2202
2222
|
if (typeof value === "string") return value.toUpperCase();
|
|
2203
|
-
if (
|
|
2204
|
-
return
|
|
2223
|
+
if (Buffer7.isBuffer(value) || value instanceof Uint8Array) {
|
|
2224
|
+
return Buffer7.from(value).toString("utf8").toUpperCase();
|
|
2205
2225
|
}
|
|
2206
2226
|
return "";
|
|
2207
2227
|
}
|
|
@@ -2291,17 +2311,17 @@ function requestFrameTooLarge(maxBytes) {
|
|
|
2291
2311
|
);
|
|
2292
2312
|
}
|
|
2293
2313
|
function binaryValueByteLength(value) {
|
|
2294
|
-
if (
|
|
2295
|
-
if (typeof value === "string") return
|
|
2314
|
+
if (Buffer8.isBuffer(value) || value instanceof Uint8Array) return value.byteLength;
|
|
2315
|
+
if (typeof value === "string") return Buffer8.byteLength(value);
|
|
2296
2316
|
if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
2297
|
-
return
|
|
2317
|
+
return Buffer8.byteLength(String(value));
|
|
2298
2318
|
}
|
|
2299
|
-
if (typeof value === "symbol") return
|
|
2319
|
+
if (typeof value === "symbol") return Buffer8.byteLength(value.description ?? value.toString());
|
|
2300
2320
|
if (value == null) return 0;
|
|
2301
2321
|
return toBuffer(value).byteLength;
|
|
2302
2322
|
}
|
|
2303
2323
|
function writeCustomPayload(output, offset, value, knownByteLength) {
|
|
2304
|
-
if (
|
|
2324
|
+
if (Buffer8.isBuffer(value)) {
|
|
2305
2325
|
value.copy(output, offset);
|
|
2306
2326
|
return;
|
|
2307
2327
|
}
|
|
@@ -2310,17 +2330,17 @@ function writeCustomPayload(output, offset, value, knownByteLength) {
|
|
|
2310
2330
|
return;
|
|
2311
2331
|
}
|
|
2312
2332
|
if (value == null) return;
|
|
2313
|
-
let
|
|
2333
|
+
let text3;
|
|
2314
2334
|
if (typeof value === "string") {
|
|
2315
|
-
|
|
2335
|
+
text3 = value;
|
|
2316
2336
|
} else if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
2317
|
-
|
|
2337
|
+
text3 = String(value);
|
|
2318
2338
|
} else if (typeof value === "symbol") {
|
|
2319
|
-
|
|
2339
|
+
text3 = value.description ?? value.toString();
|
|
2320
2340
|
} else {
|
|
2321
2341
|
throw new FerricStoreError(`unsupported binary command argument type: ${typeof value}`);
|
|
2322
2342
|
}
|
|
2323
|
-
output.write(
|
|
2343
|
+
output.write(text3, offset, knownByteLength ?? Buffer8.byteLength(text3), "utf8");
|
|
2324
2344
|
}
|
|
2325
2345
|
function compactBinaryEncodedLength(value) {
|
|
2326
2346
|
return 4 + compactBinaryByteLength(value);
|
|
@@ -2333,10 +2353,10 @@ function compactBinaryByteLength(value) {
|
|
|
2333
2353
|
return byteLength;
|
|
2334
2354
|
}
|
|
2335
2355
|
function isCompactBinaryArgument(value) {
|
|
2336
|
-
return typeof value === "string" ||
|
|
2356
|
+
return typeof value === "string" || Buffer8.isBuffer(value) || value instanceof Uint8Array;
|
|
2337
2357
|
}
|
|
2338
2358
|
function isCompactBinaryScalar(value) {
|
|
2339
|
-
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" ||
|
|
2359
|
+
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || typeof value === "symbol" || Buffer8.isBuffer(value) || value instanceof Uint8Array;
|
|
2340
2360
|
}
|
|
2341
2361
|
function compactOptionalBinaryEncodedLength(value) {
|
|
2342
2362
|
return value == null ? 4 : compactBinaryEncodedLength(value);
|
|
@@ -2419,13 +2439,13 @@ function i64Arg(value) {
|
|
|
2419
2439
|
}
|
|
2420
2440
|
function boolArg(value) {
|
|
2421
2441
|
if (typeof value === "boolean") return value;
|
|
2422
|
-
const
|
|
2423
|
-
return
|
|
2442
|
+
const text3 = asText(value).toUpperCase();
|
|
2443
|
+
return text3 === "1" || text3 === "TRUE" || text3 === "YES" || text3 === "ON";
|
|
2424
2444
|
}
|
|
2425
2445
|
function isBoolToken(value) {
|
|
2426
2446
|
if (typeof value === "boolean") return true;
|
|
2427
|
-
const
|
|
2428
|
-
return
|
|
2447
|
+
const text3 = asText(value).toUpperCase();
|
|
2448
|
+
return text3 === "1" || text3 === "0" || text3 === "TRUE" || text3 === "FALSE" || text3 === "YES" || text3 === "NO" || text3 === "ON" || text3 === "OFF";
|
|
2429
2449
|
}
|
|
2430
2450
|
function independentMode(value) {
|
|
2431
2451
|
if (value === true) return 2;
|
|
@@ -2467,7 +2487,23 @@ function setOwnValue2(target, key, value) {
|
|
|
2467
2487
|
}
|
|
2468
2488
|
|
|
2469
2489
|
// src/protocol-flow-options.ts
|
|
2470
|
-
import { Buffer as
|
|
2490
|
+
import { Buffer as Buffer9 } from "buffer";
|
|
2491
|
+
|
|
2492
|
+
// src/protocol-flow-option-value.ts
|
|
2493
|
+
function setFlowOptionValue(payload, field2, value, repeat) {
|
|
2494
|
+
if (!repeat || !Object.hasOwn(payload, field2)) {
|
|
2495
|
+
setOwnValue2(payload, field2, value);
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
const previous = payload[field2];
|
|
2499
|
+
setOwnValue2(
|
|
2500
|
+
payload,
|
|
2501
|
+
field2,
|
|
2502
|
+
Array.isArray(previous) ? [...previous, value] : [previous, value]
|
|
2503
|
+
);
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
// src/protocol-flow-options.ts
|
|
2471
2507
|
var OPTION_FIELDS = {
|
|
2472
2508
|
CONSISTENT_PROJECTION: "consistent_projection",
|
|
2473
2509
|
COUNT: "count",
|
|
@@ -2542,7 +2578,7 @@ function normalizeFlowSearchStateMeta(payload) {
|
|
|
2542
2578
|
payload.state_meta = { [asText(state)]: stateMeta };
|
|
2543
2579
|
}
|
|
2544
2580
|
function isPlainObject2(value) {
|
|
2545
|
-
return typeof value === "object" && value != null && !Array.isArray(value) && !
|
|
2581
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer9.isBuffer(value) && !(value instanceof Uint8Array);
|
|
2546
2582
|
}
|
|
2547
2583
|
function parseFlowOptions(args, start, end, config) {
|
|
2548
2584
|
const payload = {};
|
|
@@ -2636,8 +2672,9 @@ function parseFlowOptions(args, start, end, config) {
|
|
|
2636
2672
|
case "TRANSITION_TO":
|
|
2637
2673
|
case "TO_EVENT":
|
|
2638
2674
|
case "EXPECT_STATE": {
|
|
2639
|
-
const field2 = token.toLowerCase();
|
|
2640
|
-
if (!
|
|
2675
|
+
const field2 = token === "IDEMPOTENCY" ? "idempotency_key" : token.toLowerCase();
|
|
2676
|
+
if (!hasOwnCommandArgument(args, index + 1, end, "Flow options")) return void 0;
|
|
2677
|
+
setFlowOptionValue(payload, field2, args[index + 1], token === "IF_STATE");
|
|
2641
2678
|
index += 2;
|
|
2642
2679
|
break;
|
|
2643
2680
|
}
|
|
@@ -2927,6 +2964,7 @@ var FLOW_ADMIN_FIELDS = {
|
|
|
2927
2964
|
LEASE_MS: "lease_ms",
|
|
2928
2965
|
LEASE_TOKEN: "lease_token",
|
|
2929
2966
|
LIMIT: "limit",
|
|
2967
|
+
MAX_ACTIVE_MS: "max_active_ms",
|
|
2930
2968
|
MAX_FIRES: "max_fires",
|
|
2931
2969
|
MAXBYTES: "payload_max_bytes",
|
|
2932
2970
|
NOW: "now_ms",
|
|
@@ -2936,7 +2974,6 @@ var FLOW_ADMIN_FIELDS = {
|
|
|
2936
2974
|
OVERLAP_RETRY_MS: "overlap_retry_ms",
|
|
2937
2975
|
OVERWRITE: "overwrite",
|
|
2938
2976
|
PARENT_FLOW_ID: "parent_flow_id",
|
|
2939
|
-
PARENT_ID: "parent_id",
|
|
2940
2977
|
PARTITION: "partition_key",
|
|
2941
2978
|
PAYLOAD: "payload",
|
|
2942
2979
|
PAYLOAD_MAX_BYTES: "payload_max_bytes",
|
|
@@ -2951,7 +2988,6 @@ var FLOW_ADMIN_FIELDS = {
|
|
|
2951
2988
|
REV: "rev",
|
|
2952
2989
|
RETURN: "return",
|
|
2953
2990
|
ROOT_FLOW_ID: "root_flow_id",
|
|
2954
|
-
ROOT_ID: "root_id",
|
|
2955
2991
|
SCOPE: "scope",
|
|
2956
2992
|
SHARD_ID: "shard_id",
|
|
2957
2993
|
START_AT_MS: "start_at_ms",
|
|
@@ -3088,7 +3124,7 @@ function flowAdminPayload(opcode, args, leadingFields = []) {
|
|
|
3088
3124
|
}
|
|
3089
3125
|
|
|
3090
3126
|
// src/protocol-flow-compact.ts
|
|
3091
|
-
import { Buffer as
|
|
3127
|
+
import { Buffer as Buffer11 } from "buffer";
|
|
3092
3128
|
|
|
3093
3129
|
// src/protocol-flow-compact-common.ts
|
|
3094
3130
|
function compactManyRequestTag(value, regularTag, okOnSuccessTag) {
|
|
@@ -3197,7 +3233,7 @@ function parseNamedCountMap(values, start) {
|
|
|
3197
3233
|
}
|
|
3198
3234
|
|
|
3199
3235
|
// src/protocol-flow-compact-transition.ts
|
|
3200
|
-
import { Buffer as
|
|
3236
|
+
import { Buffer as Buffer10 } from "buffer";
|
|
3201
3237
|
function compactFlowTransitionManyPayload(partition, fromState, toState, rawItems, mixed, options, maxBodyBytes) {
|
|
3202
3238
|
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
3239
|
return void 0;
|
|
@@ -3249,7 +3285,7 @@ function compactFlowTransitionManyPayload(partition, fromState, toState, rawItem
|
|
|
3249
3285
|
total += 4 + idLength + 4 + itemPartitionLength + 8 + 4 + leaseLength;
|
|
3250
3286
|
}
|
|
3251
3287
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3252
|
-
const out =
|
|
3288
|
+
const out = Buffer10.allocUnsafe(total);
|
|
3253
3289
|
let offset = 0;
|
|
3254
3290
|
out.writeUInt8(tag, offset);
|
|
3255
3291
|
offset += 1;
|
|
@@ -3307,7 +3343,7 @@ function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options,
|
|
|
3307
3343
|
}
|
|
3308
3344
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3309
3345
|
const tag = mixed ? COMPACT_FLOW_CREATE_MANY_MIXED_REQUEST : auto ? COMPACT_FLOW_CREATE_MANY_REQUEST : COMPACT_FLOW_CREATE_MANY_PARTITION_REQUEST;
|
|
3310
|
-
const out =
|
|
3346
|
+
const out = Buffer11.allocUnsafe(total);
|
|
3311
3347
|
let offset = 0;
|
|
3312
3348
|
out.writeUInt8(tag, offset++);
|
|
3313
3349
|
offset = writeBinary(out, offset, toBuffer(options.type));
|
|
@@ -3352,7 +3388,7 @@ function compactFlowClaimDuePayload(type, options, maxBodyBytes) {
|
|
|
3352
3388
|
total += 1;
|
|
3353
3389
|
}
|
|
3354
3390
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3355
|
-
const out =
|
|
3391
|
+
const out = Buffer11.allocUnsafe(total);
|
|
3356
3392
|
let offset = 0;
|
|
3357
3393
|
out.writeUInt8(COMPACT_FLOW_CLAIM_DUE_REQUEST, offset++);
|
|
3358
3394
|
offset = writeBinary(out, offset, toBuffer(type));
|
|
@@ -3406,7 +3442,7 @@ function compactFlowCompleteManyPayload(opcode, partition, rawItems, mixed, auto
|
|
|
3406
3442
|
total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
|
|
3407
3443
|
}
|
|
3408
3444
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3409
|
-
const out =
|
|
3445
|
+
const out = Buffer11.allocUnsafe(total);
|
|
3410
3446
|
let offset = 0;
|
|
3411
3447
|
out.writeUInt8(
|
|
3412
3448
|
returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_COMPLETE_MANY_OK_REQUEST : COMPACT_FLOW_COMPLETE_MANY_REQUEST,
|
|
@@ -3453,7 +3489,7 @@ function compactFlowRetryManyPayload(partition, rawItems, mixed, auto, options,
|
|
|
3453
3489
|
total += compactBinaryEncodedLength(rawItems[rawIndex]) + compactOptionalBinaryEncodedLength(mixed ? rawItems[rawIndex + 1] : null) + compactBinaryEncodedLength(rawItems[rawIndex + width - 2]) + 8;
|
|
3454
3490
|
}
|
|
3455
3491
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3456
|
-
const out =
|
|
3492
|
+
const out = Buffer11.allocUnsafe(total);
|
|
3457
3493
|
let offset = 0;
|
|
3458
3494
|
out.writeUInt8(
|
|
3459
3495
|
returnMode === "OK_ON_SUCCESS" ? COMPACT_FLOW_RETRY_MANY_OK_REQUEST : COMPACT_FLOW_RETRY_MANY_REQUEST,
|
|
@@ -3541,7 +3577,7 @@ function compactFlowCancelManyPayload(args, maxBodyBytes) {
|
|
|
3541
3577
|
total += 4 + idLength + 4 + itemPartitionLength + 8;
|
|
3542
3578
|
}
|
|
3543
3579
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3544
|
-
const out =
|
|
3580
|
+
const out = Buffer11.allocUnsafe(total);
|
|
3545
3581
|
let offset = 0;
|
|
3546
3582
|
out.writeUInt8(tag, offset);
|
|
3547
3583
|
offset += 1;
|
|
@@ -3577,7 +3613,7 @@ function isOptionalSafeIntegerNumber(value) {
|
|
|
3577
3613
|
}
|
|
3578
3614
|
|
|
3579
3615
|
// src/protocol-flow-compact-single.ts
|
|
3580
|
-
import { Buffer as
|
|
3616
|
+
import { Buffer as Buffer12 } from "buffer";
|
|
3581
3617
|
function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
|
|
3582
3618
|
if (refs.length > 4294967295 || maxBytes != null && (typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 0)) return void 0;
|
|
3583
3619
|
const minimum = 13 + refs.length * 4;
|
|
@@ -3594,7 +3630,7 @@ function compactFlowValueMGetPayload(refs, maxBytes, maxBodyBytes) {
|
|
|
3594
3630
|
total += 4 + byteLength;
|
|
3595
3631
|
}
|
|
3596
3632
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3597
|
-
const out =
|
|
3633
|
+
const out = Buffer12.allocUnsafe(total);
|
|
3598
3634
|
let offset = 0;
|
|
3599
3635
|
out.writeUInt8(COMPACT_FLOW_VALUE_MGET_REQUEST, offset);
|
|
3600
3636
|
offset += 1;
|
|
@@ -3637,7 +3673,7 @@ function compactFlowListPayload(args, maxBodyBytes) {
|
|
|
3637
3673
|
const stateLength = state == null ? 0 : compactBinaryByteLength(state);
|
|
3638
3674
|
const total = 1 + 4 + typeLength + 4 + stateLength + 8 + 1;
|
|
3639
3675
|
assertCompactPayloadFits(total, maxBodyBytes);
|
|
3640
|
-
const out =
|
|
3676
|
+
const out = Buffer12.allocUnsafe(total);
|
|
3641
3677
|
let offset = 0;
|
|
3642
3678
|
out.writeUInt8(COMPACT_FLOW_LIST_REQUEST, offset);
|
|
3643
3679
|
offset += 1;
|
|
@@ -4080,6 +4116,7 @@ function flowSpawnChildrenPayload(args) {
|
|
|
4080
4116
|
"FROM_STATE",
|
|
4081
4117
|
"ON_CHILD_FAILED",
|
|
4082
4118
|
"ON_PARENT_CLOSED",
|
|
4119
|
+
"MAX_ACTIVE_MS",
|
|
4083
4120
|
"VALUE",
|
|
4084
4121
|
"VALUE_REF"
|
|
4085
4122
|
])
|
|
@@ -4110,6 +4147,185 @@ function flowSearchPayload(args) {
|
|
|
4110
4147
|
return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
|
|
4111
4148
|
}
|
|
4112
4149
|
|
|
4150
|
+
// src/protocol-flow-signal.ts
|
|
4151
|
+
function flowSignalPayload(args) {
|
|
4152
|
+
if (args.length < 3) return void 0;
|
|
4153
|
+
const options = parseFlowOptions(args, 1, args.length, {
|
|
4154
|
+
allowed: /* @__PURE__ */ new Set([
|
|
4155
|
+
"SIGNAL",
|
|
4156
|
+
"PARTITION",
|
|
4157
|
+
"IDEMPOTENCY",
|
|
4158
|
+
"IF_STATE",
|
|
4159
|
+
"TRANSITION_TO",
|
|
4160
|
+
"RUN_AT",
|
|
4161
|
+
"NOW",
|
|
4162
|
+
"VALUE",
|
|
4163
|
+
"VALUE_REF",
|
|
4164
|
+
"DROP_VALUE",
|
|
4165
|
+
"OVERRIDE_VALUE"
|
|
4166
|
+
]),
|
|
4167
|
+
required: /* @__PURE__ */ new Set(["SIGNAL"])
|
|
4168
|
+
});
|
|
4169
|
+
if (options == null) return void 0;
|
|
4170
|
+
return { opcode: OPCODES.flowSignal, payload: { id: args[0], ...options } };
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
// src/protocol-flow-policy.ts
|
|
4174
|
+
import { Buffer as Buffer13 } from "buffer";
|
|
4175
|
+
var BACKOFF_FIELDS = {
|
|
4176
|
+
BASE_MS: "base_ms",
|
|
4177
|
+
MAX_MS: "max_ms",
|
|
4178
|
+
JITTER_PCT: "jitter_pct"
|
|
4179
|
+
};
|
|
4180
|
+
var RETENTION_FIELDS = {
|
|
4181
|
+
RETENTION_TTL: "ttl_ms",
|
|
4182
|
+
RETENTION_TTL_MS: "ttl_ms",
|
|
4183
|
+
HISTORY_MAX_EVENTS: "history_max_events"
|
|
4184
|
+
};
|
|
4185
|
+
function flowPolicySetPayload(args) {
|
|
4186
|
+
if (!hasOwnCommandArgument(args, 0, args.length, "Flow policy arguments")) return void 0;
|
|
4187
|
+
if (!isBinaryArgument(args[0])) return void 0;
|
|
4188
|
+
const payload = { type: args[0] };
|
|
4189
|
+
const states = {};
|
|
4190
|
+
let target = payload;
|
|
4191
|
+
for (let index = 1; index < args.length; index += 2) {
|
|
4192
|
+
if (!hasOwnCommandArgument(args, index, args.length, "Flow policy arguments") || !hasOwnCommandArgument(args, index + 1, args.length, "Flow policy arguments")) return void 0;
|
|
4193
|
+
const token = optionalText(args[index])?.toUpperCase();
|
|
4194
|
+
const value = args[index + 1];
|
|
4195
|
+
if (token == null || value == null) return void 0;
|
|
4196
|
+
if (token === "STATE") {
|
|
4197
|
+
if (!isBinaryArgument(value)) return void 0;
|
|
4198
|
+
const state = asText(value);
|
|
4199
|
+
target = {};
|
|
4200
|
+
setOwnValue2(states, state, target);
|
|
4201
|
+
setOwnValue2(payload, "states", states);
|
|
4202
|
+
continue;
|
|
4203
|
+
}
|
|
4204
|
+
if (token === "MODE") {
|
|
4205
|
+
if (!isBinaryArgument(value)) return void 0;
|
|
4206
|
+
const mode = optionalText(value)?.toLowerCase();
|
|
4207
|
+
if (target === payload || mode !== "fifo" && mode !== "parallel") return void 0;
|
|
4208
|
+
setOwnValue2(target, "mode", mode);
|
|
4209
|
+
continue;
|
|
4210
|
+
}
|
|
4211
|
+
if (token === "EXPECTED_GENERATION") {
|
|
4212
|
+
if (target !== payload) return void 0;
|
|
4213
|
+
const generation = integerOption(value);
|
|
4214
|
+
if (generation == null || generation < 0) return void 0;
|
|
4215
|
+
setOwnValue2(payload, "expected_generation", generation);
|
|
4216
|
+
continue;
|
|
4217
|
+
}
|
|
4218
|
+
if (token === "REPLACE") {
|
|
4219
|
+
if (target !== payload || !isBoolToken(value)) return void 0;
|
|
4220
|
+
setOwnValue2(payload, "replace", boolArg(value));
|
|
4221
|
+
continue;
|
|
4222
|
+
}
|
|
4223
|
+
if (token === "MAX_ACTIVE_MS") {
|
|
4224
|
+
if (target !== payload) return void 0;
|
|
4225
|
+
const maxActiveMs = maxActiveOption(value);
|
|
4226
|
+
if (maxActiveMs == null) return void 0;
|
|
4227
|
+
setOwnValue2(payload, "max_active_ms", maxActiveMs);
|
|
4228
|
+
continue;
|
|
4229
|
+
}
|
|
4230
|
+
if (token === "INDEXED_STATE_META") {
|
|
4231
|
+
if (target !== payload || !isBinaryArgument(value)) return void 0;
|
|
4232
|
+
setOwnValue2(payload, "indexed_state_meta", value);
|
|
4233
|
+
continue;
|
|
4234
|
+
}
|
|
4235
|
+
if (token === "INDEXED_ATTRIBUTES") {
|
|
4236
|
+
if (target !== payload) return void 0;
|
|
4237
|
+
const names = indexedAttributes(value);
|
|
4238
|
+
if (names == null) return void 0;
|
|
4239
|
+
setOwnValue2(payload, "indexed_attributes", names);
|
|
4240
|
+
continue;
|
|
4241
|
+
}
|
|
4242
|
+
if (token === "MAX_RETRIES") {
|
|
4243
|
+
const parsed = integerOption(value);
|
|
4244
|
+
if (parsed == null) return void 0;
|
|
4245
|
+
setOwnValue2(objectField(target, "retry"), "max_retries", parsed);
|
|
4246
|
+
continue;
|
|
4247
|
+
}
|
|
4248
|
+
if (token === "EXHAUSTED_TO") {
|
|
4249
|
+
if (!isBinaryArgument(value)) return void 0;
|
|
4250
|
+
setOwnValue2(objectField(target, "retry"), "exhausted_to", value);
|
|
4251
|
+
continue;
|
|
4252
|
+
}
|
|
4253
|
+
const backoffField = BACKOFF_FIELDS[token];
|
|
4254
|
+
if (backoffField != null) {
|
|
4255
|
+
const parsed = integerOption(value);
|
|
4256
|
+
if (parsed == null) return void 0;
|
|
4257
|
+
setOwnValue2(objectField(objectField(target, "retry"), "backoff"), backoffField, parsed);
|
|
4258
|
+
continue;
|
|
4259
|
+
}
|
|
4260
|
+
if (token === "BACKOFF") {
|
|
4261
|
+
if (!isBinaryArgument(value)) return void 0;
|
|
4262
|
+
const kind = optionalText(value)?.toLowerCase();
|
|
4263
|
+
if (kind == null) return void 0;
|
|
4264
|
+
setOwnValue2(objectField(objectField(target, "retry"), "backoff"), "kind", kind);
|
|
4265
|
+
continue;
|
|
4266
|
+
}
|
|
4267
|
+
const retentionField = RETENTION_FIELDS[token];
|
|
4268
|
+
if (retentionField != null) {
|
|
4269
|
+
if (target === payload) return void 0;
|
|
4270
|
+
const parsed = integerOption(value);
|
|
4271
|
+
if (parsed == null) return void 0;
|
|
4272
|
+
setOwnValue2(objectField(target, "retention"), retentionField, parsed);
|
|
4273
|
+
continue;
|
|
4274
|
+
}
|
|
4275
|
+
return void 0;
|
|
4276
|
+
}
|
|
4277
|
+
return { opcode: OPCODES.flowPolicySet, payload };
|
|
4278
|
+
}
|
|
4279
|
+
function flowPolicyGetPayload(args) {
|
|
4280
|
+
if (!hasOwnCommandArgument(args, 0, args.length, "Flow policy arguments")) return void 0;
|
|
4281
|
+
if (!isBinaryArgument(args[0])) return void 0;
|
|
4282
|
+
if (args.length !== 1 && args.length !== 3) return void 0;
|
|
4283
|
+
const payload = { type: args[0] };
|
|
4284
|
+
if (args.length === 3) {
|
|
4285
|
+
if (!hasOwnCommandArgument(args, 1, args.length, "Flow policy arguments") || !hasOwnCommandArgument(args, 2, args.length, "Flow policy arguments") || optionalText(args[1])?.toUpperCase() !== "STATE" || !isBinaryArgument(args[2])) return void 0;
|
|
4286
|
+
setOwnValue2(payload, "state", args[2]);
|
|
4287
|
+
}
|
|
4288
|
+
return { opcode: OPCODES.flowPolicyGet, payload };
|
|
4289
|
+
}
|
|
4290
|
+
function integerOption(value) {
|
|
4291
|
+
try {
|
|
4292
|
+
return safeIntegerNumberArg(value);
|
|
4293
|
+
} catch {
|
|
4294
|
+
return void 0;
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
function maxActiveOption(value) {
|
|
4298
|
+
if (isBinaryArgument(value) && asText(value).toLowerCase() === "infinity") {
|
|
4299
|
+
return "infinity";
|
|
4300
|
+
}
|
|
4301
|
+
return integerOption(value);
|
|
4302
|
+
}
|
|
4303
|
+
function isBinaryArgument(value) {
|
|
4304
|
+
return typeof value === "string" || Buffer13.isBuffer(value) || value instanceof Uint8Array;
|
|
4305
|
+
}
|
|
4306
|
+
function objectField(target, name) {
|
|
4307
|
+
const existing = Object.hasOwn(target, name) ? target[name] : void 0;
|
|
4308
|
+
if (typeof existing === "object" && existing != null && !Array.isArray(existing)) {
|
|
4309
|
+
return existing;
|
|
4310
|
+
}
|
|
4311
|
+
const value = {};
|
|
4312
|
+
setOwnValue2(target, name, value);
|
|
4313
|
+
return value;
|
|
4314
|
+
}
|
|
4315
|
+
function indexedAttributes(value) {
|
|
4316
|
+
if (Array.isArray(value)) {
|
|
4317
|
+
return value.every((item) => typeof item === "string") ? value : void 0;
|
|
4318
|
+
}
|
|
4319
|
+
const source = optionalText(value);
|
|
4320
|
+
if (source == null) return void 0;
|
|
4321
|
+
try {
|
|
4322
|
+
const parsed = JSON.parse(source);
|
|
4323
|
+
return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : void 0;
|
|
4324
|
+
} catch {
|
|
4325
|
+
return void 0;
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4113
4329
|
// src/protocol-connection-policy.ts
|
|
4114
4330
|
function assertCommandDoesNotRequirePinnedConnection(args) {
|
|
4115
4331
|
const outer = commandName(args[0]);
|
|
@@ -4301,7 +4517,7 @@ function compactArgumentsEligible(args, sparseMessage) {
|
|
|
4301
4517
|
}
|
|
4302
4518
|
return true;
|
|
4303
4519
|
}
|
|
4304
|
-
function compactPipelineEligible(commands,
|
|
4520
|
+
function compactPipelineEligible(commands, commandName5, argumentCount) {
|
|
4305
4521
|
for (let index = 0; index < commands.length; index += 1) {
|
|
4306
4522
|
const command = commands[index];
|
|
4307
4523
|
if (!Object.hasOwn(commands, index) || !Array.isArray(command)) {
|
|
@@ -4313,7 +4529,7 @@ function compactPipelineEligible(commands, commandName4, argumentCount) {
|
|
|
4313
4529
|
throw new TypeError("pipeline command arguments must be dense");
|
|
4314
4530
|
}
|
|
4315
4531
|
}
|
|
4316
|
-
if (!commandNameIs(command[0],
|
|
4532
|
+
if (!commandNameIs(command[0], commandName5)) return false;
|
|
4317
4533
|
for (let argumentIndex = 1; argumentIndex < argumentCount; argumentIndex += 1) {
|
|
4318
4534
|
if (!isCompactBinaryScalar(command[argumentIndex])) return false;
|
|
4319
4535
|
}
|
|
@@ -4476,15 +4692,20 @@ function fetchOrComputeCommand(args) {
|
|
|
4476
4692
|
};
|
|
4477
4693
|
}
|
|
4478
4694
|
function fetchOrComputeResultCommand(args) {
|
|
4479
|
-
if (args.length !== 4 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1]))
|
|
4695
|
+
if (args.length !== 4 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1])) {
|
|
4696
|
+
throw new FerricStoreError("FETCH_OR_COMPUTE_RESULT requires key, ownership token, value, and ttl_ms");
|
|
4697
|
+
}
|
|
4480
4698
|
const ttlMs = positiveSafeInteger2(args[3]);
|
|
4481
|
-
|
|
4699
|
+
if (ttlMs == null) throw new FerricStoreError("FETCH_OR_COMPUTE_RESULT ttl_ms must be positive");
|
|
4700
|
+
return {
|
|
4482
4701
|
opcode: COMMAND_OPCODES.FETCH_OR_COMPUTE_RESULT,
|
|
4483
4702
|
payload: { key: args[0], token: args[1], ttl_ms: ttlMs, value: args[2] }
|
|
4484
4703
|
};
|
|
4485
4704
|
}
|
|
4486
4705
|
function fetchOrComputeErrorCommand(args) {
|
|
4487
|
-
if (args.length !== 3 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1]) || !isBinaryCommandArgument(args[2]))
|
|
4706
|
+
if (args.length !== 3 || !isBinaryCommandArgument(args[0]) || !isBinaryCommandArgument(args[1]) || !isBinaryCommandArgument(args[2])) {
|
|
4707
|
+
throw new FerricStoreError("FETCH_OR_COMPUTE_ERROR requires key, ownership token, and message");
|
|
4708
|
+
}
|
|
4488
4709
|
return {
|
|
4489
4710
|
opcode: COMMAND_OPCODES.FETCH_OR_COMPUTE_ERROR,
|
|
4490
4711
|
payload: { key: args[0], message: args[2], token: args[1] }
|
|
@@ -4841,62 +5062,462 @@ function requireAvailable(data, offset, size) {
|
|
|
4841
5062
|
}
|
|
4842
5063
|
}
|
|
4843
5064
|
|
|
4844
|
-
// src/
|
|
5065
|
+
// src/key-slot-validation.ts
|
|
4845
5066
|
import { Buffer as Buffer18 } from "buffer";
|
|
4846
5067
|
|
|
4847
|
-
// src/
|
|
5068
|
+
// src/topology-utilities.ts
|
|
4848
5069
|
import { Buffer as Buffer17 } from "buffer";
|
|
4849
|
-
function
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
if (
|
|
4854
|
-
const
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
5070
|
+
function isPlainObject3(value) {
|
|
5071
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer17.isBuffer(value);
|
|
5072
|
+
}
|
|
5073
|
+
function getField(source, ...keys) {
|
|
5074
|
+
if (source instanceof Map) {
|
|
5075
|
+
for (const key of keys) {
|
|
5076
|
+
if (source.has(key)) return source.get(key);
|
|
5077
|
+
const bufferKey = Buffer17.from(key);
|
|
5078
|
+
for (const [itemKey, value] of source.entries()) {
|
|
5079
|
+
if (Buffer17.isBuffer(itemKey) && itemKey.equals(bufferKey)) return value;
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
return void 0;
|
|
4859
5083
|
}
|
|
4860
|
-
if ((
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
};
|
|
5084
|
+
if (isPlainObject3(source)) {
|
|
5085
|
+
for (const key of keys) {
|
|
5086
|
+
if (Object.hasOwn(source, key)) return source[key];
|
|
5087
|
+
}
|
|
4865
5088
|
}
|
|
4866
|
-
|
|
4867
|
-
|
|
5089
|
+
return void 0;
|
|
5090
|
+
}
|
|
5091
|
+
function textOrUndefined(value) {
|
|
5092
|
+
if (typeof value === "string") return value;
|
|
5093
|
+
if (Buffer17.isBuffer(value)) return value.toString("utf8");
|
|
5094
|
+
return void 0;
|
|
5095
|
+
}
|
|
5096
|
+
function numberOrUndefined(value) {
|
|
5097
|
+
return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
|
|
5098
|
+
}
|
|
5099
|
+
function nativeEventName(event) {
|
|
5100
|
+
return textOrUndefined(getField(event.value, "event"))?.toUpperCase();
|
|
5101
|
+
}
|
|
5102
|
+
function endpointFromRange(item) {
|
|
5103
|
+
const endpointValue = getField(item, "endpoint");
|
|
5104
|
+
if (endpointValue != null && !isPlainObject3(endpointValue) && !(endpointValue instanceof Map)) {
|
|
5105
|
+
throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
|
|
4868
5106
|
}
|
|
4869
|
-
|
|
4870
|
-
|
|
5107
|
+
const raw = endpointValue ?? item;
|
|
5108
|
+
const host = textOrUndefined(getField(raw, "host", "native_host"));
|
|
5109
|
+
const nativePort = numberOrUndefined(getField(raw, "native_port"));
|
|
5110
|
+
if (host == null || !validEndpointHost(host) || nativePort == null || nativePort <= 0 || nativePort > 65535) {
|
|
5111
|
+
throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
|
|
4871
5112
|
}
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
5113
|
+
const nativeTlsPortValue = getField(raw, "native_tls_port");
|
|
5114
|
+
const nativeTlsPort = numberOrUndefined(nativeTlsPortValue);
|
|
5115
|
+
if (nativeTlsPortValue != null && (nativeTlsPort == null || nativeTlsPort <= 0 || nativeTlsPort > 65535)) {
|
|
5116
|
+
throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
|
|
4876
5117
|
}
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
5118
|
+
return {
|
|
5119
|
+
host,
|
|
5120
|
+
nativePort,
|
|
5121
|
+
node: textOrUndefined(getField(raw, "node", "leader_node", "owner_node")) ?? host,
|
|
5122
|
+
...nativeTlsPort == null ? {} : { nativeTlsPort }
|
|
5123
|
+
};
|
|
5124
|
+
}
|
|
5125
|
+
function validEndpointHost(host) {
|
|
5126
|
+
if (host.length === 0 || host.trim() !== host || /[\s\\/?#@]/u.test(host)) return false;
|
|
5127
|
+
const authorityHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
5128
|
+
try {
|
|
5129
|
+
const url = new URL(`ferric://${authorityHost}:6388`);
|
|
5130
|
+
return url.hostname !== "" && url.port === "6388" && url.username === "" && url.password === "";
|
|
5131
|
+
} catch {
|
|
5132
|
+
return false;
|
|
4881
5133
|
}
|
|
4882
|
-
return { found: false, value: void 0 };
|
|
4883
5134
|
}
|
|
4884
|
-
function
|
|
4885
|
-
return
|
|
5135
|
+
function sameEndpoint(left, right) {
|
|
5136
|
+
return normalizedEndpointHost(left.host) === normalizedEndpointHost(right.host) && left.nativePort === right.nativePort && left.nativeTlsPort === right.nativeTlsPort && left.node === right.node;
|
|
4886
5137
|
}
|
|
4887
|
-
function
|
|
4888
|
-
|
|
5138
|
+
function parseFerricUrl2(value) {
|
|
5139
|
+
const url = new URL(value);
|
|
5140
|
+
if (url.protocol !== "ferric:" && url.protocol !== "ferrics:") {
|
|
5141
|
+
throw new FerricStoreError(`unsupported FerricStore URL scheme: ${url.protocol}`);
|
|
5142
|
+
}
|
|
5143
|
+
return {
|
|
5144
|
+
host: normalizeFerricUrlHost(url.hostname),
|
|
5145
|
+
...url.password === "" ? {} : { password: decodeURIComponent(url.password) },
|
|
5146
|
+
port: Number(url.port || (url.protocol === "ferrics:" ? 6389 : 6388)),
|
|
5147
|
+
tls: url.protocol === "ferrics:",
|
|
5148
|
+
...url.username === "" ? {} : { username: decodeURIComponent(url.username) }
|
|
5149
|
+
};
|
|
4889
5150
|
}
|
|
4890
|
-
function
|
|
4891
|
-
|
|
4892
|
-
const count = data.readUInt32BE(1);
|
|
4893
|
-
requireCompactContainer(count, budget);
|
|
4894
|
-
if (data.byteLength !== 5) throw new FerricStoreError("invalid compact OK list response");
|
|
4895
|
-
return Array.from({ length: count }, () => Buffer17.from("OK"));
|
|
5151
|
+
function endpointKeyFor(endpoint) {
|
|
5152
|
+
return `${normalizedEndpointHost(endpoint.host)}:${endpoint.nativePort}`;
|
|
4896
5153
|
}
|
|
4897
|
-
function
|
|
4898
|
-
|
|
4899
|
-
|
|
5154
|
+
function connectionKeyForEndpoint(endpoint, useTls) {
|
|
5155
|
+
const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
|
|
5156
|
+
return `${useTls ? "ferrics" : "ferric"}://${normalizedEndpointHost(endpoint.host)}:${port}`;
|
|
5157
|
+
}
|
|
5158
|
+
function connectionKeyFromUrl(url) {
|
|
5159
|
+
const parsed = parseFerricUrl2(url);
|
|
5160
|
+
return `${parsed.tls ? "ferrics" : "ferric"}://${normalizedEndpointHost(parsed.host)}:${parsed.port}`;
|
|
5161
|
+
}
|
|
5162
|
+
function normalizedEndpointHost(host) {
|
|
5163
|
+
const lower = host.toLowerCase();
|
|
5164
|
+
return lower.startsWith("[") && lower.endsWith("]") ? lower.slice(1, -1) : lower;
|
|
5165
|
+
}
|
|
5166
|
+
function urlFromEndpoint(endpoint, useTls) {
|
|
5167
|
+
const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
|
|
5168
|
+
const host = endpoint.host.includes(":") && !endpoint.host.startsWith("[") ? `[${endpoint.host}]` : endpoint.host;
|
|
5169
|
+
return `${useTls ? "ferrics" : "ferric"}://${host}:${port}`;
|
|
5170
|
+
}
|
|
5171
|
+
async function mapSettledWithConcurrency(items, concurrency, operation) {
|
|
5172
|
+
const results = new Array(items.length);
|
|
5173
|
+
let nextIndex = 0;
|
|
5174
|
+
const worker = async () => {
|
|
5175
|
+
while (nextIndex < items.length) {
|
|
5176
|
+
const index = nextIndex++;
|
|
5177
|
+
const item = items[index];
|
|
5178
|
+
try {
|
|
5179
|
+
results[index] = { status: "fulfilled", value: await operation(item, index) };
|
|
5180
|
+
} catch (reason) {
|
|
5181
|
+
results[index] = { status: "rejected", reason };
|
|
5182
|
+
}
|
|
5183
|
+
}
|
|
5184
|
+
};
|
|
5185
|
+
await Promise.all(Array.from(
|
|
5186
|
+
{ length: Math.min(concurrency, items.length) },
|
|
5187
|
+
async () => await worker()
|
|
5188
|
+
));
|
|
5189
|
+
return results;
|
|
5190
|
+
}
|
|
5191
|
+
function throwFirstRejected(results) {
|
|
5192
|
+
for (const result of results) {
|
|
5193
|
+
if (result.status === "rejected") throw result.reason;
|
|
5194
|
+
}
|
|
5195
|
+
}
|
|
5196
|
+
var TaskConcurrencyLimiter = class {
|
|
5197
|
+
constructor(concurrency) {
|
|
5198
|
+
this.concurrency = concurrency;
|
|
5199
|
+
}
|
|
5200
|
+
concurrency;
|
|
5201
|
+
active = 0;
|
|
5202
|
+
head = 0;
|
|
5203
|
+
pending = [];
|
|
5204
|
+
async run(operation) {
|
|
5205
|
+
await this.acquire();
|
|
5206
|
+
try {
|
|
5207
|
+
return await operation();
|
|
5208
|
+
} finally {
|
|
5209
|
+
this.release();
|
|
5210
|
+
}
|
|
5211
|
+
}
|
|
5212
|
+
acquire() {
|
|
5213
|
+
if (this.active < this.concurrency) {
|
|
5214
|
+
this.active += 1;
|
|
5215
|
+
return Promise.resolve();
|
|
5216
|
+
}
|
|
5217
|
+
return new Promise((resolve) => this.pending.push(resolve));
|
|
5218
|
+
}
|
|
5219
|
+
release() {
|
|
5220
|
+
const next = this.pending[this.head];
|
|
5221
|
+
if (next == null) {
|
|
5222
|
+
this.active -= 1;
|
|
5223
|
+
return;
|
|
5224
|
+
}
|
|
5225
|
+
this.head += 1;
|
|
5226
|
+
next();
|
|
5227
|
+
if (this.head === this.pending.length) {
|
|
5228
|
+
this.pending.length = 0;
|
|
5229
|
+
this.head = 0;
|
|
5230
|
+
} else if (this.head >= 1024 && this.head * 2 >= this.pending.length) {
|
|
5231
|
+
this.pending.splice(0, this.head);
|
|
5232
|
+
this.head = 0;
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
};
|
|
5236
|
+
function normalizedHostSet(hosts) {
|
|
5237
|
+
return new Set(
|
|
5238
|
+
hosts.filter((host) => host != null && host !== "").map((host) => normalizedEndpointHost(host))
|
|
5239
|
+
);
|
|
5240
|
+
}
|
|
5241
|
+
var OPEN_BRACE = "{".charCodeAt(0);
|
|
5242
|
+
var CLOSE_BRACE = "}".charCodeAt(0);
|
|
5243
|
+
function hashTagOrKey(key) {
|
|
5244
|
+
const start = key.indexOf(OPEN_BRACE);
|
|
5245
|
+
if (start < 0) return key;
|
|
5246
|
+
const end = key.indexOf(CLOSE_BRACE, start + 1);
|
|
5247
|
+
return end > start + 1 ? key.subarray(start + 1, end) : key;
|
|
5248
|
+
}
|
|
5249
|
+
var ROUTE_SLOT_MASK = 1023;
|
|
5250
|
+
function routingSlotForKey(key) {
|
|
5251
|
+
if (typeof key === "string") {
|
|
5252
|
+
const [start, end] = stringHashRange(key);
|
|
5253
|
+
return crc32Utf8(key, start, end) & ROUTE_SLOT_MASK;
|
|
5254
|
+
}
|
|
5255
|
+
const keyBytes = key;
|
|
5256
|
+
return crc32(hashTagOrKey(keyBytes)) & ROUTE_SLOT_MASK;
|
|
5257
|
+
}
|
|
5258
|
+
function stringHashRange(key) {
|
|
5259
|
+
const startBrace = key.indexOf("{");
|
|
5260
|
+
const endBrace = startBrace < 0 ? -1 : key.indexOf("}", startBrace + 1);
|
|
5261
|
+
return endBrace > startBrace + 1 ? [startBrace + 1, endBrace] : [0, key.length];
|
|
5262
|
+
}
|
|
5263
|
+
|
|
5264
|
+
// src/key-slot-validation.ts
|
|
5265
|
+
var validatedCommands = /* @__PURE__ */ new WeakSet();
|
|
5266
|
+
function assertAtomicKeyValueCommandSharesSlot(args) {
|
|
5267
|
+
const value = args[0];
|
|
5268
|
+
const command = (typeof value === "string" ? value : Buffer18.isBuffer(value) ? value.toString("utf8") : "").toUpperCase();
|
|
5269
|
+
if (command === "MSET" || command === "MSETNX") {
|
|
5270
|
+
assertKeyValueCommandSharesSlot(args, command);
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
function assertKeyValueCommandSharesSlot(args, command) {
|
|
5274
|
+
if (validatedCommands.has(args) || args.length < 3 || args.length % 2 === 0) return;
|
|
5275
|
+
let expectedSlot;
|
|
5276
|
+
for (let index = 1; index < args.length; index += 2) {
|
|
5277
|
+
const key = args[index];
|
|
5278
|
+
if (typeof key !== "string" && !Buffer18.isBuffer(key)) return;
|
|
5279
|
+
const slot = routingSlotForKey(key);
|
|
5280
|
+
expectedSlot ??= slot;
|
|
5281
|
+
if (slot !== expectedSlot) {
|
|
5282
|
+
throw new TypeError(`${command} keys must share a slot`);
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
validatedCommands.add(args);
|
|
5286
|
+
}
|
|
5287
|
+
|
|
5288
|
+
// src/protocol-response.ts
|
|
5289
|
+
import { Buffer as Buffer22 } from "buffer";
|
|
5290
|
+
|
|
5291
|
+
// src/protocol-compact-response.ts
|
|
5292
|
+
import { Buffer as Buffer21 } from "buffer";
|
|
5293
|
+
|
|
5294
|
+
// src/native-negotiation.ts
|
|
5295
|
+
import { Buffer as Buffer19 } from "buffer";
|
|
5296
|
+
var EMPTY_COMPACT_RESPONSE_OPCODES = /* @__PURE__ */ new Map();
|
|
5297
|
+
function nativeNegotiation(value) {
|
|
5298
|
+
const capabilities = field(value, "capabilities") ?? value;
|
|
5299
|
+
const limits = field(capabilities, "limits");
|
|
5300
|
+
const responseCodecs = field(capabilities, "response_codecs");
|
|
5301
|
+
const maxResponseBytes = positiveSafeInteger3(field(limits, "max_response_bytes"));
|
|
5302
|
+
return {
|
|
5303
|
+
compactResponseOpcodes: parseCompactResponseOpcodes(
|
|
5304
|
+
field(responseCodecs, "compact_response_opcodes")
|
|
5305
|
+
),
|
|
5306
|
+
...maxResponseBytes == null ? {} : { maxResponseBytes }
|
|
5307
|
+
};
|
|
5308
|
+
}
|
|
5309
|
+
function compactResponseOpcodeSupports(capabilities, codec, opcode) {
|
|
5310
|
+
return capabilities?.get(codec)?.has(opcode) === true;
|
|
5311
|
+
}
|
|
5312
|
+
function parseCompactResponseOpcodes(value) {
|
|
5313
|
+
const entries = mapEntries(value);
|
|
5314
|
+
if (entries == null) return EMPTY_COMPACT_RESPONSE_OPCODES;
|
|
5315
|
+
const result = /* @__PURE__ */ new Map();
|
|
5316
|
+
for (const [rawName, rawOpcodes] of entries) {
|
|
5317
|
+
const name = text2(rawName);
|
|
5318
|
+
if (name == null || name.length === 0 || !Array.isArray(rawOpcodes)) continue;
|
|
5319
|
+
const opcodes = /* @__PURE__ */ new Set();
|
|
5320
|
+
let valid = true;
|
|
5321
|
+
for (let index = 0; index < rawOpcodes.length; index += 1) {
|
|
5322
|
+
if (!Object.hasOwn(rawOpcodes, index)) {
|
|
5323
|
+
valid = false;
|
|
5324
|
+
break;
|
|
5325
|
+
}
|
|
5326
|
+
const opcode = unsigned16(rawOpcodes[index]);
|
|
5327
|
+
if (opcode == null) {
|
|
5328
|
+
valid = false;
|
|
5329
|
+
break;
|
|
5330
|
+
}
|
|
5331
|
+
opcodes.add(opcode);
|
|
5332
|
+
}
|
|
5333
|
+
if (valid) result.set(name, opcodes);
|
|
5334
|
+
}
|
|
5335
|
+
return result;
|
|
5336
|
+
}
|
|
5337
|
+
function mapEntries(value) {
|
|
5338
|
+
if (value instanceof Map) return [...value.entries()];
|
|
5339
|
+
if (typeof value !== "object" || value == null || Array.isArray(value)) return void 0;
|
|
5340
|
+
return Object.entries(value);
|
|
5341
|
+
}
|
|
5342
|
+
function unsigned16(value) {
|
|
5343
|
+
const parsed = nonNegativeSafeInteger2(value);
|
|
5344
|
+
return parsed != null && parsed <= 65535 ? parsed : void 0;
|
|
5345
|
+
}
|
|
5346
|
+
function positiveSafeInteger3(value) {
|
|
5347
|
+
const parsed = nonNegativeSafeInteger2(value);
|
|
5348
|
+
return parsed != null && parsed > 0 ? parsed : void 0;
|
|
5349
|
+
}
|
|
5350
|
+
function nonNegativeSafeInteger2(value) {
|
|
5351
|
+
if (typeof value === "bigint") {
|
|
5352
|
+
return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : void 0;
|
|
5353
|
+
}
|
|
5354
|
+
const source = text2(value) ?? value;
|
|
5355
|
+
if (typeof source !== "number" && (typeof source !== "string" || !/^\d+$/u.test(source))) {
|
|
5356
|
+
return void 0;
|
|
5357
|
+
}
|
|
5358
|
+
const parsed = Number(source);
|
|
5359
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
5360
|
+
}
|
|
5361
|
+
function text2(value) {
|
|
5362
|
+
if (typeof value === "string") return value;
|
|
5363
|
+
if (Buffer19.isBuffer(value) || value instanceof Uint8Array) {
|
|
5364
|
+
return Buffer19.from(value).toString("utf8");
|
|
5365
|
+
}
|
|
5366
|
+
return void 0;
|
|
5367
|
+
}
|
|
5368
|
+
|
|
5369
|
+
// src/protocol-compact-collections.ts
|
|
5370
|
+
import "buffer";
|
|
5371
|
+
function decodeCompactIntegerList(data, budget) {
|
|
5372
|
+
requireAvailable(data, 0, 5);
|
|
5373
|
+
const count = data.readUInt32BE(1);
|
|
5374
|
+
requireCompactContainer(count, budget);
|
|
5375
|
+
if (data.byteLength !== 5 + count * 8) {
|
|
5376
|
+
throw new FerricStoreError("invalid compact integer list response");
|
|
5377
|
+
}
|
|
5378
|
+
const values = new Array(count);
|
|
5379
|
+
for (let index = 0, offset = 5; index < count; index += 1, offset += 8) {
|
|
5380
|
+
const value = data.readBigInt64BE(offset);
|
|
5381
|
+
values[index] = value <= MAX_SAFE_INTEGER_BIGINT && value >= MIN_SAFE_INTEGER_BIGINT ? Number(value) : value;
|
|
5382
|
+
}
|
|
5383
|
+
return values;
|
|
5384
|
+
}
|
|
5385
|
+
function decodeCompactBinaryListList(data, budget) {
|
|
5386
|
+
requireAvailable(data, 0, 5);
|
|
5387
|
+
const count = data.readUInt32BE(1);
|
|
5388
|
+
requireCompactContainer(count, budget);
|
|
5389
|
+
let offset = 5;
|
|
5390
|
+
const values = new Array(count);
|
|
5391
|
+
for (let index = 0; index < count; index += 1) {
|
|
5392
|
+
const read = readCompactBinaryList(data, offset, budget);
|
|
5393
|
+
values[index] = read.value;
|
|
5394
|
+
offset = read.offset;
|
|
5395
|
+
}
|
|
5396
|
+
if (offset !== data.byteLength) throw new FerricStoreError("trailing compact binary list-list bytes");
|
|
5397
|
+
return values;
|
|
5398
|
+
}
|
|
5399
|
+
function decodeCompactBinaryMapList(data, budget) {
|
|
5400
|
+
requireAvailable(data, 0, 5);
|
|
5401
|
+
const count = data.readUInt32BE(1);
|
|
5402
|
+
requireCompactContainer(count, budget);
|
|
5403
|
+
let offset = 5;
|
|
5404
|
+
const values = new Array(count);
|
|
5405
|
+
for (let index = 0; index < count; index += 1) {
|
|
5406
|
+
const read = readCompactBinaryMap(data, offset, budget);
|
|
5407
|
+
values[index] = read.value;
|
|
5408
|
+
offset = read.offset;
|
|
5409
|
+
}
|
|
5410
|
+
if (offset !== data.byteLength) throw new FerricStoreError("trailing compact binary map-list bytes");
|
|
5411
|
+
return values;
|
|
5412
|
+
}
|
|
5413
|
+
function readCompactBinaryList(data, offset, budget) {
|
|
5414
|
+
requireAvailable(data, offset, 4);
|
|
5415
|
+
const count = data.readUInt32BE(offset);
|
|
5416
|
+
requireCompactContainer(count, budget);
|
|
5417
|
+
offset += 4;
|
|
5418
|
+
const values = new Array(count);
|
|
5419
|
+
for (let index = 0; index < count; index += 1) {
|
|
5420
|
+
const read = readBinary(data, offset);
|
|
5421
|
+
values[index] = read.value;
|
|
5422
|
+
offset = read.offset;
|
|
5423
|
+
}
|
|
5424
|
+
return { value: values, offset };
|
|
5425
|
+
}
|
|
5426
|
+
function readCompactBinaryMap(data, offset, budget) {
|
|
5427
|
+
requireAvailable(data, offset, 4);
|
|
5428
|
+
const count = data.readUInt32BE(offset);
|
|
5429
|
+
requireCompactContainer(count, budget);
|
|
5430
|
+
offset += 4;
|
|
5431
|
+
const values = {};
|
|
5432
|
+
for (let index = 0; index < count; index += 1) {
|
|
5433
|
+
const key = readBinary(data, offset);
|
|
5434
|
+
const value = readBinary(data, key.offset);
|
|
5435
|
+
setOwnValue2(values, key.value.toString("utf8"), value.value);
|
|
5436
|
+
offset = value.offset;
|
|
5437
|
+
}
|
|
5438
|
+
return { value: values, offset };
|
|
5439
|
+
}
|
|
5440
|
+
function markCompactPipelineDecoded(values) {
|
|
5441
|
+
Object.defineProperty(values, COMPACT_PIPELINE_DECODED, { value: true });
|
|
5442
|
+
return values;
|
|
5443
|
+
}
|
|
5444
|
+
function requireCompactContainer(count, budget) {
|
|
5445
|
+
if (count > DEFAULT_MAX_VALUE_ITEMS) {
|
|
5446
|
+
throw new FerricStoreError("native compact response container exceeds max items");
|
|
5447
|
+
}
|
|
5448
|
+
consumeDecodeItems(count, budget);
|
|
5449
|
+
}
|
|
5450
|
+
|
|
5451
|
+
// src/protocol-compact-response.ts
|
|
5452
|
+
function tryDecodeCompactResponse(opcode, body, hints) {
|
|
5453
|
+
if (body.byteLength === 0) return { found: false, value: void 0 };
|
|
5454
|
+
const budget = { remainingItems: DEFAULT_MAX_VALUE_ITEMS };
|
|
5455
|
+
const tag = body.readUInt8(0);
|
|
5456
|
+
const pipelineValues = opcode === OPCODES.pipeline && supports(hints, "pipeline_v1", opcode);
|
|
5457
|
+
if (tag === COMPACT_OK_LIST && (supports(hints, "ok_list_v1", opcode) || pipelineValues)) {
|
|
5458
|
+
const values = decodeCompactOkList(body, budget);
|
|
5459
|
+
return {
|
|
5460
|
+
found: true,
|
|
5461
|
+
value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values.length === 1 ? "OK" : values
|
|
5462
|
+
};
|
|
5463
|
+
}
|
|
5464
|
+
if (tag === COMPACT_KV_GET && supports(hints, "kv_get_v1", opcode)) {
|
|
5465
|
+
return { found: true, value: decodeCompactKvGet(body) };
|
|
5466
|
+
}
|
|
5467
|
+
if ((tag === COMPACT_KV_MGET || tag === COMPACT_KV_MGET_FIXED) && (supports(hints, "kv_mget_v1", opcode) || pipelineValues)) {
|
|
5468
|
+
const values = tag === COMPACT_KV_MGET ? decodeCompactMget(body, budget) : decodeCompactMgetFixed(body, budget);
|
|
5469
|
+
return {
|
|
5470
|
+
found: true,
|
|
5471
|
+
value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
|
|
5472
|
+
};
|
|
5473
|
+
}
|
|
5474
|
+
if (tag === COMPACT_INTEGER_LIST && pipelineValues) {
|
|
5475
|
+
return { found: true, value: markCompactPipelineDecoded(decodeCompactIntegerList(body, budget)) };
|
|
5476
|
+
}
|
|
5477
|
+
if (tag === COMPACT_BINARY_LIST_LIST && pipelineValues) {
|
|
5478
|
+
return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryListList(body, budget)) };
|
|
5479
|
+
}
|
|
5480
|
+
if (tag === COMPACT_BINARY_MAP_LIST && pipelineValues) {
|
|
5481
|
+
return { found: true, value: markCompactPipelineDecoded(decodeCompactBinaryMapList(body, budget)) };
|
|
5482
|
+
}
|
|
5483
|
+
if (tag === COMPACT_PIPELINE_RESPONSE && pipelineValues) {
|
|
5484
|
+
return { found: true, value: decodeCompactPipeline(body, budget, hints.pipelineClaimModes) };
|
|
5485
|
+
}
|
|
5486
|
+
if (tag === COMPACT_FLOW_CLAIM_JOBS && (supports(hints, "flow_claim_jobs_v1", opcode) || pipelineValues)) {
|
|
5487
|
+
const values = decodeCompactClaimJobs(body, budget, hints.compactClaimMode);
|
|
5488
|
+
return {
|
|
5489
|
+
found: true,
|
|
5490
|
+
value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(values) : values
|
|
5491
|
+
};
|
|
5492
|
+
}
|
|
5493
|
+
if (tag === COMPACT_FLOW_RECORD && supports(hints, "flow_record_v1", opcode)) {
|
|
5494
|
+
const read = readCompactFlowRecord(body, 0, budget);
|
|
5495
|
+
if (read.offset !== body.byteLength) throw new FerricStoreError("trailing compact Flow record bytes");
|
|
5496
|
+
return { found: true, value: read.value };
|
|
5497
|
+
}
|
|
5498
|
+
if (tag === COMPACT_FLOW_RECORD_LIST && (supports(hints, "flow_record_list_v1", opcode) || pipelineValues)) {
|
|
5499
|
+
const read = readCompactFlowRecordList(body, 0, budget);
|
|
5500
|
+
if (read.offset !== body.byteLength) throw new FerricStoreError("trailing compact Flow record list bytes");
|
|
5501
|
+
return {
|
|
5502
|
+
found: true,
|
|
5503
|
+
value: opcode === OPCODES.pipeline ? markCompactPipelineDecoded(read.value) : read.value
|
|
5504
|
+
};
|
|
5505
|
+
}
|
|
5506
|
+
return { found: false, value: void 0 };
|
|
5507
|
+
}
|
|
5508
|
+
function supports(hints, codec, opcode) {
|
|
5509
|
+
return compactResponseOpcodeSupports(hints.compactResponseOpcodes, codec, opcode);
|
|
5510
|
+
}
|
|
5511
|
+
function decodeCompactOkList(data, budget) {
|
|
5512
|
+
requireAvailable(data, 0, 5);
|
|
5513
|
+
const count = data.readUInt32BE(1);
|
|
5514
|
+
requireCompactContainer2(count, budget);
|
|
5515
|
+
if (data.byteLength !== 5) throw new FerricStoreError("invalid compact OK list response");
|
|
5516
|
+
return Array.from({ length: count }, () => Buffer21.from("OK"));
|
|
5517
|
+
}
|
|
5518
|
+
function decodeCompactKvGet(data) {
|
|
5519
|
+
requireAvailable(data, 0, 2);
|
|
5520
|
+
const present = data.readUInt8(1);
|
|
4900
5521
|
if (present === 0) {
|
|
4901
5522
|
if (data.byteLength !== 2) throw new FerricStoreError("trailing compact GET bytes");
|
|
4902
5523
|
return null;
|
|
@@ -4909,7 +5530,7 @@ function decodeCompactKvGet(data) {
|
|
|
4909
5530
|
function decodeCompactMget(data, budget) {
|
|
4910
5531
|
requireAvailable(data, 0, 5);
|
|
4911
5532
|
const count = data.readUInt32BE(1);
|
|
4912
|
-
|
|
5533
|
+
requireCompactContainer2(count, budget);
|
|
4913
5534
|
let offset = 5;
|
|
4914
5535
|
const values = [];
|
|
4915
5536
|
for (let index = 0; index < count; index += 1) {
|
|
@@ -4933,12 +5554,12 @@ function decodeCompactMgetFixed(data, budget) {
|
|
|
4933
5554
|
requireAvailable(data, 0, 9);
|
|
4934
5555
|
const count = data.readUInt32BE(1);
|
|
4935
5556
|
const size = data.readUInt32BE(5);
|
|
4936
|
-
|
|
5557
|
+
requireCompactContainer2(count, budget);
|
|
4937
5558
|
const expected = 9 + count * size;
|
|
4938
5559
|
if (size === NULL_U32 || data.byteLength !== expected) {
|
|
4939
5560
|
throw new FerricStoreError("invalid compact fixed MGET response");
|
|
4940
5561
|
}
|
|
4941
|
-
if (size === 0) return new Array(count).fill(
|
|
5562
|
+
if (size === 0) return new Array(count).fill(Buffer21.alloc(0));
|
|
4942
5563
|
const values = new Array(count);
|
|
4943
5564
|
for (let index = 0, offset = 9; index < count; index += 1, offset += size) {
|
|
4944
5565
|
values[index] = data.subarray(offset, offset + size);
|
|
@@ -4948,7 +5569,7 @@ function decodeCompactMgetFixed(data, budget) {
|
|
|
4948
5569
|
function decodeCompactPipeline(data, budget, claimModes) {
|
|
4949
5570
|
requireAvailable(data, 0, 5);
|
|
4950
5571
|
const count = data.readUInt32BE(1);
|
|
4951
|
-
|
|
5572
|
+
requireCompactContainer2(count, budget);
|
|
4952
5573
|
if (count > Math.floor((data.byteLength - 5) / 2)) {
|
|
4953
5574
|
throw new FerricStoreError("compact pipeline item count exceeds response bytes");
|
|
4954
5575
|
}
|
|
@@ -5010,13 +5631,12 @@ function decodeCompactPipeline(data, budget, claimModes) {
|
|
|
5010
5631
|
}
|
|
5011
5632
|
}
|
|
5012
5633
|
if (offset !== data.byteLength) throw new FerricStoreError("trailing compact pipeline bytes");
|
|
5013
|
-
|
|
5014
|
-
return values;
|
|
5634
|
+
return markCompactPipelineDecoded(values);
|
|
5015
5635
|
}
|
|
5016
5636
|
function decodeCompactClaimJobs(data, budget, mode) {
|
|
5017
5637
|
requireAvailable(data, 0, 5);
|
|
5018
5638
|
const count = data.readUInt32BE(1);
|
|
5019
|
-
|
|
5639
|
+
requireCompactContainer2(count, budget);
|
|
5020
5640
|
if (mode != null) {
|
|
5021
5641
|
const values = [];
|
|
5022
5642
|
let offset = 5;
|
|
@@ -5100,7 +5720,7 @@ function readCompactFlowRecord(data, offset, budget = { remainingItems: DEFAULT_
|
|
|
5100
5720
|
if (data.readUInt8(offset) !== COMPACT_FLOW_RECORD) throw new FerricStoreError("expected compact Flow record");
|
|
5101
5721
|
offset += 1;
|
|
5102
5722
|
const count = data.readUInt32BE(offset);
|
|
5103
|
-
|
|
5723
|
+
requireCompactContainer2(count, budget);
|
|
5104
5724
|
offset += 4;
|
|
5105
5725
|
const record = {};
|
|
5106
5726
|
for (let index = 0; index < count; index += 1) {
|
|
@@ -5128,7 +5748,7 @@ function readCompactFlowRecordList(data, offset, budget = { remainingItems: DEFA
|
|
|
5128
5748
|
}
|
|
5129
5749
|
offset += 1;
|
|
5130
5750
|
const count = data.readUInt32BE(offset);
|
|
5131
|
-
|
|
5751
|
+
requireCompactContainer2(count, budget);
|
|
5132
5752
|
offset += 4;
|
|
5133
5753
|
const records = [];
|
|
5134
5754
|
for (let index = 0; index < count; index += 1) {
|
|
@@ -5138,33 +5758,6 @@ function readCompactFlowRecordList(data, offset, budget = { remainingItems: DEFA
|
|
|
5138
5758
|
}
|
|
5139
5759
|
return { value: records, offset };
|
|
5140
5760
|
}
|
|
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 };
|
|
5167
|
-
}
|
|
5168
5761
|
function readOptionalBinary(data, offset) {
|
|
5169
5762
|
requireAvailable(data, offset, 4);
|
|
5170
5763
|
const size = data.readUInt32BE(offset);
|
|
@@ -5173,7 +5766,7 @@ function readOptionalBinary(data, offset) {
|
|
|
5173
5766
|
requireAvailable(data, offset, size);
|
|
5174
5767
|
return { value: data.subarray(offset, offset + size), offset: offset + size };
|
|
5175
5768
|
}
|
|
5176
|
-
function
|
|
5769
|
+
function requireCompactContainer2(count, budget) {
|
|
5177
5770
|
if (count > DEFAULT_MAX_VALUE_ITEMS) {
|
|
5178
5771
|
throw new FerricStoreError("native compact response container exceeds max items");
|
|
5179
5772
|
}
|
|
@@ -5181,7 +5774,7 @@ function requireCompactContainer(count, budget) {
|
|
|
5181
5774
|
}
|
|
5182
5775
|
function errorMessage(status, value) {
|
|
5183
5776
|
if (typeof value === "string") return value;
|
|
5184
|
-
if (
|
|
5777
|
+
if (Buffer21.isBuffer(value)) return value.toString("utf8");
|
|
5185
5778
|
if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
|
|
5186
5779
|
const message = value.message;
|
|
5187
5780
|
return typeof message === "string" ? message : String(message);
|
|
@@ -5261,7 +5854,7 @@ function unwrapPipelineResponse(value, options = {}, expectedItems) {
|
|
|
5261
5854
|
return out;
|
|
5262
5855
|
}
|
|
5263
5856
|
function pipelineStatus(value) {
|
|
5264
|
-
if (typeof value !== "string" && !
|
|
5857
|
+
if (typeof value !== "string" && !Buffer22.isBuffer(value) && !(value instanceof Uint8Array)) return null;
|
|
5265
5858
|
const status = asText(value).toLowerCase();
|
|
5266
5859
|
return status === "ok" || status === "busy" || status === "error" ? status : null;
|
|
5267
5860
|
}
|
|
@@ -5276,7 +5869,7 @@ function decodeResponseValue(opcode, body, hints) {
|
|
|
5276
5869
|
}
|
|
5277
5870
|
function errorMessage2(status, value) {
|
|
5278
5871
|
if (typeof value === "string") return value;
|
|
5279
|
-
if (
|
|
5872
|
+
if (Buffer22.isBuffer(value)) return value.toString("utf8");
|
|
5280
5873
|
if (typeof value === "object" && value != null && Object.hasOwn(value, "message")) {
|
|
5281
5874
|
const message = value.message;
|
|
5282
5875
|
return typeof message === "string" ? message : String(message);
|
|
@@ -5292,7 +5885,7 @@ function encodeRequest(command, requestId, maxBodyBytes = Number.MAX_SAFE_INTEGE
|
|
|
5292
5885
|
const bodyLength = customPayload ? binaryValueByteLength(command.payload) : plan?.byteLength ?? 0;
|
|
5293
5886
|
if (bodyLength > bodyLimit) throw requestFrameTooLarge(bodyLimit);
|
|
5294
5887
|
const flags = command.flags ?? 0;
|
|
5295
|
-
const frame =
|
|
5888
|
+
const frame = Buffer23.allocUnsafe(HEADER_SIZE + bodyLength);
|
|
5296
5889
|
frame.write(MAGIC, 0, "ascii");
|
|
5297
5890
|
frame.writeUInt8(REQUEST_VERSION, 4);
|
|
5298
5891
|
frame.writeUInt8(flags, 5);
|
|
@@ -5343,6 +5936,9 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
|
|
|
5343
5936
|
}
|
|
5344
5937
|
const command = asText(args[0]).toUpperCase();
|
|
5345
5938
|
assertNormalizedCommandDoesNotRequirePinnedConnection(args, command);
|
|
5939
|
+
if (command === "MSET" || command === "MSETNX") {
|
|
5940
|
+
assertKeyValueCommandSharesSlot(args, command);
|
|
5941
|
+
}
|
|
5346
5942
|
const commandArgs2 = args.slice(1);
|
|
5347
5943
|
if (command === "COMMAND_EXEC" && commandArgs2.length >= 1) {
|
|
5348
5944
|
return commandExec(commandArgs2);
|
|
@@ -5414,6 +6010,12 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
|
|
|
5414
6010
|
if (command === "FLOW.LIST") {
|
|
5415
6011
|
return (allowCustomPayload ? compactFlowListPayload(commandArgs2, maxBodyBytes) : void 0) ?? commandExec(args);
|
|
5416
6012
|
}
|
|
6013
|
+
if (command === "FLOW.POLICY.SET") {
|
|
6014
|
+
return flowPolicySetPayload(commandArgs2) ?? commandExec(args);
|
|
6015
|
+
}
|
|
6016
|
+
if (command === "FLOW.POLICY.GET") {
|
|
6017
|
+
return flowPolicyGetPayload(commandArgs2) ?? commandExec(args);
|
|
6018
|
+
}
|
|
5417
6019
|
const flowAdmin = FLOW_ADMIN_COMMANDS[command];
|
|
5418
6020
|
if (flowAdmin != null) {
|
|
5419
6021
|
return flowAdminPayload(flowAdmin.opcode, commandArgs2, flowAdmin.leadingFields) ?? commandExec(args);
|
|
@@ -5480,20 +6082,7 @@ function buildProtocolCommand(args, maxBodyBytes = Number.MAX_SAFE_INTEGER, allo
|
|
|
5480
6082
|
])) ?? commandExec(args);
|
|
5481
6083
|
}
|
|
5482
6084
|
if (command === "FLOW.SIGNAL") {
|
|
5483
|
-
return
|
|
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
|
-
]));
|
|
6085
|
+
return flowSignalPayload(commandArgs2) ?? commandExec(args);
|
|
5497
6086
|
}
|
|
5498
6087
|
if (command === "FLOW.CANCEL") {
|
|
5499
6088
|
return flowCommandExecWithRouting(command, commandArgs2, 1, /* @__PURE__ */ new Set([
|
|
@@ -5662,6 +6251,7 @@ var DEFAULT_MAX_PENDING_CONTROL_REQUESTS = 4096;
|
|
|
5662
6251
|
var DEFAULT_MAX_RESPONSE_BYTES = 64 * 1024 * 1024;
|
|
5663
6252
|
var DEFAULT_MAX_QUEUED_REQUESTS = 65536;
|
|
5664
6253
|
var DEFAULT_MAX_QUEUED_WRITE_BYTES = 64 * 1024 * 1024;
|
|
6254
|
+
var UNAUTHENTICATED_MAX_FRAME_BYTES = 64 * 1024;
|
|
5665
6255
|
function assertNativeAdapterOptions(options) {
|
|
5666
6256
|
const supplied = options;
|
|
5667
6257
|
for (const name of ["autoReconnect", "haRouting", "seeds"]) {
|
|
@@ -5681,7 +6271,7 @@ import "net";
|
|
|
5681
6271
|
import "tls";
|
|
5682
6272
|
|
|
5683
6273
|
// src/client-native-options.ts
|
|
5684
|
-
import { Buffer as
|
|
6274
|
+
import { Buffer as Buffer24 } from "buffer";
|
|
5685
6275
|
|
|
5686
6276
|
// src/string-array-snapshot.ts
|
|
5687
6277
|
function snapshotOwnStringArray(values, name) {
|
|
@@ -5764,7 +6354,7 @@ function snapshotTlsOptions(options) {
|
|
|
5764
6354
|
return Object.freeze(snapshot);
|
|
5765
6355
|
}
|
|
5766
6356
|
function snapshotTlsValue(value, name) {
|
|
5767
|
-
if (
|
|
6357
|
+
if (Buffer24.isBuffer(value)) return Buffer24.from(value);
|
|
5768
6358
|
if (value instanceof Uint8Array) return value.slice();
|
|
5769
6359
|
if (Array.isArray(value)) {
|
|
5770
6360
|
const snapshot = new Array(value.length);
|
|
@@ -6234,6 +6824,9 @@ var NativeChunkAssembler = class {
|
|
|
6234
6824
|
framesByKey = /* @__PURE__ */ new Map();
|
|
6235
6825
|
totalBytes = 0;
|
|
6236
6826
|
totalFrames = 0;
|
|
6827
|
+
updateMaxResponseBytes(limit) {
|
|
6828
|
+
this.maxResponseBytes = Math.min(this.maxResponseBytes, limit);
|
|
6829
|
+
}
|
|
6237
6830
|
assemble(frame) {
|
|
6238
6831
|
const key = `${frame.requestId}:${frame.opcode}:${frame.laneId}`;
|
|
6239
6832
|
const previous = this.chunks.get(key);
|
|
@@ -6478,12 +7071,18 @@ var NativeReceiveBuffer = class {
|
|
|
6478
7071
|
var NativeResponseHandler = class {
|
|
6479
7072
|
constructor(options) {
|
|
6480
7073
|
this.options = options;
|
|
7074
|
+
this.maxResponseBytes = options.maxResponseBytes;
|
|
6481
7075
|
}
|
|
6482
7076
|
options;
|
|
6483
7077
|
receiveBuffer = new NativeReceiveBuffer();
|
|
6484
7078
|
drainScheduled = false;
|
|
6485
7079
|
paused = false;
|
|
6486
7080
|
stopped = false;
|
|
7081
|
+
maxResponseBytes;
|
|
7082
|
+
updateMaxResponseBytes(limit) {
|
|
7083
|
+
this.maxResponseBytes = Math.min(this.maxResponseBytes, limit);
|
|
7084
|
+
this.options.chunkAssembler.updateMaxResponseBytes(this.maxResponseBytes);
|
|
7085
|
+
}
|
|
6487
7086
|
onData(chunk) {
|
|
6488
7087
|
if (this.stopped) return;
|
|
6489
7088
|
try {
|
|
@@ -6565,15 +7164,18 @@ var NativeResponseHandler = class {
|
|
|
6565
7164
|
}
|
|
6566
7165
|
const completeFrame = this.options.chunkAssembler.assemble(frame);
|
|
6567
7166
|
if (completeFrame == null) return;
|
|
6568
|
-
if (completeFrame.body.byteLength > this.
|
|
7167
|
+
if (completeFrame.body.byteLength > this.maxResponseBytes) {
|
|
6569
7168
|
throw new FerricStoreError(
|
|
6570
|
-
`native protocol response exceeded ${this.
|
|
7169
|
+
`native protocol response exceeded ${this.maxResponseBytes} bytes`
|
|
6571
7170
|
);
|
|
6572
7171
|
}
|
|
6573
7172
|
let value;
|
|
6574
7173
|
let responseError;
|
|
6575
7174
|
try {
|
|
6576
|
-
value = decodeResponse(completeFrame, pending.opcode,
|
|
7175
|
+
value = decodeResponse(completeFrame, pending.opcode, {
|
|
7176
|
+
...pending,
|
|
7177
|
+
compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
|
|
7178
|
+
});
|
|
6577
7179
|
if (pending.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
|
|
6578
7180
|
} catch (error) {
|
|
6579
7181
|
responseError = error;
|
|
@@ -6589,7 +7191,7 @@ var NativeResponseHandler = class {
|
|
|
6589
7191
|
pending.discardedResponseBytes = discardedResponseBytes;
|
|
6590
7192
|
pending.discardedResponseFrames = discardedResponseFrames;
|
|
6591
7193
|
const chunked = discardedResponseFrames > 1 || (frame.flags & FLAG_MORE_CHUNKS) !== 0;
|
|
6592
|
-
if (discardedResponseBytes > this.
|
|
7194
|
+
if (discardedResponseBytes > this.maxResponseBytes || chunked && discardedResponseBytes > this.options.maxChunkBytes) {
|
|
6593
7195
|
throw new FerricStoreError("native protocol discarded response exceeded configured byte limits");
|
|
6594
7196
|
}
|
|
6595
7197
|
if (discardedResponseFrames > this.options.maxChunkFrames) {
|
|
@@ -6598,12 +7200,14 @@ var NativeResponseHandler = class {
|
|
|
6598
7200
|
if ((frame.flags & FLAG_MORE_CHUNKS) === 0) this.options.takePending(frame.requestId);
|
|
6599
7201
|
}
|
|
6600
7202
|
handleManagementFrame(frame) {
|
|
6601
|
-
if (frame.body.byteLength > this.
|
|
7203
|
+
if (frame.body.byteLength > this.maxResponseBytes) {
|
|
6602
7204
|
throw new FerricStoreError(
|
|
6603
|
-
`native protocol response exceeded ${this.
|
|
7205
|
+
`native protocol response exceeded ${this.maxResponseBytes} bytes`
|
|
6604
7206
|
);
|
|
6605
7207
|
}
|
|
6606
|
-
const value = decodeResponse(frame, frame.opcode
|
|
7208
|
+
const value = decodeResponse(frame, frame.opcode, {
|
|
7209
|
+
compactResponseOpcodes: this.options.compactResponseOpcodes?.() ?? EMPTY_COMPACT_RESPONSE_OPCODES
|
|
7210
|
+
});
|
|
6607
7211
|
if (frame.opcode === OPCODES.windowUpdate) this.options.applyFlowControlLimits(value);
|
|
6608
7212
|
const event = {
|
|
6609
7213
|
flags: frame.flags,
|
|
@@ -6768,6 +7372,40 @@ var NativeWriteQueue = class {
|
|
|
6768
7372
|
}
|
|
6769
7373
|
};
|
|
6770
7374
|
|
|
7375
|
+
// src/native-connection-capabilities.ts
|
|
7376
|
+
var NativeConnectionCapabilities = class {
|
|
7377
|
+
constructor(configuredRequestFrameBytes) {
|
|
7378
|
+
this.configuredRequestFrameBytes = configuredRequestFrameBytes;
|
|
7379
|
+
this.negotiatedRequestFrameBytes = configuredRequestFrameBytes;
|
|
7380
|
+
this.requestFrameBytes = Math.min(configuredRequestFrameBytes, UNAUTHENTICATED_MAX_FRAME_BYTES);
|
|
7381
|
+
}
|
|
7382
|
+
configuredRequestFrameBytes;
|
|
7383
|
+
compactResponseOpcodes = EMPTY_COMPACT_RESPONSE_OPCODES;
|
|
7384
|
+
requestFrameBytes;
|
|
7385
|
+
negotiatedRequestFrameBytes;
|
|
7386
|
+
apply(value) {
|
|
7387
|
+
const limits = startupLimits(value);
|
|
7388
|
+
const negotiation = nativeNegotiation(value);
|
|
7389
|
+
this.compactResponseOpcodes = negotiation.compactResponseOpcodes;
|
|
7390
|
+
if (limits.frameBytes != null) {
|
|
7391
|
+
this.negotiatedRequestFrameBytes = Math.min(
|
|
7392
|
+
this.configuredRequestFrameBytes,
|
|
7393
|
+
limits.frameBytes
|
|
7394
|
+
);
|
|
7395
|
+
this.requestFrameBytes = Math.min(this.requestFrameBytes, this.negotiatedRequestFrameBytes);
|
|
7396
|
+
}
|
|
7397
|
+
return {
|
|
7398
|
+
...limits.laneQueue == null ? {} : { laneQueue: limits.laneQueue },
|
|
7399
|
+
...limits.lanes == null ? {} : { lanes: limits.lanes },
|
|
7400
|
+
...negotiation.maxResponseBytes == null ? {} : { maxResponseBytes: negotiation.maxResponseBytes },
|
|
7401
|
+
...limits.pipelineCommands == null ? {} : { pipelineCommands: limits.pipelineCommands }
|
|
7402
|
+
};
|
|
7403
|
+
}
|
|
7404
|
+
activateAuthenticated() {
|
|
7405
|
+
this.requestFrameBytes = this.negotiatedRequestFrameBytes;
|
|
7406
|
+
}
|
|
7407
|
+
};
|
|
7408
|
+
|
|
6771
7409
|
// src/native-adapter.ts
|
|
6772
7410
|
var NativeAdapter = class _NativeAdapter {
|
|
6773
7411
|
socket;
|
|
@@ -6776,9 +7414,9 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6776
7414
|
closedWaiters = /* @__PURE__ */ new Set();
|
|
6777
7415
|
chunkAssembler;
|
|
6778
7416
|
closed = false;
|
|
7417
|
+
capabilities;
|
|
6779
7418
|
protocolLanes;
|
|
6780
7419
|
maxPipelineCommands = Number.MAX_SAFE_INTEGER;
|
|
6781
|
-
maxRequestFrameBytes;
|
|
6782
7420
|
pendingControlRequests = 0;
|
|
6783
7421
|
maxPendingControlRequests;
|
|
6784
7422
|
heartbeat;
|
|
@@ -6793,7 +7431,7 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6793
7431
|
const normalizedMaxChunkBytes = normalizePositiveLimit(maxChunkBytes, DEFAULT_MAX_CHUNK_BYTES);
|
|
6794
7432
|
const normalizedMaxChunkFrames = normalizePositiveLimit(maxChunkFrames, DEFAULT_MAX_CHUNK_FRAMES);
|
|
6795
7433
|
const normalizedMaxFrameBytes = normalizePositiveLimit(maxFrameBytes, DEFAULT_MAX_FRAME_BYTES);
|
|
6796
|
-
this.
|
|
7434
|
+
this.capabilities = new NativeConnectionCapabilities(normalizedMaxFrameBytes);
|
|
6797
7435
|
const normalizedMaxResponseBytes = normalizePositiveLimit(maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES);
|
|
6798
7436
|
this.chunkAssembler = new NativeChunkAssembler(
|
|
6799
7437
|
normalizedMaxChunkBytes,
|
|
@@ -6820,7 +7458,7 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6820
7458
|
this.heartbeat = new NativeHeartbeat(
|
|
6821
7459
|
this.heartbeatIntervalMs,
|
|
6822
7460
|
async () => {
|
|
6823
|
-
await this.request(buildProtocolCommand(["PING"], this.
|
|
7461
|
+
await this.request(buildProtocolCommand(["PING"], this.capabilities.requestFrameBytes), true);
|
|
6824
7462
|
},
|
|
6825
7463
|
(error) => {
|
|
6826
7464
|
this.failAll(new FerricStoreError("FerricStore protocol heartbeat failed", { cause: error }), true);
|
|
@@ -6831,6 +7469,7 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6831
7469
|
applyFlowControlLimits: (value) => this.applyFlowControlLimits(value),
|
|
6832
7470
|
beginDraining: () => this.beginDraining(),
|
|
6833
7471
|
chunkAssembler: this.chunkAssembler,
|
|
7472
|
+
compactResponseOpcodes: () => this.capabilities.compactResponseOpcodes,
|
|
6834
7473
|
destroy: (error) => this.socket.destroy(error),
|
|
6835
7474
|
failAll: (reason, connectionClosed, message) => this.failAll(reason, connectionClosed, message),
|
|
6836
7475
|
heartbeat: this.heartbeat,
|
|
@@ -6856,6 +7495,7 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6856
7495
|
adapter,
|
|
6857
7496
|
auth: async (username, password) => {
|
|
6858
7497
|
await adapter.request({ laneId: 0, opcode: OPCODES.auth, payload: { password, username } });
|
|
7498
|
+
adapter.capabilities.activateAuthenticated();
|
|
6859
7499
|
},
|
|
6860
7500
|
close: async () => {
|
|
6861
7501
|
await adapter.close();
|
|
@@ -6873,13 +7513,13 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6873
7513
|
return await this.executeCommandArgs(args);
|
|
6874
7514
|
}
|
|
6875
7515
|
async executeCommandArgs(args) {
|
|
6876
|
-
const command = buildProtocolCommand(args, this.
|
|
7516
|
+
const command = buildProtocolCommand(args, this.capabilities.requestFrameBytes);
|
|
6877
7517
|
return await this.request(command);
|
|
6878
7518
|
}
|
|
6879
7519
|
/** @internal Execute raw command arguments on a topology-selected lane. */
|
|
6880
7520
|
async executeCommandOnLane(args, laneId) {
|
|
6881
7521
|
return await this.executeProtocolCommand(
|
|
6882
|
-
buildProtocolCommand(args, this.
|
|
7522
|
+
buildProtocolCommand(args, this.capabilities.requestFrameBytes),
|
|
6883
7523
|
laneId
|
|
6884
7524
|
);
|
|
6885
7525
|
}
|
|
@@ -6901,7 +7541,7 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6901
7541
|
laneId,
|
|
6902
7542
|
options,
|
|
6903
7543
|
this.maxPipelineCommands,
|
|
6904
|
-
this.
|
|
7544
|
+
this.capabilities.requestFrameBytes
|
|
6905
7545
|
);
|
|
6906
7546
|
}
|
|
6907
7547
|
/** @internal Execute an ordered pipeline on a topology-selected lane. */
|
|
@@ -6912,13 +7552,11 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6912
7552
|
laneId,
|
|
6913
7553
|
options,
|
|
6914
7554
|
this.maxPipelineCommands,
|
|
6915
|
-
this.
|
|
7555
|
+
this.capabilities.requestFrameBytes
|
|
6916
7556
|
);
|
|
6917
7557
|
}
|
|
6918
7558
|
async close() {
|
|
6919
|
-
if (this.closed)
|
|
6920
|
-
return;
|
|
6921
|
-
}
|
|
7559
|
+
if (this.closed) return;
|
|
6922
7560
|
this.failAll(new FerricStoreError("FerricStore connection closed"), true);
|
|
6923
7561
|
this.socket.destroy();
|
|
6924
7562
|
}
|
|
@@ -6936,7 +7574,9 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6936
7574
|
});
|
|
6937
7575
|
this.applyStartupLimits(response);
|
|
6938
7576
|
const authRequired = field(response, "auth_required");
|
|
6939
|
-
|
|
7577
|
+
const required = authRequired == null ? false : booleanResponse(authRequired);
|
|
7578
|
+
if (authRequired != null && !required) this.capabilities.activateAuthenticated();
|
|
7579
|
+
return required;
|
|
6940
7580
|
}
|
|
6941
7581
|
request(command, allowWhileDraining = false) {
|
|
6942
7582
|
if (this.closed || this.draining && !allowWhileDraining) {
|
|
@@ -6977,7 +7617,7 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
6977
7617
|
let frame;
|
|
6978
7618
|
try {
|
|
6979
7619
|
requestId = this.requestScheduler.nextRequestId();
|
|
6980
|
-
frame = encodeRequest(command, requestId, this.
|
|
7620
|
+
frame = encodeRequest(command, requestId, this.capabilities.requestFrameBytes);
|
|
6981
7621
|
} catch (error) {
|
|
6982
7622
|
if (hasFlowControlCredit) this.flowControl.release(laneId);
|
|
6983
7623
|
return Promise.reject(error instanceof Error ? error : new FerricStoreError(String(error), { raw: error }));
|
|
@@ -7031,9 +7671,7 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
7031
7671
|
this.resolveClosedWaiters();
|
|
7032
7672
|
}
|
|
7033
7673
|
failAll(reason, connectionClosed = false, dispatchedMessage) {
|
|
7034
|
-
if (this.closed)
|
|
7035
|
-
return;
|
|
7036
|
-
}
|
|
7674
|
+
if (this.closed) return;
|
|
7037
7675
|
this.closed = true;
|
|
7038
7676
|
this.responseHandler.stop();
|
|
7039
7677
|
this.resolveClosedWaiters();
|
|
@@ -7099,18 +7737,18 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
7099
7737
|
}
|
|
7100
7738
|
applyStartupLimits(value) {
|
|
7101
7739
|
this.applyFlowControlLimits(value);
|
|
7102
|
-
const
|
|
7103
|
-
if (
|
|
7104
|
-
this.
|
|
7740
|
+
const capabilities = this.capabilities.apply(value);
|
|
7741
|
+
if (capabilities.maxResponseBytes != null) {
|
|
7742
|
+
this.responseHandler.updateMaxResponseBytes(capabilities.maxResponseBytes);
|
|
7105
7743
|
}
|
|
7106
|
-
if (
|
|
7107
|
-
this.
|
|
7744
|
+
if (capabilities.laneQueue != null) {
|
|
7745
|
+
this.flowControl.updateLaneQueueLimit(capabilities.laneQueue);
|
|
7108
7746
|
}
|
|
7109
|
-
if (
|
|
7110
|
-
this.
|
|
7747
|
+
if (capabilities.lanes != null) {
|
|
7748
|
+
this.protocolLanes = Math.min(this.protocolLanes, capabilities.lanes);
|
|
7111
7749
|
}
|
|
7112
|
-
if (
|
|
7113
|
-
this.
|
|
7750
|
+
if (capabilities.pipelineCommands != null) {
|
|
7751
|
+
this.maxPipelineCommands = capabilities.pipelineCommands;
|
|
7114
7752
|
}
|
|
7115
7753
|
}
|
|
7116
7754
|
};
|
|
@@ -7124,6 +7762,29 @@ function executeCommandArgs(executor, args) {
|
|
|
7124
7762
|
|
|
7125
7763
|
// src/reconnecting-executor.ts
|
|
7126
7764
|
import "buffer";
|
|
7765
|
+
|
|
7766
|
+
// src/command-retry-policy.ts
|
|
7767
|
+
import { Buffer as Buffer28 } from "buffer";
|
|
7768
|
+
function isCasMutation(args) {
|
|
7769
|
+
const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
|
|
7770
|
+
const name = commandName2(args[offset]);
|
|
7771
|
+
if (name === "CAS") return true;
|
|
7772
|
+
if (name !== "FLOW.POLICY.SET") return false;
|
|
7773
|
+
for (let index = offset + 2; index < args.length; index += 2) {
|
|
7774
|
+
if (!Object.hasOwn(args, index)) return false;
|
|
7775
|
+
if (commandName2(args[index]) === "EXPECTED_GENERATION") return true;
|
|
7776
|
+
}
|
|
7777
|
+
return false;
|
|
7778
|
+
}
|
|
7779
|
+
function commandName2(value) {
|
|
7780
|
+
if (typeof value === "string") return value.toUpperCase();
|
|
7781
|
+
if (Buffer28.isBuffer(value) || value instanceof Uint8Array) {
|
|
7782
|
+
return Buffer28.from(value).toString("utf8").toUpperCase();
|
|
7783
|
+
}
|
|
7784
|
+
return void 0;
|
|
7785
|
+
}
|
|
7786
|
+
|
|
7787
|
+
// src/reconnecting-executor.ts
|
|
7127
7788
|
var ReconnectingExecutor = class {
|
|
7128
7789
|
constructor(createExecutor, options = {}) {
|
|
7129
7790
|
this.createExecutor = createExecutor;
|
|
@@ -7154,7 +7815,12 @@ var ReconnectingExecutor = class {
|
|
|
7154
7815
|
async executeCommandArgs(args) {
|
|
7155
7816
|
const snapshot = snapshotCommandArguments(args);
|
|
7156
7817
|
assertCommandHasStableConnectionState(snapshot);
|
|
7157
|
-
|
|
7818
|
+
const casMutation = isCasMutation(snapshot);
|
|
7819
|
+
return await this.withReconnect(
|
|
7820
|
+
(executor) => executeCommandArgs(executor, snapshot),
|
|
7821
|
+
casMutation ? isClosedConnectionError : isReconnectableClosedConnectionError,
|
|
7822
|
+
!casMutation
|
|
7823
|
+
);
|
|
7158
7824
|
}
|
|
7159
7825
|
async ready() {
|
|
7160
7826
|
await this.executorPromise;
|
|
@@ -7202,333 +7868,134 @@ var ReconnectingExecutor = class {
|
|
|
7202
7868
|
async refreshTopology() {
|
|
7203
7869
|
return await this.withReconnect(async (executor) => {
|
|
7204
7870
|
if (executor.refreshTopology == null) {
|
|
7205
|
-
throw new FerricStoreError("topology refresh requires a topology-aware native executor");
|
|
7206
|
-
}
|
|
7207
|
-
return await executor.refreshTopology();
|
|
7208
|
-
}, isReadOnlyReconnectableClosedConnectionError);
|
|
7209
|
-
}
|
|
7210
|
-
async route(key) {
|
|
7211
|
-
return await this.withReconnect(async (executor) => {
|
|
7212
|
-
if (executor.route == null) {
|
|
7213
|
-
throw new FerricStoreError("route lookup requires a topology-aware native executor");
|
|
7214
|
-
}
|
|
7215
|
-
return await executor.route(key);
|
|
7216
|
-
}, isReadOnlyReconnectableClosedConnectionError);
|
|
7217
|
-
}
|
|
7218
|
-
async close() {
|
|
7219
|
-
if (this.closePromise != null) {
|
|
7220
|
-
await this.closePromise;
|
|
7221
|
-
return;
|
|
7222
|
-
}
|
|
7223
|
-
this.closed = true;
|
|
7224
|
-
this.retryAbortController.abort(new FerricStoreError("FerricStore client is closed"));
|
|
7225
|
-
const executorPromise = this.executorPromise;
|
|
7226
|
-
const reconnectPromise = this.reconnectPromise;
|
|
7227
|
-
this.closePromise = (async () => {
|
|
7228
|
-
let closeError;
|
|
7229
|
-
let closeFailed = false;
|
|
7230
|
-
const executor = await executorPromise.catch(() => void 0);
|
|
7231
|
-
try {
|
|
7232
|
-
await Promise.resolve(executor?.close?.());
|
|
7233
|
-
} catch (error) {
|
|
7234
|
-
closeFailed = true;
|
|
7235
|
-
closeError = error;
|
|
7236
|
-
}
|
|
7237
|
-
await reconnectPromise?.catch(() => void 0);
|
|
7238
|
-
if (closeFailed) throw closeError;
|
|
7239
|
-
})();
|
|
7240
|
-
await this.closePromise;
|
|
7241
|
-
}
|
|
7242
|
-
async withReconnect(operation, reconnectable = isReconnectableClosedConnectionError) {
|
|
7243
|
-
let executor = await this.executorPromise;
|
|
7244
|
-
let retries = 0;
|
|
7245
|
-
for (; ; ) {
|
|
7246
|
-
if (this.closed) throw new FerricStoreError("FerricStore client is closed");
|
|
7247
|
-
try {
|
|
7248
|
-
return await operation(executor);
|
|
7249
|
-
} catch (error) {
|
|
7250
|
-
if (this.closed || retries >= this.maxRetries || !reconnectable(error)) throw error;
|
|
7251
|
-
for (; ; ) {
|
|
7252
|
-
retries += 1;
|
|
7253
|
-
try {
|
|
7254
|
-
executor = await this.reconnect(executor);
|
|
7255
|
-
break;
|
|
7256
|
-
} catch (reconnectError) {
|
|
7257
|
-
if (this.closed || retries >= this.maxRetries) throw reconnectError;
|
|
7258
|
-
await this.waitBeforeReconnect(retries);
|
|
7259
|
-
}
|
|
7260
|
-
}
|
|
7261
|
-
}
|
|
7262
|
-
}
|
|
7263
|
-
}
|
|
7264
|
-
async waitBeforeReconnect(failedAttempts) {
|
|
7265
|
-
const exponent = Math.min(30, Math.max(0, failedAttempts - 1));
|
|
7266
|
-
const base = Math.min(this.maxDelayMs, this.baseDelayMs * 2 ** exponent);
|
|
7267
|
-
const jitter = base * (this.jitterPct / 100) * Math.random();
|
|
7268
|
-
try {
|
|
7269
|
-
await sleep(Math.min(this.maxDelayMs, base + jitter), this.retryAbortController.signal);
|
|
7270
|
-
} catch (error) {
|
|
7271
|
-
if (this.closed) throw new FerricStoreError("FerricStore client is closed", { cause: error });
|
|
7272
|
-
throw error;
|
|
7273
|
-
}
|
|
7274
|
-
}
|
|
7275
|
-
async reconnect(staleExecutor) {
|
|
7276
|
-
if (this.closed) throw new FerricStoreError("FerricStore client is closed");
|
|
7277
|
-
const competingReconnect = this.reconnectPromise;
|
|
7278
|
-
if (competingReconnect != null) return await competingReconnect;
|
|
7279
|
-
const observedExecutorPromise = this.executorPromise;
|
|
7280
|
-
const currentExecutor = await observedExecutorPromise.catch(() => void 0);
|
|
7281
|
-
if (this.closed) throw new FerricStoreError("FerricStore client is closed");
|
|
7282
|
-
if (this.reconnectPromise != null) return await this.reconnectPromise;
|
|
7283
|
-
if (this.executorPromise !== observedExecutorPromise) return await this.executorPromise;
|
|
7284
|
-
if (currentExecutor != null && currentExecutor !== staleExecutor) return currentExecutor;
|
|
7285
|
-
this.reconnectPromise = (async () => {
|
|
7286
|
-
await Promise.resolve(staleExecutor.close?.()).catch(() => void 0);
|
|
7287
|
-
const nextExecutor = await this.createExecutor(this.retryAbortController.signal);
|
|
7288
|
-
if (this.closed) {
|
|
7289
|
-
await Promise.resolve(nextExecutor.close?.()).catch(() => void 0);
|
|
7290
|
-
throw new FerricStoreError("FerricStore client is closed");
|
|
7291
|
-
}
|
|
7292
|
-
this.executorPromise = Promise.resolve(nextExecutor);
|
|
7293
|
-
return nextExecutor;
|
|
7294
|
-
})().finally(() => {
|
|
7295
|
-
this.reconnectPromise = void 0;
|
|
7296
|
-
});
|
|
7297
|
-
return await this.reconnectPromise;
|
|
7298
|
-
}
|
|
7299
|
-
};
|
|
7300
|
-
function isReconnectableClosedConnectionError(error) {
|
|
7301
|
-
return error instanceof ConnectionClosedError && error.requestDisposition === "unsent";
|
|
7302
|
-
}
|
|
7303
|
-
function isReadOnlyReconnectableClosedConnectionError(error) {
|
|
7304
|
-
const pending = [error];
|
|
7305
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7306
|
-
for (let visited = 0; visited < 16 && pending.length > 0; visited += 1) {
|
|
7307
|
-
const current = pending.pop();
|
|
7308
|
-
if (isReconnectableClosedConnectionError(current)) return true;
|
|
7309
|
-
if (current == null || typeof current !== "object" && typeof current !== "function" || seen.has(current)) continue;
|
|
7310
|
-
seen.add(current);
|
|
7311
|
-
if (current instanceof Error && current.cause != null) pending.push(current.cause);
|
|
7312
|
-
if (current instanceof FerricStoreError && current.raw != null) pending.push(current.raw);
|
|
7313
|
-
}
|
|
7314
|
-
return false;
|
|
7315
|
-
}
|
|
7316
|
-
function normalizeNonNegativeInteger2(value, fallback) {
|
|
7317
|
-
return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : fallback;
|
|
7318
|
-
}
|
|
7319
|
-
|
|
7320
|
-
// src/topology.ts
|
|
7321
|
-
import "buffer";
|
|
7322
|
-
|
|
7323
|
-
// src/topology-routing.ts
|
|
7324
|
-
import { Buffer as Buffer26 } from "buffer";
|
|
7325
|
-
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 };
|
|
7871
|
+
throw new FerricStoreError("topology refresh requires a topology-aware native executor");
|
|
7441
7872
|
}
|
|
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;
|
|
7873
|
+
return await executor.refreshTopology();
|
|
7874
|
+
}, isReadOnlyReconnectableClosedConnectionError);
|
|
7453
7875
|
}
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7876
|
+
async route(key) {
|
|
7877
|
+
return await this.withReconnect(async (executor) => {
|
|
7878
|
+
if (executor.route == null) {
|
|
7879
|
+
throw new FerricStoreError("route lookup requires a topology-aware native executor");
|
|
7880
|
+
}
|
|
7881
|
+
return await executor.route(key);
|
|
7882
|
+
}, isReadOnlyReconnectableClosedConnectionError);
|
|
7458
7883
|
}
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
async run(operation) {
|
|
7464
|
-
await this.acquire();
|
|
7465
|
-
try {
|
|
7466
|
-
return await operation();
|
|
7467
|
-
} finally {
|
|
7468
|
-
this.release();
|
|
7884
|
+
async close() {
|
|
7885
|
+
if (this.closePromise != null) {
|
|
7886
|
+
await this.closePromise;
|
|
7887
|
+
return;
|
|
7469
7888
|
}
|
|
7889
|
+
this.closed = true;
|
|
7890
|
+
this.retryAbortController.abort(new FerricStoreError("FerricStore client is closed"));
|
|
7891
|
+
const executorPromise = this.executorPromise;
|
|
7892
|
+
const reconnectPromise = this.reconnectPromise;
|
|
7893
|
+
this.closePromise = (async () => {
|
|
7894
|
+
let closeError;
|
|
7895
|
+
let closeFailed = false;
|
|
7896
|
+
const executor = await executorPromise.catch(() => void 0);
|
|
7897
|
+
try {
|
|
7898
|
+
await Promise.resolve(executor?.close?.());
|
|
7899
|
+
} catch (error) {
|
|
7900
|
+
closeFailed = true;
|
|
7901
|
+
closeError = error;
|
|
7902
|
+
}
|
|
7903
|
+
await reconnectPromise?.catch(() => void 0);
|
|
7904
|
+
if (closeFailed) throw closeError;
|
|
7905
|
+
})();
|
|
7906
|
+
await this.closePromise;
|
|
7470
7907
|
}
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7908
|
+
async withReconnect(operation, reconnectable = isReconnectableClosedConnectionError, replayAllowed = true) {
|
|
7909
|
+
let executor = await this.executorPromise;
|
|
7910
|
+
let retries = 0;
|
|
7911
|
+
for (; ; ) {
|
|
7912
|
+
if (this.closed) throw new FerricStoreError("FerricStore client is closed");
|
|
7913
|
+
try {
|
|
7914
|
+
return await operation(executor);
|
|
7915
|
+
} catch (error) {
|
|
7916
|
+
if (this.closed || retries >= this.maxRetries || !reconnectable(error)) throw error;
|
|
7917
|
+
if (!replayAllowed) {
|
|
7918
|
+
await this.reconnect(executor).catch(() => void 0);
|
|
7919
|
+
throw error;
|
|
7920
|
+
}
|
|
7921
|
+
for (; ; ) {
|
|
7922
|
+
retries += 1;
|
|
7923
|
+
try {
|
|
7924
|
+
executor = await this.reconnect(executor);
|
|
7925
|
+
break;
|
|
7926
|
+
} catch (reconnectError) {
|
|
7927
|
+
if (this.closed || retries >= this.maxRetries) throw reconnectError;
|
|
7928
|
+
await this.waitBeforeReconnect(retries);
|
|
7929
|
+
}
|
|
7930
|
+
}
|
|
7931
|
+
}
|
|
7475
7932
|
}
|
|
7476
|
-
return new Promise((resolve) => this.pending.push(resolve));
|
|
7477
7933
|
}
|
|
7478
|
-
|
|
7479
|
-
const
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
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;
|
|
7934
|
+
async waitBeforeReconnect(failedAttempts) {
|
|
7935
|
+
const exponent = Math.min(30, Math.max(0, failedAttempts - 1));
|
|
7936
|
+
const base = Math.min(this.maxDelayMs, this.baseDelayMs * 2 ** exponent);
|
|
7937
|
+
const jitter = base * (this.jitterPct / 100) * Math.random();
|
|
7938
|
+
try {
|
|
7939
|
+
await sleep(Math.min(this.maxDelayMs, base + jitter), this.retryAbortController.signal);
|
|
7940
|
+
} catch (error) {
|
|
7941
|
+
if (this.closed) throw new FerricStoreError("FerricStore client is closed", { cause: error });
|
|
7942
|
+
throw error;
|
|
7492
7943
|
}
|
|
7493
7944
|
}
|
|
7945
|
+
async reconnect(staleExecutor) {
|
|
7946
|
+
if (this.closed) throw new FerricStoreError("FerricStore client is closed");
|
|
7947
|
+
const competingReconnect = this.reconnectPromise;
|
|
7948
|
+
if (competingReconnect != null) return await competingReconnect;
|
|
7949
|
+
const observedExecutorPromise = this.executorPromise;
|
|
7950
|
+
const currentExecutor = await observedExecutorPromise.catch(() => void 0);
|
|
7951
|
+
if (this.closed) throw new FerricStoreError("FerricStore client is closed");
|
|
7952
|
+
if (this.reconnectPromise != null) return await this.reconnectPromise;
|
|
7953
|
+
if (this.executorPromise !== observedExecutorPromise) return await this.executorPromise;
|
|
7954
|
+
if (currentExecutor != null && currentExecutor !== staleExecutor) return currentExecutor;
|
|
7955
|
+
this.reconnectPromise = (async () => {
|
|
7956
|
+
await Promise.resolve(staleExecutor.close?.()).catch(() => void 0);
|
|
7957
|
+
const nextExecutor = await this.createExecutor(this.retryAbortController.signal);
|
|
7958
|
+
if (this.closed) {
|
|
7959
|
+
await Promise.resolve(nextExecutor.close?.()).catch(() => void 0);
|
|
7960
|
+
throw new FerricStoreError("FerricStore client is closed");
|
|
7961
|
+
}
|
|
7962
|
+
this.executorPromise = Promise.resolve(nextExecutor);
|
|
7963
|
+
return nextExecutor;
|
|
7964
|
+
})().finally(() => {
|
|
7965
|
+
this.reconnectPromise = void 0;
|
|
7966
|
+
});
|
|
7967
|
+
return await this.reconnectPromise;
|
|
7968
|
+
}
|
|
7494
7969
|
};
|
|
7495
|
-
function
|
|
7496
|
-
return
|
|
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;
|
|
7970
|
+
function isReconnectableClosedConnectionError(error) {
|
|
7971
|
+
return error instanceof ConnectionClosedError && error.requestDisposition === "unsent";
|
|
7510
7972
|
}
|
|
7511
|
-
function
|
|
7512
|
-
|
|
7513
|
-
return end > 0 ? rest.subarray(0, end) : hashTagOrKey(fallbackKey);
|
|
7973
|
+
function isClosedConnectionError(error) {
|
|
7974
|
+
return error instanceof ConnectionClosedError;
|
|
7514
7975
|
}
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
} else {
|
|
7526
|
-
hashInput = hashTagOrKey(keyBytes);
|
|
7976
|
+
function isReadOnlyReconnectableClosedConnectionError(error) {
|
|
7977
|
+
const pending = [error];
|
|
7978
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7979
|
+
for (let visited = 0; visited < 16 && pending.length > 0; visited += 1) {
|
|
7980
|
+
const current = pending.pop();
|
|
7981
|
+
if (isReconnectableClosedConnectionError(current)) return true;
|
|
7982
|
+
if (current == null || typeof current !== "object" && typeof current !== "function" || seen.has(current)) continue;
|
|
7983
|
+
seen.add(current);
|
|
7984
|
+
if (current instanceof Error && current.cause != null) pending.push(current.cause);
|
|
7985
|
+
if (current instanceof FerricStoreError && current.raw != null) pending.push(current.raw);
|
|
7527
7986
|
}
|
|
7528
|
-
return
|
|
7987
|
+
return false;
|
|
7988
|
+
}
|
|
7989
|
+
function normalizeNonNegativeInteger2(value, fallback) {
|
|
7990
|
+
return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : fallback;
|
|
7529
7991
|
}
|
|
7530
7992
|
|
|
7993
|
+
// src/topology.ts
|
|
7994
|
+
import "buffer";
|
|
7995
|
+
|
|
7531
7996
|
// src/topology-routing.ts
|
|
7997
|
+
import { Buffer as Buffer30 } from "buffer";
|
|
7998
|
+
import { createHash } from "crypto";
|
|
7532
7999
|
var FLOW_PARTITION_ROUTE_CACHE_MAX = 1024;
|
|
7533
8000
|
var flowPartitionRouteCache = /* @__PURE__ */ new Map();
|
|
7534
8001
|
function routingKeyFromProtocolPayload(name, command) {
|
|
@@ -7536,9 +8003,18 @@ function routingKeyFromProtocolPayload(name, command) {
|
|
|
7536
8003
|
return void 0;
|
|
7537
8004
|
}
|
|
7538
8005
|
if (isPlainObject3(command.payload)) {
|
|
7539
|
-
for (const field2 of [
|
|
8006
|
+
for (const field2 of [
|
|
8007
|
+
"key",
|
|
8008
|
+
"partition_key",
|
|
8009
|
+
"id",
|
|
8010
|
+
"owner_flow_id",
|
|
8011
|
+
"parent_flow_id",
|
|
8012
|
+
"root_flow_id",
|
|
8013
|
+
"correlation_id",
|
|
8014
|
+
"scope"
|
|
8015
|
+
]) {
|
|
7540
8016
|
const value = getField(command.payload, field2);
|
|
7541
|
-
if (typeof value === "string" ||
|
|
8017
|
+
if (typeof value === "string" || Buffer30.isBuffer(value)) {
|
|
7542
8018
|
return value;
|
|
7543
8019
|
}
|
|
7544
8020
|
}
|
|
@@ -7585,9 +8061,9 @@ function flowRoutingData(name, args) {
|
|
|
7585
8061
|
if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
|
|
7586
8062
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
7587
8063
|
}
|
|
7588
|
-
if (
|
|
7589
|
-
const
|
|
7590
|
-
if (
|
|
8064
|
+
if (Buffer30.isBuffer(partition)) {
|
|
8065
|
+
const text3 = partition.toString("utf8").toUpperCase();
|
|
8066
|
+
if (text3 !== "AUTO" && text3 !== "MIXED") {
|
|
7591
8067
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
7592
8068
|
}
|
|
7593
8069
|
}
|
|
@@ -7676,22 +8152,22 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
|
|
|
7676
8152
|
return { handled: false };
|
|
7677
8153
|
}
|
|
7678
8154
|
function isRoutingKey(value) {
|
|
7679
|
-
return typeof value === "string" ||
|
|
8155
|
+
return typeof value === "string" || Buffer30.isBuffer(value);
|
|
7680
8156
|
}
|
|
7681
8157
|
function flowLogicalPartitionRoutingKey(value) {
|
|
7682
|
-
if (typeof value !== "string" && !
|
|
8158
|
+
if (typeof value !== "string" && !Buffer30.isBuffer(value)) {
|
|
7683
8159
|
return void 0;
|
|
7684
8160
|
}
|
|
7685
|
-
const bytes2 =
|
|
7686
|
-
const
|
|
7687
|
-
const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(
|
|
8161
|
+
const bytes2 = Buffer30.isBuffer(value) ? value : Buffer30.from(value);
|
|
8162
|
+
const text3 = bytes2.toString("utf8");
|
|
8163
|
+
const autoMatch = /^__flow_auto__:(0|[1-9]\d{0,2})$/u.exec(text3);
|
|
7688
8164
|
if (autoMatch != null) {
|
|
7689
8165
|
const bucket = Number(autoMatch[1]);
|
|
7690
8166
|
if (bucket < 256) {
|
|
7691
|
-
return `
|
|
8167
|
+
return `{fa:${bucket}}`;
|
|
7692
8168
|
}
|
|
7693
8169
|
}
|
|
7694
|
-
const cacheKey = `${
|
|
8170
|
+
const cacheKey = `${Buffer30.isBuffer(value) ? "b" : "s"}:${bytes2.toString("base64")}`;
|
|
7695
8171
|
const cached = flowPartitionRouteCache.get(cacheKey);
|
|
7696
8172
|
if (cached != null) {
|
|
7697
8173
|
flowPartitionRouteCache.delete(cacheKey);
|
|
@@ -7699,7 +8175,7 @@ function flowLogicalPartitionRoutingKey(value) {
|
|
|
7699
8175
|
return cached;
|
|
7700
8176
|
}
|
|
7701
8177
|
const digest = createHash("sha256").update(bytes2).digest("base64url");
|
|
7702
|
-
const routeKey = `
|
|
8178
|
+
const routeKey = `{f:${digest}}`;
|
|
7703
8179
|
if (flowPartitionRouteCache.size >= FLOW_PARTITION_ROUTE_CACHE_MAX) {
|
|
7704
8180
|
const oldest = flowPartitionRouteCache.keys().next().value;
|
|
7705
8181
|
if (oldest != null) flowPartitionRouteCache.delete(oldest);
|
|
@@ -7708,18 +8184,17 @@ function flowLogicalPartitionRoutingKey(value) {
|
|
|
7708
8184
|
return routeKey;
|
|
7709
8185
|
}
|
|
7710
8186
|
function flowAutoIdRoutingKey(value) {
|
|
7711
|
-
if (typeof value !== "string" && !
|
|
8187
|
+
if (typeof value !== "string" && !Buffer30.isBuffer(value)) {
|
|
7712
8188
|
return void 0;
|
|
7713
8189
|
}
|
|
7714
|
-
const
|
|
7715
|
-
|
|
7716
|
-
return `f:{fa:${bucket}}:route`;
|
|
8190
|
+
const bucket = (Buffer30.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
|
|
8191
|
+
return `{fa:${bucket}}`;
|
|
7717
8192
|
}
|
|
7718
8193
|
function flowClaimLogicalPartitionRoutingKey(value) {
|
|
7719
|
-
if (typeof value !== "string" && !
|
|
8194
|
+
if (typeof value !== "string" && !Buffer30.isBuffer(value)) return void 0;
|
|
7720
8195
|
const selector = commandPart(value);
|
|
7721
8196
|
if (selector === "AUTO" || selector === "ANY") return void 0;
|
|
7722
|
-
if (selector === "GLOBAL") return "
|
|
8197
|
+
if (selector === "GLOBAL") return "{f}";
|
|
7723
8198
|
return flowLogicalPartitionRoutingKey(value);
|
|
7724
8199
|
}
|
|
7725
8200
|
function singleShardFlowPartitionKey(values) {
|
|
@@ -7731,7 +8206,7 @@ function singleShardFlowClaimPartitionKey(values) {
|
|
|
7731
8206
|
return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
|
|
7732
8207
|
}
|
|
7733
8208
|
function singleShardKey(keys) {
|
|
7734
|
-
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !
|
|
8209
|
+
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer30.isBuffer(key))) {
|
|
7735
8210
|
return void 0;
|
|
7736
8211
|
}
|
|
7737
8212
|
const usable = keys;
|
|
@@ -7742,7 +8217,7 @@ function singleShardKey(keys) {
|
|
|
7742
8217
|
const firstSlot = routingSlotForKey(first);
|
|
7743
8218
|
return usable.every((key) => routingSlotForKey(key) === firstSlot) ? first : void 0;
|
|
7744
8219
|
}
|
|
7745
|
-
function
|
|
8220
|
+
function commandName3(args) {
|
|
7746
8221
|
return commandView(args).name;
|
|
7747
8222
|
}
|
|
7748
8223
|
var commandPart = commandToken;
|
|
@@ -7764,7 +8239,7 @@ function routedKeyGroups(keys, routeKey) {
|
|
|
7764
8239
|
const groups = /* @__PURE__ */ new Map();
|
|
7765
8240
|
for (let index = 0; index < keys.length; index += 1) {
|
|
7766
8241
|
const key = keys[index];
|
|
7767
|
-
if (typeof key !== "string" && !
|
|
8242
|
+
if (typeof key !== "string" && !Buffer30.isBuffer(key)) return void 0;
|
|
7768
8243
|
const route = routeKey(key);
|
|
7769
8244
|
const groupKey = `${route.endpointKey}\0${route.laneId}`;
|
|
7770
8245
|
const group = groups.get(groupKey);
|
|
@@ -8005,7 +8480,16 @@ function isExplicitlySafeReroute(error) {
|
|
|
8005
8480
|
if (error instanceof ConnectionClosedError) {
|
|
8006
8481
|
return error.requestDisposition === "unsent";
|
|
8007
8482
|
}
|
|
8008
|
-
return error instanceof RerouteError &&
|
|
8483
|
+
return error instanceof RerouteError && error.retryable === true && error.safeToRetry === true;
|
|
8484
|
+
}
|
|
8485
|
+
function retryAfterMs(error) {
|
|
8486
|
+
return error instanceof FerricStoreError ? error.retryAfterMs ?? 0 : 0;
|
|
8487
|
+
}
|
|
8488
|
+
async function waitForExplicitlySafeReroute(error) {
|
|
8489
|
+
if (!isExplicitlySafeReroute(error)) return false;
|
|
8490
|
+
const delayMs = retryAfterMs(error);
|
|
8491
|
+
if (delayMs > 0) await sleep(delayMs);
|
|
8492
|
+
return true;
|
|
8009
8493
|
}
|
|
8010
8494
|
|
|
8011
8495
|
// src/topology-endpoint-trust.ts
|
|
@@ -8147,7 +8631,7 @@ var TopologyPipelineExecutor = class {
|
|
|
8147
8631
|
commands.forEach((command, index) => {
|
|
8148
8632
|
const routed = this.context.routeData(command);
|
|
8149
8633
|
if (routed == null) {
|
|
8150
|
-
if (decomposableCommandNames.has(
|
|
8634
|
+
if (decomposableCommandNames.has(commandName3(command) ?? "")) standalone.push({ command, index });
|
|
8151
8635
|
else {
|
|
8152
8636
|
controlCommands.push(command);
|
|
8153
8637
|
controlIndices.push(index);
|
|
@@ -8363,7 +8847,7 @@ function topologyRouteIsCurrent(topology, route) {
|
|
|
8363
8847
|
// src/topology-route-planner.ts
|
|
8364
8848
|
function topologyRouteData(args, route) {
|
|
8365
8849
|
if (args.length === 0) return void 0;
|
|
8366
|
-
const name =
|
|
8850
|
+
const name = commandName3(args);
|
|
8367
8851
|
if (name?.startsWith("FLOW.") === true) {
|
|
8368
8852
|
const routed = flowRoutingData(name, args);
|
|
8369
8853
|
return routed == null ? void 0 : {
|
|
@@ -8392,7 +8876,7 @@ var TopologyScatterExecutor = class {
|
|
|
8392
8876
|
}
|
|
8393
8877
|
dependencies;
|
|
8394
8878
|
async execute(args) {
|
|
8395
|
-
const name =
|
|
8879
|
+
const name = commandName3(args);
|
|
8396
8880
|
if (name === "MGET") {
|
|
8397
8881
|
const value = await this.scatterArray(name, args.slice(1));
|
|
8398
8882
|
return value == null ? { handled: false } : { handled: true, value };
|
|
@@ -8474,6 +8958,18 @@ var TopologyScatterExecutor = class {
|
|
|
8474
8958
|
}
|
|
8475
8959
|
};
|
|
8476
8960
|
|
|
8961
|
+
// src/topology-reroute-retry.ts
|
|
8962
|
+
async function canRetrySafeReroute(error, attempt, retryAllowed, refresh, assertOpen) {
|
|
8963
|
+
if (attempt !== 0 || !isRetryableRouteError(error)) return false;
|
|
8964
|
+
const refreshed = await refresh().then(
|
|
8965
|
+
() => true,
|
|
8966
|
+
() => false
|
|
8967
|
+
);
|
|
8968
|
+
if (!refreshed || !retryAllowed || !await waitForExplicitlySafeReroute(error)) return false;
|
|
8969
|
+
assertOpen();
|
|
8970
|
+
return true;
|
|
8971
|
+
}
|
|
8972
|
+
|
|
8477
8973
|
// src/topology.ts
|
|
8478
8974
|
var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
8479
8975
|
adapterOptions;
|
|
@@ -8659,6 +9155,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
8659
9155
|
this.assertOpen();
|
|
8660
9156
|
const snapshot = snapshotCommandArguments(args);
|
|
8661
9157
|
assertCommandHasStableConnectionState(snapshot);
|
|
9158
|
+
const casMutation = isCasMutation(snapshot);
|
|
8662
9159
|
let rerouteAttempt = 0;
|
|
8663
9160
|
for (let planningAttempt = 0; planningAttempt < MAX_TOPOLOGY_PLANNING_ATTEMPTS; planningAttempt += 1) {
|
|
8664
9161
|
const routed = this.routeData(snapshot);
|
|
@@ -8674,7 +9171,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
8674
9171
|
try {
|
|
8675
9172
|
return routed.command == null ? await adapter.executeCommandOnLane(snapshot, routed.route.laneId) : await adapter.executeProtocolCommand(routed.command, routed.route.laneId);
|
|
8676
9173
|
} catch (error) {
|
|
8677
|
-
if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt)) {
|
|
9174
|
+
if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt, !casMutation)) {
|
|
8678
9175
|
rerouteAttempt += 1;
|
|
8679
9176
|
continue;
|
|
8680
9177
|
}
|
|
@@ -8716,6 +9213,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
8716
9213
|
assertCommandHasStableConnectionState(command);
|
|
8717
9214
|
}
|
|
8718
9215
|
let rerouteAttempt = 0;
|
|
9216
|
+
const containsCasMutation = snapshot.some(isCasMutation);
|
|
8719
9217
|
for (let planningAttempt = 0; planningAttempt < MAX_TOPOLOGY_PLANNING_ATTEMPTS; planningAttempt += 1) {
|
|
8720
9218
|
const route = singleRouteForCommands(snapshot, (command) => this.routeData(command));
|
|
8721
9219
|
if (route == null) return void 0;
|
|
@@ -8724,7 +9222,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
8724
9222
|
try {
|
|
8725
9223
|
return await adapter.executeFusedPipelineOnLane(snapshot, route.laneId, snapshotOptions);
|
|
8726
9224
|
} catch (error) {
|
|
8727
|
-
if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt)) {
|
|
9225
|
+
if (await this.refreshAndCanRetrySafeReroute(error, rerouteAttempt, !containsCasMutation)) {
|
|
8728
9226
|
rerouteAttempt += 1;
|
|
8729
9227
|
continue;
|
|
8730
9228
|
}
|
|
@@ -8733,13 +9231,14 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
8733
9231
|
}
|
|
8734
9232
|
throw new StaleTopologyRouteError();
|
|
8735
9233
|
}
|
|
8736
|
-
async refreshAndCanRetrySafeReroute(error, attempt) {
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
9234
|
+
async refreshAndCanRetrySafeReroute(error, attempt, retryAllowed = true) {
|
|
9235
|
+
return await canRetrySafeReroute(
|
|
9236
|
+
error,
|
|
9237
|
+
attempt,
|
|
9238
|
+
retryAllowed,
|
|
9239
|
+
async () => await this.refreshTopology(),
|
|
9240
|
+
() => this.assertOpen()
|
|
8741
9241
|
);
|
|
8742
|
-
return refreshed && isExplicitlySafeReroute(error);
|
|
8743
9242
|
}
|
|
8744
9243
|
async executePipelineOnRoute(commands, route, options) {
|
|
8745
9244
|
const adapter = await this.adapterForCurrentRoute(route);
|
|
@@ -8829,7 +9328,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
8829
9328
|
};
|
|
8830
9329
|
|
|
8831
9330
|
// src/response-map-preservation.ts
|
|
8832
|
-
import { Buffer as
|
|
9331
|
+
import { Buffer as Buffer32 } from "buffer";
|
|
8833
9332
|
function toStringKeyMapPreservingValues(value) {
|
|
8834
9333
|
if (value == null) return void 0;
|
|
8835
9334
|
const result = {};
|
|
@@ -8839,7 +9338,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
8839
9338
|
}
|
|
8840
9339
|
return result;
|
|
8841
9340
|
}
|
|
8842
|
-
if (typeof value === "object" && !Array.isArray(value) && !
|
|
9341
|
+
if (typeof value === "object" && !Array.isArray(value) && !Buffer32.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
8843
9342
|
for (const [key, item] of Object.entries(value)) {
|
|
8844
9343
|
setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
|
|
8845
9344
|
}
|
|
@@ -8848,7 +9347,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
8848
9347
|
return void 0;
|
|
8849
9348
|
}
|
|
8850
9349
|
function normalizeMapStructurePreservingBytes(value) {
|
|
8851
|
-
if (
|
|
9350
|
+
if (Buffer32.isBuffer(value) || value instanceof Uint8Array) return value;
|
|
8852
9351
|
if (value instanceof Map) {
|
|
8853
9352
|
const result = {};
|
|
8854
9353
|
for (const [key, item] of value.entries()) {
|
|
@@ -8870,7 +9369,7 @@ function normalizeMapStructurePreservingBytes(value) {
|
|
|
8870
9369
|
}
|
|
8871
9370
|
|
|
8872
9371
|
// src/native-kv-responses.ts
|
|
8873
|
-
import { Buffer as
|
|
9372
|
+
import { Buffer as Buffer33 } from "buffer";
|
|
8874
9373
|
function rateLimitResultFromResp(value) {
|
|
8875
9374
|
if (!Array.isArray(value) || value.length !== 4) {
|
|
8876
9375
|
throw new TypeError("RATELIMIT.ADD returned an unexpected response");
|
|
@@ -8913,30 +9412,27 @@ function fetchOrComputeResultFromResp(value, codec) {
|
|
|
8913
9412
|
shouldCompute: false
|
|
8914
9413
|
};
|
|
8915
9414
|
}
|
|
8916
|
-
if (status !== "compute"
|
|
9415
|
+
if (status !== "compute" || value.length !== 3) {
|
|
9416
|
+
throw new TypeError("FETCH_OR_COMPUTE returned an unexpected response");
|
|
9417
|
+
}
|
|
8917
9418
|
return {
|
|
8918
9419
|
status,
|
|
8919
9420
|
computeHint: responseBytes(value[1], "FETCH_OR_COMPUTE"),
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
computeToken: responseBytes(value[2], "FETCH_OR_COMPUTE")
|
|
8923
|
-
} : {
|
|
8924
|
-
computeMode: "legacy",
|
|
8925
|
-
computeToken: null
|
|
8926
|
-
},
|
|
9421
|
+
computeMode: "fenced",
|
|
9422
|
+
computeToken: responseBytes(value[2], "FETCH_OR_COMPUTE"),
|
|
8927
9423
|
hit: false,
|
|
8928
9424
|
shouldCompute: true
|
|
8929
9425
|
};
|
|
8930
9426
|
}
|
|
8931
9427
|
function decodePayload(codec, value) {
|
|
8932
9428
|
if (value == null) return null;
|
|
8933
|
-
if (
|
|
8934
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
8935
|
-
if (typeof value === "string") return codec.decode(
|
|
9429
|
+
if (Buffer33.isBuffer(value)) return codec.decode(value);
|
|
9430
|
+
if (value instanceof Uint8Array) return codec.decode(Buffer33.from(value));
|
|
9431
|
+
if (typeof value === "string") return codec.decode(Buffer33.from(value));
|
|
8936
9432
|
return normalizeRefMeta(value);
|
|
8937
9433
|
}
|
|
8938
9434
|
function requiredResponseString(value, context) {
|
|
8939
|
-
if (typeof value !== "string" && !
|
|
9435
|
+
if (typeof value !== "string" && !Buffer33.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
8940
9436
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
8941
9437
|
}
|
|
8942
9438
|
const result = text(value);
|
|
@@ -8953,7 +9449,7 @@ function requiredNonNegativeInteger(value, context) {
|
|
|
8953
9449
|
return result;
|
|
8954
9450
|
}
|
|
8955
9451
|
function responseBytes(value, context) {
|
|
8956
|
-
if (typeof value !== "string" && !
|
|
9452
|
+
if (typeof value !== "string" && !Buffer33.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
8957
9453
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
8958
9454
|
}
|
|
8959
9455
|
return bytes(value);
|
|
@@ -9038,6 +9534,9 @@ function flowRecordFromResp(value, codec) {
|
|
|
9038
9534
|
field(value, "max_active_ms"),
|
|
9039
9535
|
"FLOW record max_active_ms"
|
|
9040
9536
|
);
|
|
9537
|
+
const rawError = field(value, "error");
|
|
9538
|
+
const error = flowError(rawError, codec);
|
|
9539
|
+
const failureReason = optionalResponseString(field(rawError, "reason"), "FLOW record error reason");
|
|
9041
9540
|
return {
|
|
9042
9541
|
id: requiredTextField(value, "id", "FLOW record"),
|
|
9043
9542
|
type: requiredTextField(value, "type", "FLOW record"),
|
|
@@ -9052,6 +9551,8 @@ function flowRecordFromResp(value, codec) {
|
|
|
9052
9551
|
rootFlowId: optionalResponseString(field(value, "root_flow_id"), "FLOW record root_flow_id"),
|
|
9053
9552
|
correlationId: optionalResponseString(field(value, "correlation_id"), "FLOW record correlation_id"),
|
|
9054
9553
|
...maxActiveMs == null ? {} : { maxActiveMs },
|
|
9554
|
+
...error == null ? {} : { error },
|
|
9555
|
+
...failureReason == null ? {} : { failureReason },
|
|
9055
9556
|
valueRefs: optionalMapField(value, "value_refs", "FLOW record"),
|
|
9056
9557
|
values,
|
|
9057
9558
|
valueSizes: optionalMapField(value, "value_sizes", "FLOW record"),
|
|
@@ -9063,6 +9564,21 @@ function flowRecordFromResp(value, codec) {
|
|
|
9063
9564
|
raw: value
|
|
9064
9565
|
};
|
|
9065
9566
|
}
|
|
9567
|
+
function flowError(value, codec) {
|
|
9568
|
+
if (value == null) return void 0;
|
|
9569
|
+
const reason = optionalResponseString(field(value, "reason"), "FLOW record error reason");
|
|
9570
|
+
if (reason === "max_active_ms") {
|
|
9571
|
+
const maxActiveMs = optionalPositiveResponseInteger(
|
|
9572
|
+
field(value, "max_active_ms"),
|
|
9573
|
+
"FLOW record error max_active_ms"
|
|
9574
|
+
);
|
|
9575
|
+
if (maxActiveMs == null) {
|
|
9576
|
+
throw new TypeError("FLOW record error max_active_ms returned an unexpected response");
|
|
9577
|
+
}
|
|
9578
|
+
return { maxActiveMs, reason };
|
|
9579
|
+
}
|
|
9580
|
+
return decodePayload2(codec, value);
|
|
9581
|
+
}
|
|
9066
9582
|
function decodePayload2(codec, value) {
|
|
9067
9583
|
if (value == null) {
|
|
9068
9584
|
return null;
|
|
@@ -9643,7 +10159,7 @@ function groupAutoPartitionItems(items) {
|
|
|
9643
10159
|
}
|
|
9644
10160
|
|
|
9645
10161
|
// src/client-values.ts
|
|
9646
|
-
import { Buffer as
|
|
10162
|
+
import { Buffer as Buffer34 } from "buffer";
|
|
9647
10163
|
async function valueMGetEntries(client, refs, options = {}) {
|
|
9648
10164
|
const refCount = refs.length;
|
|
9649
10165
|
if (refCount === 0) {
|
|
@@ -9678,12 +10194,12 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
9678
10194
|
const item = response[index];
|
|
9679
10195
|
if (item == null) {
|
|
9680
10196
|
entries[index] = { found: false };
|
|
9681
|
-
} else if (
|
|
10197
|
+
} else if (Buffer34.isBuffer(item)) {
|
|
9682
10198
|
entries[index] = { found: true, value: client.codec.decode(item) };
|
|
9683
10199
|
} else if (item instanceof Uint8Array) {
|
|
9684
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10200
|
+
entries[index] = { found: true, value: client.codec.decode(Buffer34.from(item)) };
|
|
9685
10201
|
} else if (typeof item === "string") {
|
|
9686
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10202
|
+
entries[index] = { found: true, value: client.codec.decode(Buffer34.from(item)) };
|
|
9687
10203
|
} else {
|
|
9688
10204
|
entries[index] = { found: true, value: item };
|
|
9689
10205
|
}
|
|
@@ -9695,7 +10211,7 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
9695
10211
|
import "buffer";
|
|
9696
10212
|
|
|
9697
10213
|
// src/auto-batch-ordering.ts
|
|
9698
|
-
import { Buffer as
|
|
10214
|
+
import { Buffer as Buffer35 } from "buffer";
|
|
9699
10215
|
function autoBatchOrderingPlan(batch) {
|
|
9700
10216
|
const accesses = /* @__PURE__ */ new Map();
|
|
9701
10217
|
const fallbackDependencies = [];
|
|
@@ -9810,13 +10326,13 @@ function flowManyAutoBatchIds(command, name) {
|
|
|
9810
10326
|
return fixedFlowItemIds(
|
|
9811
10327
|
command,
|
|
9812
10328
|
mixed ? 4 : 3,
|
|
9813
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) &&
|
|
10329
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && Buffer35.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
|
|
9814
10330
|
);
|
|
9815
10331
|
}
|
|
9816
10332
|
return fixedFlowItemIds(
|
|
9817
10333
|
command,
|
|
9818
10334
|
mixed ? 4 : 3,
|
|
9819
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
10335
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer35.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
|
|
9820
10336
|
);
|
|
9821
10337
|
}
|
|
9822
10338
|
function createManyAutoBatchIds(command) {
|
|
@@ -9829,7 +10345,7 @@ function createManyAutoBatchIds(command) {
|
|
|
9829
10345
|
const ids = fixedFlowItemIds(
|
|
9830
10346
|
command,
|
|
9831
10347
|
width,
|
|
9832
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
10348
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer35.isBuffer(command[itemIndex + width - 1]),
|
|
9833
10349
|
markerIndex
|
|
9834
10350
|
);
|
|
9835
10351
|
if (ids != null) return ids;
|
|
@@ -9847,7 +10363,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
|
|
|
9847
10363
|
let cursor = markerIndex + 2;
|
|
9848
10364
|
for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
|
|
9849
10365
|
const id = command[cursor];
|
|
9850
|
-
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !
|
|
10366
|
+
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer35.isBuffer(command[cursor + 2])) return void 0;
|
|
9851
10367
|
ids.push(id);
|
|
9852
10368
|
cursor += 3;
|
|
9853
10369
|
const afterValues = skipExtendedNamedItems(command, cursor, true);
|
|
@@ -9866,7 +10382,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
|
|
|
9866
10382
|
for (let index = 0; index < count; index += 1) {
|
|
9867
10383
|
const name = command[firstItem + index * 2];
|
|
9868
10384
|
const value = command[firstItem + index * 2 + 1];
|
|
9869
|
-
if (!isAutoBatchResourceValue(name) || (encodedValues ? !
|
|
10385
|
+
if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer35.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
|
|
9870
10386
|
}
|
|
9871
10387
|
return firstItem + count * 2;
|
|
9872
10388
|
}
|
|
@@ -9881,7 +10397,7 @@ function runStepsManyAutoBatchIds(command) {
|
|
|
9881
10397
|
ids.push(item);
|
|
9882
10398
|
continue;
|
|
9883
10399
|
}
|
|
9884
|
-
if (typeof item !== "object" || item == null || Array.isArray(item) ||
|
|
10400
|
+
if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer35.isBuffer(item)) return void 0;
|
|
9885
10401
|
const id = item.id;
|
|
9886
10402
|
if (!isAutoBatchResourceValue(id)) return void 0;
|
|
9887
10403
|
ids.push(id);
|
|
@@ -9922,7 +10438,7 @@ function flowValuePutOwner(command, start) {
|
|
|
9922
10438
|
}
|
|
9923
10439
|
var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
|
|
9924
10440
|
function isAutoBatchResourceValue(value) {
|
|
9925
|
-
return typeof value === "string" ||
|
|
10441
|
+
return typeof value === "string" || Buffer35.isBuffer(value);
|
|
9926
10442
|
}
|
|
9927
10443
|
function isFencingToken(value) {
|
|
9928
10444
|
return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
|
|
@@ -9931,7 +10447,7 @@ function nonNegativeItemCount(value) {
|
|
|
9931
10447
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
9932
10448
|
}
|
|
9933
10449
|
function autoBatchResourceKey(namespace, value) {
|
|
9934
|
-
return `${namespace}:${
|
|
10450
|
+
return `${namespace}:${Buffer35.from(value).toString("base64")}`;
|
|
9935
10451
|
}
|
|
9936
10452
|
function autoBatchCommandName(command) {
|
|
9937
10453
|
return commandView(command).name ?? null;
|
|
@@ -10346,9 +10862,9 @@ import "buffer";
|
|
|
10346
10862
|
import "buffer";
|
|
10347
10863
|
|
|
10348
10864
|
// src/client-core-helpers.ts
|
|
10349
|
-
import { Buffer as
|
|
10865
|
+
import { Buffer as Buffer37 } from "buffer";
|
|
10350
10866
|
function bgsaveResponse(response) {
|
|
10351
|
-
if ((typeof response === "string" ||
|
|
10867
|
+
if ((typeof response === "string" || Buffer37.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
|
|
10352
10868
|
return true;
|
|
10353
10869
|
}
|
|
10354
10870
|
return okResponse(response);
|
|
@@ -10359,11 +10875,11 @@ function clientNameResponse(response) {
|
|
|
10359
10875
|
function fetchOrComputeCompletionToken(options) {
|
|
10360
10876
|
if (options == null || !Object.hasOwn(options, "computeToken") || options.computeToken === void 0) {
|
|
10361
10877
|
throw new TypeError(
|
|
10362
|
-
"fetch-or-compute completion requires computeToken
|
|
10878
|
+
"fetch-or-compute completion requires computeToken"
|
|
10363
10879
|
);
|
|
10364
10880
|
}
|
|
10365
|
-
if (
|
|
10366
|
-
throw new TypeError("fetch-or-compute computeToken must be a Buffer
|
|
10881
|
+
if (!Buffer37.isBuffer(options.computeToken)) {
|
|
10882
|
+
throw new TypeError("fetch-or-compute computeToken must be a Buffer");
|
|
10367
10883
|
}
|
|
10368
10884
|
return options.computeToken;
|
|
10369
10885
|
}
|
|
@@ -10485,14 +11001,17 @@ var FerricStoreClientBase = class {
|
|
|
10485
11001
|
};
|
|
10486
11002
|
}
|
|
10487
11003
|
async command(...args) {
|
|
11004
|
+
assertAtomicKeyValueCommandSharesSlot(args);
|
|
10488
11005
|
return await executeCommandArgs(this.executor, args);
|
|
10489
11006
|
}
|
|
10490
11007
|
/** Execute an already-built command without a JavaScript variadic-call limit. */
|
|
10491
11008
|
async commandArgs(args) {
|
|
11009
|
+
assertAtomicKeyValueCommandSharesSlot(args);
|
|
10492
11010
|
return await executeCommandArgs(this.executor, args);
|
|
10493
11011
|
}
|
|
10494
11012
|
async pipeline(commands, options) {
|
|
10495
11013
|
const snapshot = snapshotPipelineCommands(commands);
|
|
11014
|
+
for (const command of snapshot) assertAtomicKeyValueCommandSharesSlot(command);
|
|
10496
11015
|
const snapshotOptions = snapshotPipelineOptions(options);
|
|
10497
11016
|
const results = this.executor.executePipeline != null ? await this.executor.executePipeline(snapshot, snapshotOptions) : await executeCommandArraysIndividually(
|
|
10498
11017
|
async (command) => await this.commandArgs(command),
|
|
@@ -10719,14 +11238,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
|
|
|
10719
11238
|
};
|
|
10720
11239
|
|
|
10721
11240
|
// src/store-utilities.ts
|
|
10722
|
-
import { Buffer as
|
|
11241
|
+
import { Buffer as Buffer40 } from "buffer";
|
|
10723
11242
|
function encode(codec, value) {
|
|
10724
11243
|
return codec.encode(value);
|
|
10725
11244
|
}
|
|
10726
11245
|
function decode(codec, value) {
|
|
10727
11246
|
if (value == null) return null;
|
|
10728
|
-
if (
|
|
10729
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
11247
|
+
if (Buffer40.isBuffer(value)) return codec.decode(value);
|
|
11248
|
+
if (value instanceof Uint8Array) return codec.decode(Buffer40.from(value));
|
|
10730
11249
|
return value;
|
|
10731
11250
|
}
|
|
10732
11251
|
function number(value) {
|
|
@@ -10787,7 +11306,7 @@ function requireNonEmpty(values, command, noun = "argument") {
|
|
|
10787
11306
|
if (values.length === 0) throw new TypeError(`${command} requires at least one ${noun}`);
|
|
10788
11307
|
return values;
|
|
10789
11308
|
}
|
|
10790
|
-
function
|
|
11309
|
+
function commandName4(args) {
|
|
10791
11310
|
return typeof args[0] === "string" ? args[0] : "command";
|
|
10792
11311
|
}
|
|
10793
11312
|
function commandArgs(client, args) {
|
|
@@ -10802,7 +11321,7 @@ function arrayOrRest(values) {
|
|
|
10802
11321
|
function appendXReadStreams(args, streams) {
|
|
10803
11322
|
const offset = args.length;
|
|
10804
11323
|
const streamCount = streams.length;
|
|
10805
|
-
requireNonEmpty(streams,
|
|
11324
|
+
requireNonEmpty(streams, commandName4(args), "stream");
|
|
10806
11325
|
args.length = offset + 1 + streamCount * 2;
|
|
10807
11326
|
args[offset] = "STREAMS";
|
|
10808
11327
|
for (let index = 0; index < streamCount; index += 1) {
|
|
@@ -10812,7 +11331,7 @@ function appendXReadStreams(args, streams) {
|
|
|
10812
11331
|
const stream = streams[index];
|
|
10813
11332
|
if (stream == null) throw new TypeError("XREAD streams must contain only stream descriptors");
|
|
10814
11333
|
if (!Object.hasOwn(stream, "key") || !Object.hasOwn(stream, "id")) {
|
|
10815
|
-
throw new TypeError(`${
|
|
11334
|
+
throw new TypeError(`${commandName4(args)} streams require own key and id fields`);
|
|
10816
11335
|
}
|
|
10817
11336
|
args[offset + 1 + index] = stream.key;
|
|
10818
11337
|
args[offset + 1 + streamCount + index] = stream.id;
|
|
@@ -10834,7 +11353,7 @@ function concatArgs(...parts) {
|
|
|
10834
11353
|
return args;
|
|
10835
11354
|
}
|
|
10836
11355
|
function encodedArgs(prefix, codec, values, allowEmpty = false) {
|
|
10837
|
-
if (!allowEmpty) requireNonEmpty(values,
|
|
11356
|
+
if (!allowEmpty) requireNonEmpty(values, commandName4(prefix));
|
|
10838
11357
|
const args = new Array(prefix.length + values.length);
|
|
10839
11358
|
for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
|
|
10840
11359
|
for (let index = 0; index < values.length; index += 1) {
|
|
@@ -10848,7 +11367,7 @@ function encodedArgs(prefix, codec, values, allowEmpty = false) {
|
|
|
10848
11367
|
function keyValueArgs(prefix, codec, entries) {
|
|
10849
11368
|
const validateTuples = Array.isArray(entries);
|
|
10850
11369
|
const pairs = validateTuples ? entries : Object.entries(entries);
|
|
10851
|
-
requireNonEmpty(pairs,
|
|
11370
|
+
requireNonEmpty(pairs, commandName4(prefix), "entry");
|
|
10852
11371
|
const args = new Array(prefix.length + pairs.length * 2);
|
|
10853
11372
|
for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
|
|
10854
11373
|
for (let index = 0; index < pairs.length; index += 1) {
|
|
@@ -10862,7 +11381,7 @@ function keyValueArgs(prefix, codec, entries) {
|
|
|
10862
11381
|
return args;
|
|
10863
11382
|
}
|
|
10864
11383
|
function encodedEntryArgs(prefix, codec, entries) {
|
|
10865
|
-
requireNonEmpty(entries,
|
|
11384
|
+
requireNonEmpty(entries, commandName4(prefix), "entry");
|
|
10866
11385
|
const args = new Array(prefix.length + entries.length * 2);
|
|
10867
11386
|
for (let index = 0; index < prefix.length; index += 1) args[index] = prefix[index];
|
|
10868
11387
|
for (let index = 0; index < entries.length; index += 1) {
|
|
@@ -11132,12 +11651,15 @@ var TopKStore = class {
|
|
|
11132
11651
|
const width = ownOption(options, "width");
|
|
11133
11652
|
const depth = ownOption(options, "depth");
|
|
11134
11653
|
const decay = ownOption(options, "decay");
|
|
11135
|
-
|
|
11136
|
-
|
|
11137
|
-
throw new TypeError("TOPK.RESERVE width, depth, and decay must be provided together");
|
|
11654
|
+
if (decay != null || Object.hasOwn(options, "decay")) {
|
|
11655
|
+
throw new TypeError("TOPK.RESERVE decay is not supported by FerricStore 0.8");
|
|
11138
11656
|
}
|
|
11139
|
-
|
|
11140
|
-
|
|
11657
|
+
const tuningCount = [width, depth].filter((value) => value != null).length;
|
|
11658
|
+
if (tuningCount !== 0 && tuningCount !== 2) {
|
|
11659
|
+
throw new TypeError("TOPK.RESERVE width and depth must be provided together");
|
|
11660
|
+
}
|
|
11661
|
+
if (tuningCount === 2) {
|
|
11662
|
+
args.push(width, depth);
|
|
11141
11663
|
}
|
|
11142
11664
|
return okResponse(await commandArgs(this.client, args));
|
|
11143
11665
|
}
|
|
@@ -11543,10 +12065,14 @@ var KeyValueStore = class {
|
|
|
11543
12065
|
);
|
|
11544
12066
|
}
|
|
11545
12067
|
async mset(entries) {
|
|
11546
|
-
|
|
12068
|
+
const args = keyValueArgs(["MSET"], this.client.codec, entries);
|
|
12069
|
+
assertKeyValueCommandSharesSlot(args, "MSET");
|
|
12070
|
+
return okResponse(await commandArgs(this.client, args));
|
|
11547
12071
|
}
|
|
11548
12072
|
async msetnx(entries) {
|
|
11549
|
-
|
|
12073
|
+
const args = keyValueArgs(["MSETNX"], this.client.codec, entries);
|
|
12074
|
+
assertKeyValueCommandSharesSlot(args, "MSETNX");
|
|
12075
|
+
return binaryBooleanResponse(await commandArgs(this.client, args));
|
|
11550
12076
|
}
|
|
11551
12077
|
async incr(key) {
|
|
11552
12078
|
return integerReply(await this.client.command("INCR", key));
|
|
@@ -12616,7 +13142,8 @@ var FerricStoreClientCore = class extends FerricStoreAdministrationClient {
|
|
|
12616
13142
|
return okResponse(await this.command(
|
|
12617
13143
|
"FETCH_OR_COMPUTE_RESULT",
|
|
12618
13144
|
key,
|
|
12619
|
-
|
|
13145
|
+
computeToken,
|
|
13146
|
+
encoded,
|
|
12620
13147
|
options.ttlMs
|
|
12621
13148
|
));
|
|
12622
13149
|
}
|
|
@@ -12625,7 +13152,7 @@ var FerricStoreClientCore = class extends FerricStoreAdministrationClient {
|
|
|
12625
13152
|
return okResponse(await this.command(
|
|
12626
13153
|
"FETCH_OR_COMPUTE_ERROR",
|
|
12627
13154
|
key,
|
|
12628
|
-
|
|
13155
|
+
computeToken,
|
|
12629
13156
|
message
|
|
12630
13157
|
));
|
|
12631
13158
|
}
|
|
@@ -12751,7 +13278,7 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
|
|
|
12751
13278
|
}
|
|
12752
13279
|
async effectGet(id, effectKey, options = {}) {
|
|
12753
13280
|
const args = ["FLOW.EFFECT.GET", id, "EFFECT_KEY", effectKey];
|
|
12754
|
-
append(args, "PARTITION", options.partitionKey
|
|
13281
|
+
append(args, "PARTITION", options.partitionKey);
|
|
12755
13282
|
return optionalAdminRecord(await this.commandArgs(args), "FLOW.EFFECT.GET");
|
|
12756
13283
|
}
|
|
12757
13284
|
async effectStatus(command, id, effectKey, options) {
|
|
@@ -12923,7 +13450,7 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
|
|
|
12923
13450
|
}
|
|
12924
13451
|
async governanceLedger(id, options = {}) {
|
|
12925
13452
|
const args = ["FLOW.GOVERNANCE.LEDGER", id];
|
|
12926
|
-
append(args, "PARTITION", options.partitionKey
|
|
13453
|
+
append(args, "PARTITION", options.partitionKey);
|
|
12927
13454
|
append(args, "LIMIT", options.limit);
|
|
12928
13455
|
append(args, "FROM_MS", options.fromMs);
|
|
12929
13456
|
append(args, "TO_MS", options.toMs);
|
|
@@ -12939,7 +13466,7 @@ async function executeProducerWriteWithBackpressure(execute, policy, signal) {
|
|
|
12939
13466
|
try {
|
|
12940
13467
|
return await execute();
|
|
12941
13468
|
} catch (error) {
|
|
12942
|
-
if (!(error instanceof OverloadedError) || attempt >= policy.maxRetries) throw error;
|
|
13469
|
+
if (!(error instanceof OverloadedError) || error.retryable !== true || error.safeToRetry !== true || attempt >= policy.maxRetries) throw error;
|
|
12943
13470
|
const exponential = Math.min(policy.maxDelayMs, policy.baseDelayMs * 2 ** attempt);
|
|
12944
13471
|
const base = Math.min(policy.maxDelayMs, error.retryAfterMs ?? exponential);
|
|
12945
13472
|
const jitter = base * (policy.jitterPct / 100) * Math.random();
|
|
@@ -12953,6 +13480,165 @@ function throwIfClosed(signal) {
|
|
|
12953
13480
|
throw new FerricStoreError("FerricStore client is closed", { raw: signal.reason });
|
|
12954
13481
|
}
|
|
12955
13482
|
|
|
13483
|
+
// src/flow-policy.ts
|
|
13484
|
+
import { Buffer as Buffer42 } from "buffer";
|
|
13485
|
+
var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
|
|
13486
|
+
function assertFlowPolicyGeneration(value) {
|
|
13487
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
13488
|
+
throw new TypeError("expectedGeneration must be a nonnegative safe integer");
|
|
13489
|
+
}
|
|
13490
|
+
}
|
|
13491
|
+
function flowPolicySnapshotFromResp(value) {
|
|
13492
|
+
const policy = requiredRecord(value, "FLOW policy snapshot");
|
|
13493
|
+
const maxActiveMs = optionalPositiveInteger(field(policy, "max_active_ms"), "max_active_ms");
|
|
13494
|
+
const state = optionalText2(field(policy, "state"), "state");
|
|
13495
|
+
const mode = optionalMode(field(policy, "mode"), "mode");
|
|
13496
|
+
const version = optionalVersion(field(policy, "version"));
|
|
13497
|
+
const indexedStateMeta = optionalText2(field(policy, "indexed_state_meta"), "indexed_state_meta");
|
|
13498
|
+
const governance = optionalRecord(field(policy, "governance"), "governance");
|
|
13499
|
+
const states = optionalStates(field(policy, "states"));
|
|
13500
|
+
return {
|
|
13501
|
+
type: requiredText(field(policy, "type"), "type"),
|
|
13502
|
+
generation: nonNegativeInteger(field(policy, "generation"), "generation"),
|
|
13503
|
+
...state == null ? {} : { state },
|
|
13504
|
+
...version == null ? {} : { version },
|
|
13505
|
+
...mode == null ? {} : { mode },
|
|
13506
|
+
...maxActiveMs == null ? {} : { maxActiveMs },
|
|
13507
|
+
retry: retrySnapshot(field(policy, "retry"), "retry"),
|
|
13508
|
+
retention: retentionSnapshot(field(policy, "retention"), "retention"),
|
|
13509
|
+
indexedAttributes: stringArray(field(policy, "indexed_attributes"), "indexed_attributes"),
|
|
13510
|
+
...indexedStateMeta == null ? {} : { indexedStateMeta },
|
|
13511
|
+
...governance == null ? {} : { governance },
|
|
13512
|
+
...states == null ? {} : { states },
|
|
13513
|
+
raw: value
|
|
13514
|
+
};
|
|
13515
|
+
}
|
|
13516
|
+
function retrySnapshot(value, context) {
|
|
13517
|
+
const retry2 = requiredRecord(value, `FLOW policy ${context}`);
|
|
13518
|
+
const backoff = requiredRecord(field(retry2, "backoff"), `FLOW policy ${context}.backoff`);
|
|
13519
|
+
return {
|
|
13520
|
+
maxRetries: nonNegativeInteger(field(retry2, "max_retries"), `${context}.max_retries`),
|
|
13521
|
+
backoff: {
|
|
13522
|
+
kind: backoffKind(field(backoff, "kind"), `${context}.backoff.kind`),
|
|
13523
|
+
baseMs: nonNegativeInteger(field(backoff, "base_ms"), `${context}.backoff.base_ms`),
|
|
13524
|
+
maxMs: nonNegativeInteger(field(backoff, "max_ms"), `${context}.backoff.max_ms`),
|
|
13525
|
+
jitterPct: nonNegativeInteger(field(backoff, "jitter_pct"), `${context}.backoff.jitter_pct`)
|
|
13526
|
+
},
|
|
13527
|
+
exhaustedTo: requiredText(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
|
|
13528
|
+
};
|
|
13529
|
+
}
|
|
13530
|
+
function retentionSnapshot(value, context) {
|
|
13531
|
+
const retention = requiredRecord(value, `FLOW policy ${context}`);
|
|
13532
|
+
return {
|
|
13533
|
+
ttlMs: nonNegativeInteger(field(retention, "ttl_ms"), `${context}.ttl_ms`),
|
|
13534
|
+
historyMaxEvents: nonNegativeInteger(
|
|
13535
|
+
field(retention, "history_max_events"),
|
|
13536
|
+
`${context}.history_max_events`
|
|
13537
|
+
)
|
|
13538
|
+
};
|
|
13539
|
+
}
|
|
13540
|
+
function optionalStates(value) {
|
|
13541
|
+
if (value == null) return void 0;
|
|
13542
|
+
const source = requiredRecord(value, "FLOW policy states");
|
|
13543
|
+
const result = {};
|
|
13544
|
+
for (const [state, raw] of Object.entries(source)) {
|
|
13545
|
+
const policy = requiredRecord(raw, `FLOW policy state ${state}`);
|
|
13546
|
+
const maxActiveMs = optionalPositiveInteger(
|
|
13547
|
+
field(policy, "max_active_ms"),
|
|
13548
|
+
`states.${state}.max_active_ms`
|
|
13549
|
+
);
|
|
13550
|
+
const governance = optionalRecord(field(policy, "governance"), `states.${state}.governance`);
|
|
13551
|
+
Object.defineProperty(result, state, {
|
|
13552
|
+
configurable: true,
|
|
13553
|
+
enumerable: true,
|
|
13554
|
+
value: {
|
|
13555
|
+
mode: requiredMode(field(policy, "mode"), `states.${state}.mode`),
|
|
13556
|
+
...maxActiveMs == null ? {} : { maxActiveMs },
|
|
13557
|
+
retry: retrySnapshot(field(policy, "retry"), `states.${state}.retry`),
|
|
13558
|
+
retention: retentionSnapshot(field(policy, "retention"), `states.${state}.retention`),
|
|
13559
|
+
...governance == null ? {} : { governance }
|
|
13560
|
+
},
|
|
13561
|
+
writable: true
|
|
13562
|
+
});
|
|
13563
|
+
}
|
|
13564
|
+
return result;
|
|
13565
|
+
}
|
|
13566
|
+
function requiredRecord(value, context) {
|
|
13567
|
+
if (value instanceof Map) {
|
|
13568
|
+
const result = {};
|
|
13569
|
+
for (const [key, item] of value.entries()) {
|
|
13570
|
+
setOwnValue(result, requiredText(key, `${context} key`), item);
|
|
13571
|
+
}
|
|
13572
|
+
return result;
|
|
13573
|
+
}
|
|
13574
|
+
if (typeof value === "object" && value != null && !Array.isArray(value) && !Buffer42.isBuffer(value) && !(value instanceof Uint8Array)) return value;
|
|
13575
|
+
throw new TypeError(`${context} returned an unexpected response`);
|
|
13576
|
+
}
|
|
13577
|
+
function optionalRecord(value, context) {
|
|
13578
|
+
return value == null ? void 0 : requiredRecord(value, `FLOW policy ${context}`);
|
|
13579
|
+
}
|
|
13580
|
+
function stringArray(value, context) {
|
|
13581
|
+
if (!Array.isArray(value)) {
|
|
13582
|
+
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13583
|
+
}
|
|
13584
|
+
const result = new Array(value.length);
|
|
13585
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13586
|
+
if (!Object.hasOwn(value, index)) {
|
|
13587
|
+
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13588
|
+
}
|
|
13589
|
+
result[index] = requiredText(value[index], `${context}[${index}]`);
|
|
13590
|
+
}
|
|
13591
|
+
return result;
|
|
13592
|
+
}
|
|
13593
|
+
function requiredText(value, context) {
|
|
13594
|
+
if (typeof value === "string") return value;
|
|
13595
|
+
if (Buffer42.isBuffer(value) || value instanceof Uint8Array) {
|
|
13596
|
+
return Buffer42.from(value).toString("utf8");
|
|
13597
|
+
}
|
|
13598
|
+
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13599
|
+
}
|
|
13600
|
+
function optionalText2(value, context) {
|
|
13601
|
+
return value == null ? void 0 : requiredText(value, context);
|
|
13602
|
+
}
|
|
13603
|
+
function nonNegativeInteger(value, context) {
|
|
13604
|
+
let parsed;
|
|
13605
|
+
try {
|
|
13606
|
+
parsed = integer(value);
|
|
13607
|
+
} catch {
|
|
13608
|
+
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13609
|
+
}
|
|
13610
|
+
if (parsed < 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13611
|
+
return parsed;
|
|
13612
|
+
}
|
|
13613
|
+
function optionalPositiveInteger(value, context) {
|
|
13614
|
+
if (value == null) return void 0;
|
|
13615
|
+
const parsed = nonNegativeInteger(value, context);
|
|
13616
|
+
if (parsed === 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13617
|
+
return parsed;
|
|
13618
|
+
}
|
|
13619
|
+
function optionalVersion(value) {
|
|
13620
|
+
if (value == null) return void 0;
|
|
13621
|
+
if (typeof value === "number" || typeof value === "bigint") {
|
|
13622
|
+
return nonNegativeInteger(value, "version");
|
|
13623
|
+
}
|
|
13624
|
+
return requiredText(value, "version");
|
|
13625
|
+
}
|
|
13626
|
+
function backoffKind(value, context) {
|
|
13627
|
+
const kind = requiredText(value, context).toLowerCase();
|
|
13628
|
+
if (kind === "none" || kind === "fixed" || kind === "linear" || kind === "exponential") {
|
|
13629
|
+
return kind;
|
|
13630
|
+
}
|
|
13631
|
+
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13632
|
+
}
|
|
13633
|
+
function requiredMode(value, context) {
|
|
13634
|
+
const mode = requiredText(value, context).toLowerCase();
|
|
13635
|
+
if (mode === "fifo" || mode === "parallel") return mode;
|
|
13636
|
+
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
13637
|
+
}
|
|
13638
|
+
function optionalMode(value, context) {
|
|
13639
|
+
return value == null ? void 0 : requiredMode(value, context);
|
|
13640
|
+
}
|
|
13641
|
+
|
|
12956
13642
|
// src/client-flow-support.ts
|
|
12957
13643
|
var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
|
|
12958
13644
|
async rewind(id, options = {}) {
|
|
@@ -13095,27 +13781,36 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
|
|
|
13095
13781
|
}
|
|
13096
13782
|
async installPolicy(type, options = {}) {
|
|
13097
13783
|
const args = ["FLOW.POLICY.SET", type];
|
|
13784
|
+
const expectedGeneration = Object.hasOwn(options, "expectedGeneration") ? options.expectedGeneration : void 0;
|
|
13785
|
+
const replace = Object.hasOwn(options, "replace") ? options.replace : void 0;
|
|
13786
|
+
if (expectedGeneration != null) assertFlowPolicyGeneration(expectedGeneration);
|
|
13787
|
+
if (replace != null && typeof replace !== "boolean") {
|
|
13788
|
+
throw new TypeError("replace must be a boolean");
|
|
13789
|
+
}
|
|
13790
|
+
append(args, "EXPECTED_GENERATION", expectedGeneration);
|
|
13791
|
+
appendBool(args, "REPLACE", replace);
|
|
13098
13792
|
if (options.indexedAttributes != null) {
|
|
13099
13793
|
args.push("INDEXED_ATTRIBUTES", JSON.stringify(options.indexedAttributes));
|
|
13100
13794
|
}
|
|
13101
13795
|
append(args, "INDEXED_STATE_META", options.indexedStateMeta);
|
|
13102
13796
|
append(args, "MAX_ACTIVE_MS", options.maxActiveMs);
|
|
13797
|
+
if (options.state == null) append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
|
|
13103
13798
|
append(args, "STATE", options.state);
|
|
13104
13799
|
appendPolicyMode(args, options.state, options.mode);
|
|
13105
13800
|
if (options.retry != null) {
|
|
13106
13801
|
appendRetryPolicy(args, options.retry);
|
|
13107
13802
|
}
|
|
13803
|
+
if (options.state != null) append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
|
|
13108
13804
|
for (const [state, policy] of Object.entries(options.states ?? {})) {
|
|
13109
13805
|
args.push("STATE", state);
|
|
13110
13806
|
appendFlowStatePolicy(args, policy);
|
|
13111
13807
|
}
|
|
13112
|
-
|
|
13113
|
-
return await this.commandArgs(args);
|
|
13808
|
+
return flowPolicySnapshotFromResp(await this.commandArgs(args));
|
|
13114
13809
|
}
|
|
13115
13810
|
async policyGet(type, options = {}) {
|
|
13116
13811
|
const args = ["FLOW.POLICY.GET", type];
|
|
13117
13812
|
append(args, "STATE", options.state);
|
|
13118
|
-
return
|
|
13813
|
+
return flowPolicySnapshotFromResp(await this.commandArgs(args));
|
|
13119
13814
|
}
|
|
13120
13815
|
async retentionCleanup() {
|
|
13121
13816
|
return parseKvResponse(await this.command("FLOW.RETENTION_CLEANUP"));
|
|
@@ -13204,7 +13899,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreManagementClient {
|
|
|
13204
13899
|
};
|
|
13205
13900
|
|
|
13206
13901
|
// src/flow-many-snapshot.ts
|
|
13207
|
-
import { Buffer as
|
|
13902
|
+
import { Buffer as Buffer44 } from "buffer";
|
|
13208
13903
|
var encodedOptionFields = ["error", "payload", "reason", "result"];
|
|
13209
13904
|
function snapshotCreateItem(item, codec) {
|
|
13210
13905
|
const snapshot = {
|
|
@@ -13244,7 +13939,7 @@ function snapshotFlowManyOptions(options, codec) {
|
|
|
13244
13939
|
}
|
|
13245
13940
|
function snapshotClaimedItem(item) {
|
|
13246
13941
|
const wire = item[CLAIMED_ITEM_WIRE];
|
|
13247
|
-
const leaseToken =
|
|
13942
|
+
const leaseToken = Buffer44.from(wire?.leaseToken ?? item.leaseToken);
|
|
13248
13943
|
const snapshot = {
|
|
13249
13944
|
...item,
|
|
13250
13945
|
fencingToken: wire?.fencingToken ?? item.fencingToken,
|
|
@@ -13261,15 +13956,15 @@ function snapshotClaimedItem(item) {
|
|
|
13261
13956
|
function snapshotFencedItem(item) {
|
|
13262
13957
|
return Object.freeze({
|
|
13263
13958
|
...item,
|
|
13264
|
-
...item.leaseToken == null ? {} : { leaseToken:
|
|
13959
|
+
...item.leaseToken == null ? {} : { leaseToken: Buffer44.from(item.leaseToken) }
|
|
13265
13960
|
});
|
|
13266
13961
|
}
|
|
13267
13962
|
function snapshotClaimedItemWire(wire, leaseToken) {
|
|
13268
13963
|
return Object.freeze({
|
|
13269
13964
|
fencingToken: wire.fencingToken,
|
|
13270
|
-
id:
|
|
13965
|
+
id: Buffer44.from(wire.id),
|
|
13271
13966
|
leaseToken,
|
|
13272
|
-
partitionKey: wire.partitionKey == null ? wire.partitionKey :
|
|
13967
|
+
partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer44.from(wire.partitionKey)
|
|
13273
13968
|
});
|
|
13274
13969
|
}
|
|
13275
13970
|
function snapshotArray(values) {
|
|
@@ -13280,7 +13975,7 @@ function snapshotArray(values) {
|
|
|
13280
13975
|
return Object.freeze(snapshot);
|
|
13281
13976
|
}
|
|
13282
13977
|
function snapshotStateMeta(stateMeta) {
|
|
13283
|
-
return snapshotRecord(stateMeta, (value) =>
|
|
13978
|
+
return snapshotRecord(stateMeta, (value) => Buffer44.isBuffer(value) ? Buffer44.from(value) : value);
|
|
13284
13979
|
}
|
|
13285
13980
|
function snapshotCommandRecord(values) {
|
|
13286
13981
|
const seen = /* @__PURE__ */ new WeakMap();
|
|
@@ -13298,7 +13993,7 @@ function snapshotRecord(values, capture) {
|
|
|
13298
13993
|
}
|
|
13299
13994
|
function snapshotCommandArgument(value, seen) {
|
|
13300
13995
|
if (typeof value !== "object" || value == null) return value;
|
|
13301
|
-
if (
|
|
13996
|
+
if (Buffer44.isBuffer(value) || value instanceof Uint8Array) return Buffer44.from(value);
|
|
13302
13997
|
const objectValue = value;
|
|
13303
13998
|
const existing = seen.get(objectValue);
|
|
13304
13999
|
if (existing != null) return existing;
|
|
@@ -14096,6 +14791,9 @@ var FerricStoreClient = class _FerricStoreClient extends FerricStoreProducerClie
|
|
|
14096
14791
|
return new _FerricStoreClient(executor, clientOptions);
|
|
14097
14792
|
}
|
|
14098
14793
|
async valuePut(value, options = {}) {
|
|
14794
|
+
if (options.ownerFlowId != null && options.name != null && options.ttlMs != null) {
|
|
14795
|
+
throw new TypeError("named Flow values cannot have a TTL");
|
|
14796
|
+
}
|
|
14099
14797
|
const args = ["FLOW.VALUE.PUT", this.codec.encode(value), "NOW", options.nowMs ?? nowMs()];
|
|
14100
14798
|
append(args, "PARTITION", options.partitionKey);
|
|
14101
14799
|
append(args, "OWNER_FLOW_ID", options.ownerFlowId);
|
|
@@ -14127,7 +14825,6 @@ var FerricStoreClient = class _FerricStoreClient extends FerricStoreProducerClie
|
|
|
14127
14825
|
append(args, "TRANSITION_TO", options.transitionTo);
|
|
14128
14826
|
append(args, "RUN_AT", options.runAtMs);
|
|
14129
14827
|
append(args, "NOW", options.nowMs ?? nowMs());
|
|
14130
|
-
append(args, "PRIORITY", options.priority);
|
|
14131
14828
|
appendNamedValues(args, this.codec, options);
|
|
14132
14829
|
return await this.commandArgs(args);
|
|
14133
14830
|
}
|
|
@@ -14157,6 +14854,7 @@ var FerricStoreClient = class _FerricStoreClient extends FerricStoreProducerClie
|
|
|
14157
14854
|
append(args, "CORRELATION_ID", options.correlationId);
|
|
14158
14855
|
append(args, "PRIORITY", options.priority);
|
|
14159
14856
|
append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
|
|
14857
|
+
append(args, "MAX_ACTIVE_MS", options.maxActiveMs);
|
|
14160
14858
|
appendAttributes(args, options.attributes);
|
|
14161
14859
|
appendStateMeta(args, options.stateMeta);
|
|
14162
14860
|
appendNamedValues(args, this.codec, options);
|
|
@@ -14517,7 +15215,7 @@ async function runContinuousWorkerPool(options) {
|
|
|
14517
15215
|
initialIdleSleepMs,
|
|
14518
15216
|
nonNegativeDuration(options.maxIdleSleepMs, 5e3)
|
|
14519
15217
|
);
|
|
14520
|
-
const refillDelayMs =
|
|
15218
|
+
const refillDelayMs = nonNegativeInteger2(options.refillDelayMs, 0);
|
|
14521
15219
|
const active = /* @__PURE__ */ new Set();
|
|
14522
15220
|
const pending = [];
|
|
14523
15221
|
let pendingIndex = 0;
|
|
@@ -14636,7 +15334,7 @@ function normalizeWorkflowWorkerConfig(options) {
|
|
|
14636
15334
|
function positiveInteger(value, fallback) {
|
|
14637
15335
|
return value == null || !Number.isFinite(value) ? fallback : Math.max(1, Math.trunc(value));
|
|
14638
15336
|
}
|
|
14639
|
-
function
|
|
15337
|
+
function nonNegativeInteger2(value, fallback) {
|
|
14640
15338
|
return value == null || !Number.isFinite(value) ? fallback : Math.max(0, Math.trunc(value));
|
|
14641
15339
|
}
|
|
14642
15340
|
function nonNegativeDuration(value, fallback) {
|
|
@@ -16052,6 +16750,7 @@ var Workflow = class {
|
|
|
16052
16750
|
}
|
|
16053
16751
|
return await this.client.installPolicy(this.type, {
|
|
16054
16752
|
...options,
|
|
16753
|
+
replace: Object.hasOwn(options, "replace") ? options.replace ?? true : true,
|
|
16055
16754
|
states
|
|
16056
16755
|
});
|
|
16057
16756
|
}
|
|
@@ -16262,15 +16961,22 @@ var WorkflowWorker = class {
|
|
|
16262
16961
|
);
|
|
16263
16962
|
}
|
|
16264
16963
|
};
|
|
16964
|
+
|
|
16965
|
+
// src/version.ts
|
|
16966
|
+
var FERRICSTORE_SDK_VERSION = "0.3.0";
|
|
16967
|
+
var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.9.1";
|
|
16968
|
+
var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
|
|
16265
16969
|
export {
|
|
16266
16970
|
BitmapStore,
|
|
16267
16971
|
BloomFilterStore,
|
|
16268
16972
|
COMMAND_OPCODES,
|
|
16269
|
-
COMPACT_RESPONSE_OPCODES,
|
|
16270
16973
|
ClaimHydrationError,
|
|
16271
16974
|
ConnectionClosedError,
|
|
16272
16975
|
CountMinSketchStore,
|
|
16273
16976
|
CuckooFilterStore,
|
|
16977
|
+
FERRICSTORE_MINIMUM_SERVER_VERSION,
|
|
16978
|
+
FERRICSTORE_NATIVE_PROTOCOL_VERSION,
|
|
16979
|
+
FERRICSTORE_SDK_VERSION,
|
|
16274
16980
|
FerricStoreClient,
|
|
16275
16981
|
FerricStoreError,
|
|
16276
16982
|
FlowAlreadyExistsError,
|
|
@@ -16287,6 +16993,7 @@ export {
|
|
|
16287
16993
|
ListStore,
|
|
16288
16994
|
LockHeldError,
|
|
16289
16995
|
LockNotOwnedError,
|
|
16996
|
+
MAX_FLOW_POLICY_GENERATION,
|
|
16290
16997
|
NativeAdapter,
|
|
16291
16998
|
OverloadedError,
|
|
16292
16999
|
Queue,
|
|
@@ -16301,6 +17008,7 @@ export {
|
|
|
16301
17008
|
SetStore,
|
|
16302
17009
|
SortedSetStore,
|
|
16303
17010
|
StaleLeaseError,
|
|
17011
|
+
StalePolicyGenerationError,
|
|
16304
17012
|
StreamStore,
|
|
16305
17013
|
TDigestStore,
|
|
16306
17014
|
TopKStore,
|