@ferricstore/ferricstore 0.5.1 → 0.11.4
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 +44 -5
- package/dist/index.cjs +2162 -518
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +183 -34
- package/dist/index.d.ts +183 -34
- package/dist/index.js +2134 -490
- 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/ConnectionClosedError.html +1 -1
- package/docs/api/classes/FerricStoreClient.html +3 -3
- package/docs/api/classes/FerricStoreError.html +1 -1
- package/docs/api/classes/FlowAlreadyExistsError.html +1 -1
- package/docs/api/classes/FlowBatchError.html +1 -1
- package/docs/api/classes/FlowNotFoundError.html +1 -1
- package/docs/api/classes/FlowQueryError.html +1 -1
- package/docs/api/classes/FlowWrongStateError.html +1 -1
- package/docs/api/classes/InvalidCommandError.html +1 -1
- package/docs/api/classes/LeaseRenewalError.html +1 -1
- package/docs/api/classes/LockHeldError.html +1 -1
- package/docs/api/classes/LockNotOwnedError.html +1 -1
- package/docs/api/classes/NativeAdapter.html +1 -1
- package/docs/api/classes/OverloadedError.html +1 -1
- package/docs/api/classes/QueueCompletionError.html +1 -1
- package/docs/api/classes/RequestTimeoutError.html +1 -1
- package/docs/api/classes/RerouteError.html +1 -1
- package/docs/api/classes/StaleLeaseError.html +1 -1
- package/docs/api/classes/StalePolicyGenerationError.html +1 -1
- package/docs/api/functions/projectFlowQuery.html +1 -1
- package/docs/api/hierarchy.html +1 -1
- package/docs/api/index.html +34 -5
- package/docs/api/interfaces/AdminListOptions.html +2 -2
- package/docs/api/interfaces/ApprovalListOptions.html +2 -2
- package/docs/api/interfaces/ApprovalRequestOptions.html +2 -2
- package/docs/api/interfaces/AttributeQueryOptions.html +2 -2
- package/docs/api/interfaces/AutoBatchOptions.html +2 -2
- package/docs/api/interfaces/BudgetCommitOptions.html +2 -2
- package/docs/api/interfaces/BudgetReserveOptions.html +2 -2
- package/docs/api/interfaces/CancelOptions.html +2 -2
- package/docs/api/interfaces/CircuitOpenOptions.html +2 -2
- package/docs/api/interfaces/ClaimDueOptions.html +3 -3
- package/docs/api/interfaces/ClaimHydrationItem.html +2 -2
- 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 +5 -5
- package/docs/api/interfaces/CreateOptions.html +3 -3
- package/docs/api/interfaces/EffectCompensateOptions.html +2 -2
- package/docs/api/interfaces/EffectConfirmOptions.html +2 -2
- package/docs/api/interfaces/EffectFailOptions.html +2 -2
- package/docs/api/interfaces/EffectReserveOptions.html +2 -2
- package/docs/api/interfaces/EffectStatusOptions.html +2 -2
- 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 +4 -4
- package/docs/api/interfaces/FerricStoreClientOptions.html +4 -4
- package/docs/api/interfaces/FlowBatchCompletedItem.html +2 -2
- package/docs/api/interfaces/FlowEventProjectionField.html +2 -2
- package/docs/api/interfaces/FlowExplainCapabilities.html +5 -0
- package/docs/api/interfaces/FlowExplainResult.html +8 -2
- package/docs/api/interfaces/FlowPolicyOptions.html +5 -5
- package/docs/api/interfaces/FlowQueryCountResult.html +1 -1
- package/docs/api/interfaces/FlowQueryIndex.html +11 -2
- package/docs/api/interfaces/FlowQueryIndexBuild.html +10 -0
- package/docs/api/interfaces/FlowQueryIndexCoverage.html +5 -0
- package/docs/api/interfaces/FlowQueryIndexField.html +5 -0
- package/docs/api/interfaces/FlowQueryIndexFormat.html +2 -2
- package/docs/api/interfaces/FlowQueryIndexProgress.html +7 -0
- package/docs/api/interfaces/FlowQueryIndexRegistry.html +2 -2
- package/docs/api/interfaces/FlowQueryIndexRetirement.html +10 -0
- package/docs/api/interfaces/FlowQueryIndexServices.html +6 -0
- package/docs/api/interfaces/FlowQueryIndexStatistics.html +11 -0
- package/docs/api/interfaces/FlowQueryIndexStatus.html +2 -2
- package/docs/api/interfaces/FlowQueryIndexValidation.html +13 -0
- package/docs/api/interfaces/FlowQueryQuality.html +2 -2
- package/docs/api/interfaces/FlowQueryRecordsResult.html +1 -1
- package/docs/api/interfaces/FlowRunProjectionField.html +2 -2
- package/docs/api/interfaces/FlowStatePolicy.html +2 -2
- package/docs/api/interfaces/FlowStatsOptions.html +2 -2
- package/docs/api/interfaces/GovernanceLedgerOptions.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/LimitAmountOptions.html +2 -2
- package/docs/api/interfaces/LimitLeaseOptions.html +2 -2
- package/docs/api/interfaces/LimitListOptions.html +2 -2
- package/docs/api/interfaces/LimitReleaseOptions.html +2 -2
- package/docs/api/interfaces/MutateOptions.html +2 -2
- package/docs/api/interfaces/NamedValueMutation.html +1 -1
- package/docs/api/interfaces/ReadOptions.html +3 -3
- 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/ScheduleFireDueOptions.html +3 -2
- package/docs/api/interfaces/ScheduleFireOptions.html +3 -0
- package/docs/api/interfaces/ScheduleListOptions.html +2 -2
- package/docs/api/interfaces/ScheduleOptions.html +4 -2
- package/docs/api/interfaces/SearchOptions.html +3 -3
- package/docs/api/interfaces/StartAndClaimOptions.html +3 -3
- 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/FlowProjectionField.html +1 -1
- package/docs/api/types/FlowProjectionShape.html +1 -1
- package/docs/api/types/FlowQueryIndexServiceState.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/ScheduleCatchupPolicy.html +2 -0
- package/docs/api/types/ScheduleFireDueResult.html +3 -0
- package/docs/api/types/ScheduleFireResult.html +2 -0
- package/docs/api/types/ScheduleKind.html +1 -0
- package/docs/api/types/ScheduleOverlapPolicy.html +1 -0
- package/docs/api/types/ScheduleRecord.html +12 -0
- package/docs/api/types/ScheduleState.html +1 -0
- package/docs/api/types/SearchStateMeta.html +1 -1
- package/docs/api/variables/FERRICSTORE_MINIMUM_SERVER_VERSION.html +1 -1
- package/docs/api/variables/FERRICSTORE_SDK_VERSION.html +1 -1
- package/docs/api/variables/FlowProjection.html +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -85,7 +85,7 @@ __export(index_exports, {
|
|
|
85
85
|
WorkflowWorker: () => WorkflowWorker,
|
|
86
86
|
classifyServerError: () => classifyServerError,
|
|
87
87
|
complete: () => complete,
|
|
88
|
-
fail: () =>
|
|
88
|
+
fail: () => fail2,
|
|
89
89
|
isOutcome: () => isOutcome,
|
|
90
90
|
isReconnectableClosedConnectionError: () => isReconnectableClosedConnectionError,
|
|
91
91
|
mapException: () => mapException,
|
|
@@ -107,7 +107,7 @@ function assertSafeVariadicDispatch(argumentCount, arrayCapability) {
|
|
|
107
107
|
// src/native-adapter.ts
|
|
108
108
|
var import_node_net3 = require("net");
|
|
109
109
|
var import_node_tls3 = require("tls");
|
|
110
|
-
var
|
|
110
|
+
var import_node_buffer32 = require("buffer");
|
|
111
111
|
|
|
112
112
|
// src/errors.ts
|
|
113
113
|
var FerricStoreError = class extends Error {
|
|
@@ -1237,10 +1237,10 @@ var NativeFlowControl = class {
|
|
|
1237
1237
|
|
|
1238
1238
|
// src/native-heartbeat.ts
|
|
1239
1239
|
var NativeHeartbeat = class {
|
|
1240
|
-
constructor(intervalMs, send,
|
|
1240
|
+
constructor(intervalMs, send, fail3) {
|
|
1241
1241
|
this.intervalMs = intervalMs;
|
|
1242
1242
|
this.send = send;
|
|
1243
|
-
this.fail =
|
|
1243
|
+
this.fail = fail3;
|
|
1244
1244
|
}
|
|
1245
1245
|
intervalMs;
|
|
1246
1246
|
send;
|
|
@@ -1287,9 +1287,11 @@ var FLOW_QUERY_LANGUAGE_VERSION = "FQL1";
|
|
|
1287
1287
|
var FLOW_QUERY_MAX_BYTES = 16 * 1024;
|
|
1288
1288
|
var FLOW_QUERY_MAX_PARAMETERS = 64;
|
|
1289
1289
|
var FLOW_QUERY_MAX_PARAMETER_NAME_BYTES = 128;
|
|
1290
|
+
var FLOW_QUERY_MAX_PARAMETER_VALUE_BYTES = 65535;
|
|
1290
1291
|
var MIN_I64 = -(1n << 63n);
|
|
1291
1292
|
var MAX_I64 = (1n << 63n) - 1n;
|
|
1292
1293
|
var INDEX_ID = /^[A-Za-z0-9_.:-]{1,64}$/u;
|
|
1294
|
+
var PARAMETER_NAME = /^[A-Za-z0-9_.-]+$/u;
|
|
1293
1295
|
function flowQueryArgs(query, params = {}) {
|
|
1294
1296
|
validateFlowQueryText(query);
|
|
1295
1297
|
const entries = flowQueryParameterEntries(params);
|
|
@@ -1343,9 +1345,34 @@ function validateFlowQueryIndexId(indexId) {
|
|
|
1343
1345
|
}
|
|
1344
1346
|
}
|
|
1345
1347
|
function hasFlowExplainPrefix(query) {
|
|
1346
|
-
const source = query
|
|
1347
|
-
|
|
1348
|
-
|
|
1348
|
+
const source = trimFlowQueryAsciiWhitespaceStart(query);
|
|
1349
|
+
return matchesFlowQueryAsciiKeyword(source, 0, "EXPLAIN") && (source.length === 7 || isFlowQueryAsciiWhitespaceCode(source.charCodeAt(7)));
|
|
1350
|
+
}
|
|
1351
|
+
function matchesFlowQueryAsciiKeyword(value, offset, keyword) {
|
|
1352
|
+
if (offset < 0 || offset + keyword.length > value.length) return false;
|
|
1353
|
+
for (let index = 0; index < keyword.length; index += 1) {
|
|
1354
|
+
let actual = value.charCodeAt(offset + index);
|
|
1355
|
+
if (actual >= 97 && actual <= 122) actual -= 32;
|
|
1356
|
+
if (actual !== keyword.charCodeAt(index)) return false;
|
|
1357
|
+
}
|
|
1358
|
+
return true;
|
|
1359
|
+
}
|
|
1360
|
+
function trimFlowQueryAsciiWhitespaceStart(value) {
|
|
1361
|
+
let start = 0;
|
|
1362
|
+
while (start < value.length && isFlowQueryAsciiWhitespaceCode(value.charCodeAt(start))) {
|
|
1363
|
+
start += 1;
|
|
1364
|
+
}
|
|
1365
|
+
return start === 0 ? value : value.slice(start);
|
|
1366
|
+
}
|
|
1367
|
+
function trimFlowQueryAsciiWhitespace(value) {
|
|
1368
|
+
let start = 0;
|
|
1369
|
+
let end = value.length;
|
|
1370
|
+
while (start < end && isFlowQueryAsciiWhitespaceCode(value.charCodeAt(start))) start += 1;
|
|
1371
|
+
while (end > start && isFlowQueryAsciiWhitespaceCode(value.charCodeAt(end - 1))) end -= 1;
|
|
1372
|
+
return start === 0 && end === value.length ? value : value.slice(start, end);
|
|
1373
|
+
}
|
|
1374
|
+
function isFlowQueryAsciiWhitespaceCode(code) {
|
|
1375
|
+
return code === 32 || code === 9 || code === 10 || code === 13;
|
|
1349
1376
|
}
|
|
1350
1377
|
function flowQueryParameterEntries(params) {
|
|
1351
1378
|
if (typeof params !== "object" || params == null || Array.isArray(params)) {
|
|
@@ -1371,19 +1398,26 @@ function flowQueryParameterEntries(params) {
|
|
|
1371
1398
|
function validateFlowQueryParameterName(name) {
|
|
1372
1399
|
validateUnicodeScalarText(name, "FLOW.QUERY parameter name");
|
|
1373
1400
|
const size = import_node_buffer3.Buffer.byteLength(name, "utf8");
|
|
1374
|
-
if (size === 0 || size > FLOW_QUERY_MAX_PARAMETER_NAME_BYTES) {
|
|
1401
|
+
if (size === 0 || size > FLOW_QUERY_MAX_PARAMETER_NAME_BYTES || !PARAMETER_NAME.test(name)) {
|
|
1375
1402
|
throw new TypeError(
|
|
1376
|
-
`FLOW.QUERY parameter names must be 1..${FLOW_QUERY_MAX_PARAMETER_NAME_BYTES}
|
|
1403
|
+
`FLOW.QUERY parameter names must be 1..${FLOW_QUERY_MAX_PARAMETER_NAME_BYTES} ASCII letters, digits, '_', '.', or '-'`
|
|
1377
1404
|
);
|
|
1378
1405
|
}
|
|
1379
1406
|
}
|
|
1380
1407
|
function normalizeFlowQueryParameter(value, name) {
|
|
1381
1408
|
if (typeof value === "string") {
|
|
1382
1409
|
validateUnicodeScalarText(value, `FLOW.QUERY parameter ${JSON.stringify(name)}`);
|
|
1410
|
+
validateParameterValueSize(import_node_buffer3.Buffer.byteLength(value, "utf8"), name);
|
|
1411
|
+
return value;
|
|
1412
|
+
}
|
|
1413
|
+
if (import_node_buffer3.Buffer.isBuffer(value)) {
|
|
1414
|
+
validateParameterValueSize(value.byteLength, name);
|
|
1383
1415
|
return value;
|
|
1384
1416
|
}
|
|
1385
|
-
if (
|
|
1386
|
-
|
|
1417
|
+
if (value instanceof Uint8Array) {
|
|
1418
|
+
validateParameterValueSize(value.byteLength, name);
|
|
1419
|
+
return import_node_buffer3.Buffer.from(value);
|
|
1420
|
+
}
|
|
1387
1421
|
if (typeof value === "boolean") return value;
|
|
1388
1422
|
if (typeof value === "bigint" && value >= MIN_I64 && value <= MAX_I64) return value;
|
|
1389
1423
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -1393,6 +1427,13 @@ function normalizeFlowQueryParameter(value, name) {
|
|
|
1393
1427
|
`FLOW.QUERY parameter ${JSON.stringify(name)} must be text, bytes, boolean, a finite float, or a signed 64-bit integer`
|
|
1394
1428
|
);
|
|
1395
1429
|
}
|
|
1430
|
+
function validateParameterValueSize(size, name) {
|
|
1431
|
+
if (size > FLOW_QUERY_MAX_PARAMETER_VALUE_BYTES) {
|
|
1432
|
+
throw new TypeError(
|
|
1433
|
+
`FLOW.QUERY parameter ${JSON.stringify(name)} exceeds ${FLOW_QUERY_MAX_PARAMETER_VALUE_BYTES} bytes`
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1396
1437
|
function commandText(value, context) {
|
|
1397
1438
|
if (typeof value === "string") {
|
|
1398
1439
|
validateUnicodeScalarText(value, context);
|
|
@@ -3146,6 +3187,7 @@ var FLOW_ADMIN_FIELDS = {
|
|
|
3146
3187
|
AT_MS: "at_ms",
|
|
3147
3188
|
BLOCK: "block_ms",
|
|
3148
3189
|
BLOCK_MS: "block_ms",
|
|
3190
|
+
CATCHUP_POLICY: "catchup_policy",
|
|
3149
3191
|
CONSISTENT_PROJECTION: "consistent_projection",
|
|
3150
3192
|
CORRELATION_ID: "correlation_id",
|
|
3151
3193
|
COUNT: "count",
|
|
@@ -5579,15 +5621,15 @@ function requiredMap(value, context) {
|
|
|
5579
5621
|
}
|
|
5580
5622
|
throw incompatibleServer(`${context} is missing or invalid`);
|
|
5581
5623
|
}
|
|
5582
|
-
function requiredBoundedText(
|
|
5583
|
-
const value = strictText(field(
|
|
5624
|
+
function requiredBoundedText(mapping2, name) {
|
|
5625
|
+
const value = strictText(field(mapping2, name));
|
|
5584
5626
|
if (value == null || value.length === 0 || import_node_buffer20.Buffer.byteLength(value) > 256) {
|
|
5585
5627
|
throw incompatibleServer(`HELLO flow_query ${name} must be bounded non-empty text`);
|
|
5586
5628
|
}
|
|
5587
5629
|
return value;
|
|
5588
5630
|
}
|
|
5589
|
-
function boundedTextSet(
|
|
5590
|
-
const raw = field(
|
|
5631
|
+
function boundedTextSet(mapping2, name, maximum) {
|
|
5632
|
+
const raw = field(mapping2, name);
|
|
5591
5633
|
if (!Array.isArray(raw) || raw.length < 1 || raw.length > maximum) {
|
|
5592
5634
|
throw incompatibleServer(`HELLO ${name} must contain 1..${maximum} entries`);
|
|
5593
5635
|
}
|
|
@@ -5864,7 +5906,10 @@ function isDecodedRecord(value) {
|
|
|
5864
5906
|
// src/protocol-flow-query-result.ts
|
|
5865
5907
|
var CONTRACT = "ferric.flow.query.result/v1";
|
|
5866
5908
|
var MAX_RECORDS = 100;
|
|
5909
|
+
var MIN_CURSOR_BYTES = 16;
|
|
5867
5910
|
var MAX_CURSOR_BYTES = 4096;
|
|
5911
|
+
var CURSOR_PREFIX = import_node_buffer24.Buffer.from("fqc1_");
|
|
5912
|
+
var MAX_SIGNED_64 = (1n << 63n) - 1n;
|
|
5868
5913
|
var RECORD_FIELDS = [
|
|
5869
5914
|
"id",
|
|
5870
5915
|
"type",
|
|
@@ -5928,9 +5973,13 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5928
5973
|
const usage = {};
|
|
5929
5974
|
for (const field3 of USAGE_FIELDS) {
|
|
5930
5975
|
const read = readU64(data, offset);
|
|
5976
|
+
if (BigInt(read.value) > MAX_SIGNED_64) {
|
|
5977
|
+
throw new FerricStoreError("compact FLOW.QUERY usage exceeds signed 64-bit range");
|
|
5978
|
+
}
|
|
5931
5979
|
usage[field3] = read.value;
|
|
5932
5980
|
offset = read.offset;
|
|
5933
5981
|
}
|
|
5982
|
+
validateCompactUsage(usage);
|
|
5934
5983
|
let result;
|
|
5935
5984
|
if (kind === 0) {
|
|
5936
5985
|
const page = readPage(data, offset);
|
|
@@ -5939,6 +5988,7 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5939
5988
|
const count = data.readUInt32BE(offset);
|
|
5940
5989
|
offset += 4;
|
|
5941
5990
|
if (count > MAX_RECORDS) throw new FerricStoreError("compact FLOW.QUERY page exceeds 100 records");
|
|
5991
|
+
validateCompactRecordUsage(usage, count);
|
|
5942
5992
|
consumeDecodeItems(count, budget);
|
|
5943
5993
|
const records = new Array(count);
|
|
5944
5994
|
for (let index = 0; index < count; index += 1) {
|
|
@@ -5948,7 +5998,13 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5948
5998
|
}
|
|
5949
5999
|
result = { version: import_node_buffer24.Buffer.from(CONTRACT), records, page: page.value, quality, usage };
|
|
5950
6000
|
} else if (kind === 1) {
|
|
6001
|
+
if (usageInteger(usage, "result_records") !== 1n) {
|
|
6002
|
+
throw new FerricStoreError("compact FLOW.QUERY count usage is inconsistent");
|
|
6003
|
+
}
|
|
5951
6004
|
const count = readU64(data, offset);
|
|
6005
|
+
if (BigInt(count.value) > MAX_SIGNED_64) {
|
|
6006
|
+
throw new FerricStoreError("compact FLOW.QUERY count exceeds signed 64-bit range");
|
|
6007
|
+
}
|
|
5952
6008
|
offset = count.offset;
|
|
5953
6009
|
result = {
|
|
5954
6010
|
version: import_node_buffer24.Buffer.from(CONTRACT),
|
|
@@ -5973,18 +6029,37 @@ function readPage(data, offset) {
|
|
|
5973
6029
|
if (hasMoreCode === 0 && size === NULL_U32) {
|
|
5974
6030
|
return { value: { has_more: false, cursor: null }, offset };
|
|
5975
6031
|
}
|
|
5976
|
-
if (hasMoreCode !== 1 || size
|
|
6032
|
+
if (hasMoreCode !== 1 || size < MIN_CURSOR_BYTES || size === NULL_U32 || size > MAX_CURSOR_BYTES) {
|
|
5977
6033
|
throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
|
|
5978
6034
|
}
|
|
5979
6035
|
requireAvailable(data, offset, size);
|
|
6036
|
+
const cursor = data.subarray(offset, offset + size);
|
|
6037
|
+
if (!cursor.subarray(0, CURSOR_PREFIX.byteLength).equals(CURSOR_PREFIX) || !(0, import_node_buffer24.isUtf8)(cursor)) {
|
|
6038
|
+
throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
|
|
6039
|
+
}
|
|
5980
6040
|
return {
|
|
5981
6041
|
value: {
|
|
5982
6042
|
has_more: true,
|
|
5983
|
-
cursor: detachDecodedBinary(
|
|
6043
|
+
cursor: detachDecodedBinary(cursor, data.byteLength)
|
|
5984
6044
|
},
|
|
5985
6045
|
offset: offset + size
|
|
5986
6046
|
};
|
|
5987
6047
|
}
|
|
6048
|
+
function validateCompactUsage(usage) {
|
|
6049
|
+
const scanned = usageInteger(usage, "scanned_entries");
|
|
6050
|
+
if (usageInteger(usage, "hydrated_records") > scanned || usageInteger(usage, "duplicate_entries") > scanned || usageInteger(usage, "range_pages") > scanned + usageInteger(usage, "range_seeks") || usageInteger(usage, "residual_checks") > scanned * 12n) {
|
|
6051
|
+
throw new FerricStoreError("compact FLOW.QUERY usage counters are inconsistent");
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
function validateCompactRecordUsage(usage, count) {
|
|
6055
|
+
const resultRecords = usageInteger(usage, "result_records");
|
|
6056
|
+
if (resultRecords !== BigInt(count) || resultRecords > usageInteger(usage, "scanned_entries")) {
|
|
6057
|
+
throw new FerricStoreError("compact FLOW.QUERY record usage is inconsistent");
|
|
6058
|
+
}
|
|
6059
|
+
}
|
|
6060
|
+
function usageInteger(usage, field3) {
|
|
6061
|
+
return BigInt(usage[field3]);
|
|
6062
|
+
}
|
|
5988
6063
|
function readRecord(data, offset, budget) {
|
|
5989
6064
|
requireAvailable(data, offset, 4);
|
|
5990
6065
|
const bitmap = data.readUInt32BE(offset);
|
|
@@ -6877,15 +6952,15 @@ function snapshotOwnStringArray(values, name) {
|
|
|
6877
6952
|
|
|
6878
6953
|
// src/client-native-options.ts
|
|
6879
6954
|
function snapshotNativeClientOptions(options) {
|
|
6880
|
-
const
|
|
6955
|
+
const own2 = { ...options };
|
|
6881
6956
|
const snapshot = {
|
|
6882
|
-
...
|
|
6883
|
-
...typeof
|
|
6884
|
-
...
|
|
6885
|
-
...
|
|
6886
|
-
...
|
|
6887
|
-
...
|
|
6888
|
-
...
|
|
6957
|
+
...own2,
|
|
6958
|
+
...typeof own2.autoReconnect === "object" && own2.autoReconnect != null ? { autoReconnect: Object.freeze({ ...own2.autoReconnect }) } : {},
|
|
6959
|
+
...own2.endpointPolicy == null ? {} : { endpointPolicy: snapshotEndpointPolicy(own2.endpointPolicy) },
|
|
6960
|
+
...own2.events == null ? {} : { events: snapshotOwnStringArray(own2.events, "events") },
|
|
6961
|
+
...own2.seeds == null ? {} : { seeds: snapshotOwnStringArray(own2.seeds, "seeds") },
|
|
6962
|
+
...own2.tlsOptions == null ? {} : { tlsOptions: snapshotTlsOptions(own2.tlsOptions) },
|
|
6963
|
+
...own2.trustedHosts == null ? {} : { trustedHosts: snapshotOwnStringArray(own2.trustedHosts, "trustedHosts") }
|
|
6889
6964
|
};
|
|
6890
6965
|
return Object.freeze(snapshot);
|
|
6891
6966
|
}
|
|
@@ -6926,12 +7001,12 @@ function topologyNativeOptions(options) {
|
|
|
6926
7001
|
}
|
|
6927
7002
|
function snapshotEndpointPolicy(policy) {
|
|
6928
7003
|
if (typeof policy !== "object") return policy;
|
|
6929
|
-
const
|
|
6930
|
-
if (!Object.hasOwn(
|
|
7004
|
+
const own2 = { ...policy };
|
|
7005
|
+
if (!Object.hasOwn(own2, "allowHosts") || !Array.isArray(own2.allowHosts)) {
|
|
6931
7006
|
throw new TypeError("endpointPolicy.allowHosts must be an own array of strings");
|
|
6932
7007
|
}
|
|
6933
7008
|
return Object.freeze({
|
|
6934
|
-
allowHosts: snapshotOwnStringArray(
|
|
7009
|
+
allowHosts: snapshotOwnStringArray(own2.allowHosts, "endpointPolicy.allowHosts")
|
|
6935
7010
|
});
|
|
6936
7011
|
}
|
|
6937
7012
|
function snapshotTlsOptions(options) {
|
|
@@ -8010,6 +8085,63 @@ function nativeStartupPayload(clientName, events) {
|
|
|
8010
8085
|
};
|
|
8011
8086
|
}
|
|
8012
8087
|
|
|
8088
|
+
// src/flow-query-deadline.ts
|
|
8089
|
+
var import_node_buffer31 = require("buffer");
|
|
8090
|
+
function withFlowQueryDeadline(command, timeoutMs, nowMs2) {
|
|
8091
|
+
if (timeoutMs == null) return command;
|
|
8092
|
+
if (command.opcode === OPCODES.pipeline) {
|
|
8093
|
+
return withPipelineQueryDeadlines(command, timeoutMs, nowMs2);
|
|
8094
|
+
}
|
|
8095
|
+
if (command.opcode !== OPCODES.flowQuery) return command;
|
|
8096
|
+
const payload = command.payload;
|
|
8097
|
+
if (payload instanceof Map) {
|
|
8098
|
+
const nextPayload = new Map(payload);
|
|
8099
|
+
nextPayload.set("deadline_ms", flowQueryDeadlineMs(timeoutMs, nowMs2));
|
|
8100
|
+
return { ...command, payload: nextPayload };
|
|
8101
|
+
}
|
|
8102
|
+
if (typeof payload !== "object" || payload == null || Array.isArray(payload) || import_node_buffer31.Buffer.isBuffer(payload) || payload instanceof Uint8Array) {
|
|
8103
|
+
return command;
|
|
8104
|
+
}
|
|
8105
|
+
return {
|
|
8106
|
+
...command,
|
|
8107
|
+
payload: {
|
|
8108
|
+
...payload,
|
|
8109
|
+
deadline_ms: flowQueryDeadlineMs(timeoutMs, nowMs2)
|
|
8110
|
+
}
|
|
8111
|
+
};
|
|
8112
|
+
}
|
|
8113
|
+
function withPipelineQueryDeadlines(command, timeoutMs, nowMs2) {
|
|
8114
|
+
const payload = plainRecord(command.payload);
|
|
8115
|
+
if (payload == null) return command;
|
|
8116
|
+
const rawCommands = payload.commands;
|
|
8117
|
+
if (!Array.isArray(rawCommands)) return command;
|
|
8118
|
+
let commands;
|
|
8119
|
+
let deadlineMs;
|
|
8120
|
+
for (let index = 0; index < rawCommands.length; index += 1) {
|
|
8121
|
+
const rawItem = rawCommands[index];
|
|
8122
|
+
const item = plainRecord(rawItem);
|
|
8123
|
+
if (item?.opcode !== OPCODES.flowQuery) continue;
|
|
8124
|
+
const body = plainRecord(item.body);
|
|
8125
|
+
if (body == null) continue;
|
|
8126
|
+
commands ??= rawCommands.slice();
|
|
8127
|
+
deadlineMs ??= flowQueryDeadlineMs(timeoutMs, nowMs2);
|
|
8128
|
+
commands[index] = { ...item, body: { ...body, deadline_ms: deadlineMs } };
|
|
8129
|
+
}
|
|
8130
|
+
return commands == null ? command : { ...command, payload: { ...payload, commands } };
|
|
8131
|
+
}
|
|
8132
|
+
function flowQueryDeadlineMs(timeoutMs, nowMs2) {
|
|
8133
|
+
return Math.min(
|
|
8134
|
+
Number.MAX_SAFE_INTEGER,
|
|
8135
|
+
(nowMs2 ?? Date.now()) + Math.max(1, Math.ceil(timeoutMs))
|
|
8136
|
+
);
|
|
8137
|
+
}
|
|
8138
|
+
function plainRecord(value) {
|
|
8139
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer31.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
8140
|
+
return void 0;
|
|
8141
|
+
}
|
|
8142
|
+
return value;
|
|
8143
|
+
}
|
|
8144
|
+
|
|
8013
8145
|
// src/native-adapter.ts
|
|
8014
8146
|
var NativeAdapter = class _NativeAdapter {
|
|
8015
8147
|
socket;
|
|
@@ -8215,7 +8347,11 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
8215
8347
|
let frame;
|
|
8216
8348
|
try {
|
|
8217
8349
|
requestId = this.requestScheduler.nextRequestId();
|
|
8218
|
-
frame = encodeRequest(
|
|
8350
|
+
frame = encodeRequest(
|
|
8351
|
+
withFlowQueryDeadline(command, timeoutMs),
|
|
8352
|
+
requestId,
|
|
8353
|
+
this.capabilities.requestFrameBytes
|
|
8354
|
+
);
|
|
8219
8355
|
} catch (error) {
|
|
8220
8356
|
if (hasFlowControlCredit) this.flowControl.release(laneId);
|
|
8221
8357
|
return Promise.reject(error instanceof Error ? error : new FerricStoreError(String(error), { raw: error }));
|
|
@@ -8360,10 +8496,10 @@ function executeCommandArgs(executor, args) {
|
|
|
8360
8496
|
}
|
|
8361
8497
|
|
|
8362
8498
|
// src/reconnecting-executor.ts
|
|
8363
|
-
var
|
|
8499
|
+
var import_node_buffer34 = require("buffer");
|
|
8364
8500
|
|
|
8365
8501
|
// src/command-retry-policy.ts
|
|
8366
|
-
var
|
|
8502
|
+
var import_node_buffer33 = require("buffer");
|
|
8367
8503
|
function isCasMutation(args) {
|
|
8368
8504
|
const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
|
|
8369
8505
|
const name = commandName2(args[offset]);
|
|
@@ -8377,8 +8513,8 @@ function isCasMutation(args) {
|
|
|
8377
8513
|
}
|
|
8378
8514
|
function commandName2(value) {
|
|
8379
8515
|
if (typeof value === "string") return value.toUpperCase();
|
|
8380
|
-
if (
|
|
8381
|
-
return
|
|
8516
|
+
if (import_node_buffer33.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
8517
|
+
return import_node_buffer33.Buffer.from(value).toString("utf8").toUpperCase();
|
|
8382
8518
|
}
|
|
8383
8519
|
return void 0;
|
|
8384
8520
|
}
|
|
@@ -8590,15 +8726,15 @@ function normalizeNonNegativeInteger2(value, fallback) {
|
|
|
8590
8726
|
}
|
|
8591
8727
|
|
|
8592
8728
|
// src/topology.ts
|
|
8593
|
-
var
|
|
8729
|
+
var import_node_buffer37 = require("buffer");
|
|
8594
8730
|
|
|
8595
8731
|
// src/topology-routing.ts
|
|
8596
|
-
var
|
|
8732
|
+
var import_node_buffer36 = require("buffer");
|
|
8597
8733
|
|
|
8598
8734
|
// src/flow-partition-route-cache.ts
|
|
8599
|
-
var
|
|
8735
|
+
var import_node_buffer35 = require("buffer");
|
|
8600
8736
|
var import_node_crypto = require("crypto");
|
|
8601
|
-
var AUTO_PREFIX =
|
|
8737
|
+
var AUTO_PREFIX = import_node_buffer35.Buffer.from("__flow_auto__:", "ascii");
|
|
8602
8738
|
var MAX_CACHEABLE_PARTITION_BYTES = 4 * 1024;
|
|
8603
8739
|
var MAX_CACHE_BYTES = 1 * 1024 * 1024;
|
|
8604
8740
|
var MAX_CACHE_ENTRIES = 1024;
|
|
@@ -8608,10 +8744,10 @@ var cacheBytes = 0;
|
|
|
8608
8744
|
var cacheHits = 0;
|
|
8609
8745
|
var cacheMisses = 0;
|
|
8610
8746
|
function flowLogicalPartitionRoutingKey(value) {
|
|
8611
|
-
if (typeof value !== "string" && !
|
|
8747
|
+
if (typeof value !== "string" && !import_node_buffer35.Buffer.isBuffer(value)) return void 0;
|
|
8612
8748
|
const autoBucket = flowAutoBucket(value);
|
|
8613
8749
|
if (autoBucket != null) return `{fa:${autoBucket}}`;
|
|
8614
|
-
const bytes2 =
|
|
8750
|
+
const bytes2 = import_node_buffer35.Buffer.isBuffer(value) ? value : import_node_buffer35.Buffer.from(value);
|
|
8615
8751
|
if (bytes2.byteLength > MAX_CACHEABLE_PARTITION_BYTES) return hashRoute(bytes2);
|
|
8616
8752
|
const cacheKey = bytes2.toString("base64");
|
|
8617
8753
|
const cached = routeCache.get(cacheKey);
|
|
@@ -8685,7 +8821,7 @@ function routingKeyFromProtocolPayload(name, command) {
|
|
|
8685
8821
|
"scope"
|
|
8686
8822
|
]) {
|
|
8687
8823
|
const value = getField(command.payload, field3);
|
|
8688
|
-
if (typeof value === "string" ||
|
|
8824
|
+
if (typeof value === "string" || import_node_buffer36.Buffer.isBuffer(value)) {
|
|
8689
8825
|
return value;
|
|
8690
8826
|
}
|
|
8691
8827
|
}
|
|
@@ -8733,7 +8869,7 @@ function flowRoutingData(name, args) {
|
|
|
8733
8869
|
if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
|
|
8734
8870
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
8735
8871
|
}
|
|
8736
|
-
if (
|
|
8872
|
+
if (import_node_buffer36.Buffer.isBuffer(partition)) {
|
|
8737
8873
|
const text3 = partition.toString("utf8").toUpperCase();
|
|
8738
8874
|
if (text3 !== "AUTO" && text3 !== "MIXED") {
|
|
8739
8875
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
@@ -8824,17 +8960,17 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
|
|
|
8824
8960
|
return { handled: false };
|
|
8825
8961
|
}
|
|
8826
8962
|
function isRoutingKey(value) {
|
|
8827
|
-
return typeof value === "string" ||
|
|
8963
|
+
return typeof value === "string" || import_node_buffer36.Buffer.isBuffer(value);
|
|
8828
8964
|
}
|
|
8829
8965
|
function flowAutoIdRoutingKey(value) {
|
|
8830
|
-
if (typeof value !== "string" && !
|
|
8966
|
+
if (typeof value !== "string" && !import_node_buffer36.Buffer.isBuffer(value)) {
|
|
8831
8967
|
return void 0;
|
|
8832
8968
|
}
|
|
8833
|
-
const bucket = (
|
|
8969
|
+
const bucket = (import_node_buffer36.Buffer.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
|
|
8834
8970
|
return `{fa:${bucket}}`;
|
|
8835
8971
|
}
|
|
8836
8972
|
function flowClaimLogicalPartitionRoutingKey(value) {
|
|
8837
|
-
if (typeof value !== "string" && !
|
|
8973
|
+
if (typeof value !== "string" && !import_node_buffer36.Buffer.isBuffer(value)) return void 0;
|
|
8838
8974
|
const selector = commandPart(value);
|
|
8839
8975
|
if (selector === "AUTO" || selector === "ANY") return void 0;
|
|
8840
8976
|
if (selector === "GLOBAL") return "{f}";
|
|
@@ -8849,7 +8985,7 @@ function singleShardFlowClaimPartitionKey(values) {
|
|
|
8849
8985
|
return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
|
|
8850
8986
|
}
|
|
8851
8987
|
function singleShardKey(keys) {
|
|
8852
|
-
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !
|
|
8988
|
+
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !import_node_buffer36.Buffer.isBuffer(key))) {
|
|
8853
8989
|
return void 0;
|
|
8854
8990
|
}
|
|
8855
8991
|
const usable = keys;
|
|
@@ -8882,7 +9018,7 @@ function routedKeyGroups(keys, routeKey) {
|
|
|
8882
9018
|
const groups = /* @__PURE__ */ new Map();
|
|
8883
9019
|
for (let index = 0; index < keys.length; index += 1) {
|
|
8884
9020
|
const key = keys[index];
|
|
8885
|
-
if (typeof key !== "string" && !
|
|
9021
|
+
if (typeof key !== "string" && !import_node_buffer36.Buffer.isBuffer(key)) return void 0;
|
|
8886
9022
|
const route = routeKey(key);
|
|
8887
9023
|
const groupKey = `${route.endpointKey}\0${route.laneId}`;
|
|
8888
9024
|
const group = groups.get(groupKey);
|
|
@@ -9971,7 +10107,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
9971
10107
|
};
|
|
9972
10108
|
|
|
9973
10109
|
// src/response-map-preservation.ts
|
|
9974
|
-
var
|
|
10110
|
+
var import_node_buffer38 = require("buffer");
|
|
9975
10111
|
function toStringKeyMapPreservingValues(value) {
|
|
9976
10112
|
if (value == null) return void 0;
|
|
9977
10113
|
const result = {};
|
|
@@ -9981,7 +10117,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
9981
10117
|
}
|
|
9982
10118
|
return result;
|
|
9983
10119
|
}
|
|
9984
|
-
if (typeof value === "object" && !Array.isArray(value) && !
|
|
10120
|
+
if (typeof value === "object" && !Array.isArray(value) && !import_node_buffer38.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
9985
10121
|
for (const [key, item] of Object.entries(value)) {
|
|
9986
10122
|
setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
|
|
9987
10123
|
}
|
|
@@ -9990,7 +10126,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
9990
10126
|
return void 0;
|
|
9991
10127
|
}
|
|
9992
10128
|
function normalizeMapStructurePreservingBytes(value) {
|
|
9993
|
-
if (
|
|
10129
|
+
if (import_node_buffer38.Buffer.isBuffer(value) || value instanceof Uint8Array) return value;
|
|
9994
10130
|
if (value instanceof Map) {
|
|
9995
10131
|
const result = {};
|
|
9996
10132
|
for (const [key, item] of value.entries()) {
|
|
@@ -10012,7 +10148,7 @@ function normalizeMapStructurePreservingBytes(value) {
|
|
|
10012
10148
|
}
|
|
10013
10149
|
|
|
10014
10150
|
// src/native-kv-responses.ts
|
|
10015
|
-
var
|
|
10151
|
+
var import_node_buffer39 = require("buffer");
|
|
10016
10152
|
function rateLimitResultFromResp(value) {
|
|
10017
10153
|
if (!Array.isArray(value) || value.length !== 4) {
|
|
10018
10154
|
throw new TypeError("RATELIMIT.ADD returned an unexpected response");
|
|
@@ -10069,13 +10205,13 @@ function fetchOrComputeResultFromResp(value, codec) {
|
|
|
10069
10205
|
}
|
|
10070
10206
|
function decodePayload(codec, value) {
|
|
10071
10207
|
if (value == null) return null;
|
|
10072
|
-
if (
|
|
10073
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
10074
|
-
if (typeof value === "string") return codec.decode(
|
|
10208
|
+
if (import_node_buffer39.Buffer.isBuffer(value)) return codec.decode(value);
|
|
10209
|
+
if (value instanceof Uint8Array) return codec.decode(import_node_buffer39.Buffer.from(value));
|
|
10210
|
+
if (typeof value === "string") return codec.decode(import_node_buffer39.Buffer.from(value));
|
|
10075
10211
|
return normalizeRefMeta(value);
|
|
10076
10212
|
}
|
|
10077
10213
|
function requiredResponseString(value, context) {
|
|
10078
|
-
if (typeof value !== "string" && !
|
|
10214
|
+
if (typeof value !== "string" && !import_node_buffer39.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
10079
10215
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
10080
10216
|
}
|
|
10081
10217
|
const result = text(value);
|
|
@@ -10092,7 +10228,7 @@ function requiredNonNegativeInteger(value, context) {
|
|
|
10092
10228
|
return result;
|
|
10093
10229
|
}
|
|
10094
10230
|
function responseBytes(value, context) {
|
|
10095
|
-
if (typeof value !== "string" && !
|
|
10231
|
+
if (typeof value !== "string" && !import_node_buffer39.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
10096
10232
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
10097
10233
|
}
|
|
10098
10234
|
return bytes(value);
|
|
@@ -10775,7 +10911,7 @@ function groupAutoPartitionItems(items) {
|
|
|
10775
10911
|
}
|
|
10776
10912
|
|
|
10777
10913
|
// src/client-values.ts
|
|
10778
|
-
var
|
|
10914
|
+
var import_node_buffer40 = require("buffer");
|
|
10779
10915
|
async function valueMGetEntries(client, refs, options = {}) {
|
|
10780
10916
|
const refCount = refs.length;
|
|
10781
10917
|
if (refCount === 0) {
|
|
@@ -10810,12 +10946,12 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
10810
10946
|
const item = response[index];
|
|
10811
10947
|
if (item == null) {
|
|
10812
10948
|
entries[index] = { found: false };
|
|
10813
|
-
} else if (
|
|
10949
|
+
} else if (import_node_buffer40.Buffer.isBuffer(item)) {
|
|
10814
10950
|
entries[index] = { found: true, value: client.codec.decode(item) };
|
|
10815
10951
|
} else if (item instanceof Uint8Array) {
|
|
10816
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10952
|
+
entries[index] = { found: true, value: client.codec.decode(import_node_buffer40.Buffer.from(item)) };
|
|
10817
10953
|
} else if (typeof item === "string") {
|
|
10818
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10954
|
+
entries[index] = { found: true, value: client.codec.decode(import_node_buffer40.Buffer.from(item)) };
|
|
10819
10955
|
} else {
|
|
10820
10956
|
entries[index] = { found: true, value: item };
|
|
10821
10957
|
}
|
|
@@ -10824,10 +10960,10 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
10824
10960
|
}
|
|
10825
10961
|
|
|
10826
10962
|
// src/auto-batch.ts
|
|
10827
|
-
var
|
|
10963
|
+
var import_node_buffer42 = require("buffer");
|
|
10828
10964
|
|
|
10829
10965
|
// src/auto-batch-ordering.ts
|
|
10830
|
-
var
|
|
10966
|
+
var import_node_buffer41 = require("buffer");
|
|
10831
10967
|
function autoBatchOrderingPlan(batch) {
|
|
10832
10968
|
const accesses = /* @__PURE__ */ new Map();
|
|
10833
10969
|
const fallbackDependencies = [];
|
|
@@ -10942,13 +11078,13 @@ function flowManyAutoBatchIds(command, name) {
|
|
|
10942
11078
|
return fixedFlowItemIds(
|
|
10943
11079
|
command,
|
|
10944
11080
|
mixed ? 4 : 3,
|
|
10945
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) &&
|
|
11081
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && import_node_buffer41.Buffer.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
|
|
10946
11082
|
);
|
|
10947
11083
|
}
|
|
10948
11084
|
return fixedFlowItemIds(
|
|
10949
11085
|
command,
|
|
10950
11086
|
mixed ? 4 : 3,
|
|
10951
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
11087
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer41.Buffer.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
|
|
10952
11088
|
);
|
|
10953
11089
|
}
|
|
10954
11090
|
function createManyAutoBatchIds(command) {
|
|
@@ -10961,7 +11097,7 @@ function createManyAutoBatchIds(command) {
|
|
|
10961
11097
|
const ids = fixedFlowItemIds(
|
|
10962
11098
|
command,
|
|
10963
11099
|
width,
|
|
10964
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
11100
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer41.Buffer.isBuffer(command[itemIndex + width - 1]),
|
|
10965
11101
|
markerIndex
|
|
10966
11102
|
);
|
|
10967
11103
|
if (ids != null) return ids;
|
|
@@ -10979,7 +11115,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
|
|
|
10979
11115
|
let cursor = markerIndex + 2;
|
|
10980
11116
|
for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
|
|
10981
11117
|
const id = command[cursor];
|
|
10982
|
-
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !
|
|
11118
|
+
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !import_node_buffer41.Buffer.isBuffer(command[cursor + 2])) return void 0;
|
|
10983
11119
|
ids.push(id);
|
|
10984
11120
|
cursor += 3;
|
|
10985
11121
|
const afterValues = skipExtendedNamedItems(command, cursor, true);
|
|
@@ -10998,7 +11134,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
|
|
|
10998
11134
|
for (let index = 0; index < count; index += 1) {
|
|
10999
11135
|
const name = command[firstItem + index * 2];
|
|
11000
11136
|
const value = command[firstItem + index * 2 + 1];
|
|
11001
|
-
if (!isAutoBatchResourceValue(name) || (encodedValues ? !
|
|
11137
|
+
if (!isAutoBatchResourceValue(name) || (encodedValues ? !import_node_buffer41.Buffer.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
|
|
11002
11138
|
}
|
|
11003
11139
|
return firstItem + count * 2;
|
|
11004
11140
|
}
|
|
@@ -11013,7 +11149,7 @@ function runStepsManyAutoBatchIds(command) {
|
|
|
11013
11149
|
ids.push(item);
|
|
11014
11150
|
continue;
|
|
11015
11151
|
}
|
|
11016
|
-
if (typeof item !== "object" || item == null || Array.isArray(item) ||
|
|
11152
|
+
if (typeof item !== "object" || item == null || Array.isArray(item) || import_node_buffer41.Buffer.isBuffer(item)) return void 0;
|
|
11017
11153
|
const id = item.id;
|
|
11018
11154
|
if (!isAutoBatchResourceValue(id)) return void 0;
|
|
11019
11155
|
ids.push(id);
|
|
@@ -11054,7 +11190,7 @@ function flowValuePutOwner(command, start) {
|
|
|
11054
11190
|
}
|
|
11055
11191
|
var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
|
|
11056
11192
|
function isAutoBatchResourceValue(value) {
|
|
11057
|
-
return typeof value === "string" ||
|
|
11193
|
+
return typeof value === "string" || import_node_buffer41.Buffer.isBuffer(value);
|
|
11058
11194
|
}
|
|
11059
11195
|
function isFencingToken(value) {
|
|
11060
11196
|
return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
|
|
@@ -11063,7 +11199,7 @@ function nonNegativeItemCount(value) {
|
|
|
11063
11199
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
11064
11200
|
}
|
|
11065
11201
|
function autoBatchResourceKey(namespace, value) {
|
|
11066
|
-
return `${namespace}:${
|
|
11202
|
+
return `${namespace}:${import_node_buffer41.Buffer.from(value).toString("base64")}`;
|
|
11067
11203
|
}
|
|
11068
11204
|
function autoBatchCommandName(command) {
|
|
11069
11205
|
return commandView(command).name ?? null;
|
|
@@ -11472,13 +11608,13 @@ function claimFailure(error) {
|
|
|
11472
11608
|
}
|
|
11473
11609
|
|
|
11474
11610
|
// src/client-flow-support.ts
|
|
11475
|
-
var
|
|
11611
|
+
var import_node_buffer55 = require("buffer");
|
|
11476
11612
|
|
|
11477
11613
|
// src/flow-query-builder.ts
|
|
11478
|
-
var
|
|
11614
|
+
var import_node_buffer44 = require("buffer");
|
|
11479
11615
|
|
|
11480
11616
|
// src/flow-query-metadata.ts
|
|
11481
|
-
var
|
|
11617
|
+
var import_node_buffer43 = require("buffer");
|
|
11482
11618
|
var MAX_FLOW_QUERY_METADATA_KEY_BYTES = 64;
|
|
11483
11619
|
function normalizeStateMeta(value, state) {
|
|
11484
11620
|
if (value == null) return {};
|
|
@@ -11503,7 +11639,7 @@ function normalizeStateMeta(value, state) {
|
|
|
11503
11639
|
function metadataEntries(value, context) {
|
|
11504
11640
|
const entries = objectEntries(value ?? {}, context).map(([rawName, item]) => {
|
|
11505
11641
|
const name = rawName.trim();
|
|
11506
|
-
const size =
|
|
11642
|
+
const size = import_node_buffer43.Buffer.byteLength(name, "utf8");
|
|
11507
11643
|
if (size === 0 || size > MAX_FLOW_QUERY_METADATA_KEY_BYTES || name.startsWith("__")) {
|
|
11508
11644
|
throw new TypeError(`${context} key is invalid or reserved`);
|
|
11509
11645
|
}
|
|
@@ -11527,7 +11663,7 @@ function objectEntries(value, context) {
|
|
|
11527
11663
|
return keys.map((key) => [key, value[key]]);
|
|
11528
11664
|
}
|
|
11529
11665
|
function isPlainRecord(value) {
|
|
11530
|
-
if (typeof value !== "object" || value == null || Array.isArray(value) ||
|
|
11666
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer43.Buffer.isBuffer(value)) {
|
|
11531
11667
|
return false;
|
|
11532
11668
|
}
|
|
11533
11669
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -11597,7 +11733,7 @@ var FlowCollectionQuery = class {
|
|
|
11597
11733
|
const states = /* @__PURE__ */ new Set();
|
|
11598
11734
|
for (const [rawState, metadata] of objectEntries(values, "stateMeta")) {
|
|
11599
11735
|
const state = requiredText(rawState, "stateMeta state").trim();
|
|
11600
|
-
const stateBytes =
|
|
11736
|
+
const stateBytes = import_node_buffer44.Buffer.byteLength(state, "utf8");
|
|
11601
11737
|
if (stateBytes === 0 || stateBytes > MAX_FLOW_QUERY_STATE_BYTES) {
|
|
11602
11738
|
throw new TypeError(
|
|
11603
11739
|
`stateMeta state names must be 1..${MAX_FLOW_QUERY_STATE_BYTES} bytes`
|
|
@@ -11776,7 +11912,7 @@ function requiredPartition(value) {
|
|
|
11776
11912
|
"FLOW.QUERY convenience methods require a partition key"
|
|
11777
11913
|
);
|
|
11778
11914
|
}
|
|
11779
|
-
const size =
|
|
11915
|
+
const size = import_node_buffer44.Buffer.byteLength(value, "utf8");
|
|
11780
11916
|
if (size === 0 || size > MAX_FLOW_QUERY_PARTITION_BYTES) {
|
|
11781
11917
|
throw new TypeError(
|
|
11782
11918
|
`FLOW.QUERY partition key must be 1..${MAX_FLOW_QUERY_PARTITION_BYTES} bytes`
|
|
@@ -11824,20 +11960,23 @@ function requiredText(value, context) {
|
|
|
11824
11960
|
return value;
|
|
11825
11961
|
}
|
|
11826
11962
|
function queryParameter(value, context) {
|
|
11827
|
-
if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" ||
|
|
11963
|
+
if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" || import_node_buffer44.Buffer.isBuffer(value)) {
|
|
11828
11964
|
return value;
|
|
11829
11965
|
}
|
|
11830
11966
|
throw new TypeError(`${context} must be a scalar FLOW.QUERY parameter`);
|
|
11831
11967
|
}
|
|
11832
11968
|
|
|
11833
11969
|
// src/flow-query-response.ts
|
|
11834
|
-
var
|
|
11970
|
+
var import_node_buffer48 = require("buffer");
|
|
11971
|
+
|
|
11972
|
+
// src/flow-query-diagnostic-response.ts
|
|
11973
|
+
var import_node_buffer46 = require("buffer");
|
|
11835
11974
|
|
|
11836
11975
|
// src/flow-query-response-validation.ts
|
|
11837
|
-
var
|
|
11976
|
+
var import_node_buffer45 = require("buffer");
|
|
11838
11977
|
function requiredMap2(value, context) {
|
|
11839
11978
|
if (value instanceof Map) return value;
|
|
11840
|
-
if (typeof value !== "object" || value == null || Array.isArray(value) ||
|
|
11979
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer45.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
11841
11980
|
throw decodeError(`${context} must be a map`, value);
|
|
11842
11981
|
}
|
|
11843
11982
|
return value;
|
|
@@ -11894,7 +12033,7 @@ function normalizeMetadataValue(value, context, budget, ancestors, depth) {
|
|
|
11894
12033
|
if (!value.isWellFormed()) throw decodeError(`${context} contains invalid text`, value);
|
|
11895
12034
|
return value;
|
|
11896
12035
|
}
|
|
11897
|
-
if (
|
|
12036
|
+
if (import_node_buffer45.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
11898
12037
|
const decoded = strictText2(value);
|
|
11899
12038
|
if (decoded == null) throw decodeError(`${context} contains invalid UTF-8`, value);
|
|
11900
12039
|
return decoded;
|
|
@@ -11947,36 +12086,36 @@ function isPlainObject6(value) {
|
|
|
11947
12086
|
const prototype = Object.getPrototypeOf(value);
|
|
11948
12087
|
return prototype === Object.prototype || prototype === null;
|
|
11949
12088
|
}
|
|
11950
|
-
function requireContract(
|
|
11951
|
-
const actual = requiredText2(
|
|
12089
|
+
function requireContract(mapping2, name, expected, context) {
|
|
12090
|
+
const actual = requiredText2(mapping2, name, context);
|
|
11952
12091
|
if (actual !== expected) {
|
|
11953
12092
|
throw decodeError(
|
|
11954
12093
|
`${context} has unsupported contract ${JSON.stringify(actual)}`,
|
|
11955
|
-
|
|
12094
|
+
mapping2
|
|
11956
12095
|
);
|
|
11957
12096
|
}
|
|
11958
12097
|
}
|
|
11959
|
-
function requiredText2(
|
|
11960
|
-
const value = strictText2(field(
|
|
12098
|
+
function requiredText2(mapping2, name, context) {
|
|
12099
|
+
const value = strictText2(field(mapping2, name));
|
|
11961
12100
|
if (value == null || value.length === 0) {
|
|
11962
|
-
throw decodeError(`${context} ${name} must be non-empty text`,
|
|
12101
|
+
throw decodeError(`${context} ${name} must be non-empty text`, mapping2);
|
|
11963
12102
|
}
|
|
11964
12103
|
return value;
|
|
11965
12104
|
}
|
|
11966
|
-
function optionalText2(
|
|
11967
|
-
const raw = field(
|
|
12105
|
+
function optionalText2(mapping2, name, context) {
|
|
12106
|
+
const raw = field(mapping2, name);
|
|
11968
12107
|
if (raw == null) return void 0;
|
|
11969
12108
|
const value = strictText2(raw);
|
|
11970
12109
|
if (value == null)
|
|
11971
|
-
throw decodeError(`${context} ${name} must be text`,
|
|
12110
|
+
throw decodeError(`${context} ${name} must be text`, mapping2);
|
|
11972
12111
|
return value;
|
|
11973
12112
|
}
|
|
11974
|
-
function requiredBoundedText2(
|
|
11975
|
-
const value = requiredText2(
|
|
11976
|
-
if (
|
|
12113
|
+
function requiredBoundedText2(mapping2, name, context, maximumBytes) {
|
|
12114
|
+
const value = requiredText2(mapping2, name, context);
|
|
12115
|
+
if (import_node_buffer45.Buffer.byteLength(value, "utf8") > maximumBytes) {
|
|
11977
12116
|
throw decodeError(
|
|
11978
12117
|
`${context} ${name} exceeds ${maximumBytes} bytes`,
|
|
11979
|
-
|
|
12118
|
+
mapping2
|
|
11980
12119
|
);
|
|
11981
12120
|
}
|
|
11982
12121
|
return value;
|
|
@@ -11986,15 +12125,15 @@ function boundedText(value, context, maximumBytes) {
|
|
|
11986
12125
|
if (decoded == null || decoded.length === 0) {
|
|
11987
12126
|
throw decodeError(`${context} must be non-empty text`, value);
|
|
11988
12127
|
}
|
|
11989
|
-
if (
|
|
12128
|
+
if (import_node_buffer45.Buffer.byteLength(decoded, "utf8") > maximumBytes) {
|
|
11990
12129
|
throw decodeError(`${context} exceeds ${maximumBytes} bytes`, value);
|
|
11991
12130
|
}
|
|
11992
12131
|
return decoded;
|
|
11993
12132
|
}
|
|
11994
|
-
function requiredBoolean(
|
|
11995
|
-
const value = field(
|
|
12133
|
+
function requiredBoolean(mapping2, name, context) {
|
|
12134
|
+
const value = field(mapping2, name);
|
|
11996
12135
|
if (typeof value !== "boolean") {
|
|
11997
|
-
throw decodeError(`${context} ${name} must be boolean`,
|
|
12136
|
+
throw decodeError(`${context} ${name} must be boolean`, mapping2);
|
|
11998
12137
|
}
|
|
11999
12138
|
return value;
|
|
12000
12139
|
}
|
|
@@ -12037,13 +12176,13 @@ function positiveBoundedInteger(value, maximum, context) {
|
|
|
12037
12176
|
if (parsed === 0) throw decodeError(`${context} must be positive`, value);
|
|
12038
12177
|
return parsed;
|
|
12039
12178
|
}
|
|
12040
|
-
function hasKey(
|
|
12041
|
-
if (!(
|
|
12042
|
-
if (
|
|
12043
|
-
const binaryName =
|
|
12044
|
-
for (const key of
|
|
12045
|
-
if (
|
|
12046
|
-
if (key instanceof Uint8Array &&
|
|
12179
|
+
function hasKey(mapping2, name) {
|
|
12180
|
+
if (!(mapping2 instanceof Map)) return Object.hasOwn(mapping2, name);
|
|
12181
|
+
if (mapping2.has(name)) return true;
|
|
12182
|
+
const binaryName = import_node_buffer45.Buffer.from(name);
|
|
12183
|
+
for (const key of mapping2.keys()) {
|
|
12184
|
+
if (import_node_buffer45.Buffer.isBuffer(key) && key.equals(binaryName)) return true;
|
|
12185
|
+
if (key instanceof Uint8Array && import_node_buffer45.Buffer.from(key).equals(binaryName))
|
|
12047
12186
|
return true;
|
|
12048
12187
|
}
|
|
12049
12188
|
return false;
|
|
@@ -12054,7 +12193,7 @@ function decodeError(message, raw) {
|
|
|
12054
12193
|
function strictText2(value) {
|
|
12055
12194
|
if (typeof value === "string")
|
|
12056
12195
|
return value.isWellFormed() ? value : void 0;
|
|
12057
|
-
if (
|
|
12196
|
+
if (import_node_buffer45.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
12058
12197
|
try {
|
|
12059
12198
|
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
12060
12199
|
} catch {
|
|
@@ -12087,193 +12226,39 @@ var FlowQueryError = class extends FerricStoreError {
|
|
|
12087
12226
|
}
|
|
12088
12227
|
};
|
|
12089
12228
|
|
|
12090
|
-
// src/flow-query-response.ts
|
|
12091
|
-
var
|
|
12092
|
-
var
|
|
12093
|
-
var
|
|
12094
|
-
var
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
["hydrated_records", "hydratedRecords"],
|
|
12100
|
-
["residual_checks", "residualChecks"],
|
|
12101
|
-
["duplicate_entries", "duplicateEntries"],
|
|
12102
|
-
["result_records", "resultRecords"],
|
|
12103
|
-
["response_bytes", "responseBytes"],
|
|
12104
|
-
["memory_high_water_bytes", "memoryHighWaterBytes"],
|
|
12105
|
-
["wall_time_us", "wallTimeUs"]
|
|
12106
|
-
];
|
|
12107
|
-
var MAX_SIGNED_64 = (1n << 63n) - 1n;
|
|
12108
|
-
var MAX_UNSIGNED_64 = (1n << 64n) - 1n;
|
|
12109
|
-
function decodeFlowQueryResult(value) {
|
|
12110
|
-
const result = decodeFlowQueryResponse(value, (mapping) => freezeMap(mapping));
|
|
12111
|
-
if (result.kind === "records") {
|
|
12112
|
-
return Object.freeze({
|
|
12113
|
-
kind: "records",
|
|
12114
|
-
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
12115
|
-
records: Object.freeze(result.records),
|
|
12116
|
-
page: result.page,
|
|
12117
|
-
quality: result.quality,
|
|
12118
|
-
usage: result.usage,
|
|
12119
|
-
raw: result.raw
|
|
12120
|
-
});
|
|
12121
|
-
}
|
|
12122
|
-
return Object.freeze({
|
|
12123
|
-
kind: "count",
|
|
12124
|
-
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
12125
|
-
count: result.count,
|
|
12126
|
-
quality: result.quality,
|
|
12127
|
-
usage: result.usage,
|
|
12128
|
-
raw: result.raw
|
|
12129
|
-
});
|
|
12130
|
-
}
|
|
12131
|
-
function decodeFlowQueryRecords(value, decodeRecord) {
|
|
12132
|
-
const result = decodeFlowQueryResponse(
|
|
12133
|
-
value,
|
|
12134
|
-
(mapping, index) => decodeRecord(mapping instanceof Map ? freezeMap(mapping) : mapping, index)
|
|
12135
|
-
);
|
|
12136
|
-
if (result.kind === "count") {
|
|
12137
|
-
throw new FerricStoreError("Flow record convenience query returned a count result", {
|
|
12138
|
-
raw: result.raw
|
|
12139
|
-
});
|
|
12140
|
-
}
|
|
12141
|
-
return result.records;
|
|
12142
|
-
}
|
|
12143
|
-
function decodeFlowQueryResponse(value, decodeRecord) {
|
|
12144
|
-
const mapping = requiredMap2(value, "FLOW.QUERY result");
|
|
12145
|
-
requireContract(mapping, "version", FLOW_QUERY_RESULT_CONTRACT, "FLOW.QUERY result");
|
|
12146
|
-
const quality = decodeQuality(field(mapping, "quality"));
|
|
12147
|
-
const usage = decodeUsage(field(mapping, "usage"));
|
|
12148
|
-
const hasRecords = hasKey(mapping, "records");
|
|
12149
|
-
const hasCount = hasKey(mapping, "result");
|
|
12150
|
-
if (hasRecords === hasCount) {
|
|
12151
|
-
throw decodeError("FLOW.QUERY result must contain exactly one records or count shape", value);
|
|
12152
|
-
}
|
|
12153
|
-
const raw = freezeMap(mapping);
|
|
12154
|
-
if (hasRecords) {
|
|
12155
|
-
const rawRecords = field(mapping, "records");
|
|
12156
|
-
if (!Array.isArray(rawRecords) || rawRecords.length > 100) {
|
|
12157
|
-
throw decodeError("FLOW.QUERY records must be an array of at most 100 maps", value);
|
|
12158
|
-
}
|
|
12159
|
-
const records = new Array(rawRecords.length);
|
|
12160
|
-
for (let index = 0; index < rawRecords.length; index += 1) {
|
|
12161
|
-
if (!Object.hasOwn(rawRecords, index)) {
|
|
12162
|
-
throw decodeError("FLOW.QUERY records must be a dense array", value);
|
|
12163
|
-
}
|
|
12164
|
-
records[index] = decodeRecord(
|
|
12165
|
-
requiredMap2(rawRecords[index], `FLOW.QUERY record ${index}`),
|
|
12166
|
-
index
|
|
12167
|
-
);
|
|
12168
|
-
}
|
|
12169
|
-
if (usage.resultRecords !== records.length) {
|
|
12170
|
-
throw decodeError("FLOW.QUERY usage result_records does not match records", value);
|
|
12171
|
-
}
|
|
12172
|
-
return {
|
|
12173
|
-
kind: "records",
|
|
12174
|
-
records,
|
|
12175
|
-
page: decodePage(field(mapping, "page")),
|
|
12176
|
-
quality,
|
|
12177
|
-
usage,
|
|
12178
|
-
raw
|
|
12179
|
-
};
|
|
12180
|
-
}
|
|
12181
|
-
if (hasKey(mapping, "page")) {
|
|
12182
|
-
throw decodeError("FLOW.QUERY count result contains an unexpected page", value);
|
|
12183
|
-
}
|
|
12184
|
-
const countResult = requiredMap2(field(mapping, "result"), "FLOW.QUERY count result");
|
|
12185
|
-
if (requiredText2(countResult, "kind", "FLOW.QUERY count result") !== "count") {
|
|
12186
|
-
throw decodeError("FLOW.QUERY count result kind must be count", value);
|
|
12187
|
-
}
|
|
12188
|
-
const count = boundedInteger(
|
|
12189
|
-
field(countResult, "value"),
|
|
12190
|
-
MAX_SIGNED_64,
|
|
12191
|
-
"FLOW.QUERY count value"
|
|
12192
|
-
);
|
|
12193
|
-
if (usage.resultRecords !== 1) {
|
|
12194
|
-
throw decodeError("FLOW.QUERY count usage result_records must be 1", value);
|
|
12195
|
-
}
|
|
12196
|
-
return {
|
|
12197
|
-
kind: "count",
|
|
12198
|
-
count,
|
|
12199
|
-
quality,
|
|
12200
|
-
usage,
|
|
12201
|
-
raw
|
|
12202
|
-
};
|
|
12203
|
-
}
|
|
12204
|
-
function decodeFlowExplainResult(value) {
|
|
12205
|
-
const mapping = requiredMap2(value, "FLOW.QUERY explain");
|
|
12206
|
-
requireContract(mapping, "version", FLOW_EXPLAIN_CONTRACT, "FLOW.QUERY explain");
|
|
12207
|
-
const queryFingerprint = requiredText2(mapping, "query_fingerprint", "FLOW.QUERY explain");
|
|
12208
|
-
if (!/^[0-9a-f]{64}$/iu.test(queryFingerprint)) {
|
|
12209
|
-
throw decodeError("FLOW.QUERY explain query_fingerprint is invalid", value);
|
|
12210
|
-
}
|
|
12211
|
-
const status = requiredText2(mapping, "status", "FLOW.QUERY explain");
|
|
12212
|
-
if (status !== "planned" && status !== "rejected" && status !== "executed") {
|
|
12213
|
-
throw decodeError(`FLOW.QUERY explain status ${JSON.stringify(status)} is unsupported`, value);
|
|
12214
|
-
}
|
|
12215
|
-
const plan = freezeMetadataMap(
|
|
12216
|
-
requiredMap2(field(mapping, "plan"), "FLOW.QUERY explain plan"),
|
|
12217
|
-
"FLOW.QUERY explain plan"
|
|
12218
|
-
);
|
|
12219
|
-
const estimate = freezeMetadataMap(
|
|
12220
|
-
requiredMap2(field(mapping, "estimate"), "FLOW.QUERY explain estimate"),
|
|
12221
|
-
"FLOW.QUERY explain estimate"
|
|
12222
|
-
);
|
|
12223
|
-
const bounds = freezeMetadataMap(
|
|
12224
|
-
requiredMap2(field(mapping, "bounds"), "FLOW.QUERY explain bounds"),
|
|
12225
|
-
"FLOW.QUERY explain bounds"
|
|
12226
|
-
);
|
|
12227
|
-
const actualValue = field(mapping, "actual");
|
|
12228
|
-
let actual;
|
|
12229
|
-
if (status === "executed") {
|
|
12230
|
-
if (actualValue == null) {
|
|
12231
|
-
throw decodeError("FLOW.QUERY executed explain is missing actual usage", value);
|
|
12232
|
-
}
|
|
12233
|
-
actual = decodeUsage(actualValue);
|
|
12234
|
-
} else if (actualValue != null) {
|
|
12235
|
-
throw decodeError("FLOW.QUERY non-executed explain contains actual usage", value);
|
|
12236
|
-
}
|
|
12237
|
-
const diagnosticValue = field(mapping, "diagnostic");
|
|
12238
|
-
let diagnostic;
|
|
12239
|
-
if (status === "rejected") {
|
|
12240
|
-
diagnostic = tryDecodeFlowQueryError(diagnosticValue);
|
|
12241
|
-
if (diagnostic == null) {
|
|
12242
|
-
throw decodeError("FLOW.QUERY rejected explain has an invalid diagnostic", value);
|
|
12243
|
-
}
|
|
12244
|
-
} else if (diagnosticValue != null) {
|
|
12245
|
-
throw decodeError("FLOW.QUERY non-rejected explain contains a diagnostic", value);
|
|
12246
|
-
}
|
|
12247
|
-
return Object.freeze({
|
|
12248
|
-
version: FLOW_EXPLAIN_CONTRACT,
|
|
12249
|
-
queryFingerprint,
|
|
12250
|
-
status,
|
|
12251
|
-
plan,
|
|
12252
|
-
estimate,
|
|
12253
|
-
bounds,
|
|
12254
|
-
actual,
|
|
12255
|
-
diagnostic,
|
|
12256
|
-
raw: freezeMap(mapping)
|
|
12257
|
-
});
|
|
12258
|
-
}
|
|
12229
|
+
// src/flow-query-diagnostic-response.ts
|
|
12230
|
+
var MIN_SIGNED_64 = -(1n << 63n);
|
|
12231
|
+
var MAX_SIGNED_642 = (1n << 63n) - 1n;
|
|
12232
|
+
var DIAGNOSTIC_TEXT_BYTES = 1024;
|
|
12233
|
+
var DIAGNOSTIC_CONTEXT_ENTRIES = 16;
|
|
12234
|
+
var DIAGNOSTIC_CONTEXT_LIST_ITEMS = 32;
|
|
12235
|
+
var DIAGNOSTIC_CONTEXT_KEY_BYTES = 128;
|
|
12236
|
+
var DIAGNOSTIC_CONTEXT_DEPTH = 6;
|
|
12237
|
+
var DIAGNOSTIC_CONTEXT_NODES = 512;
|
|
12259
12238
|
function tryDecodeFlowQueryError(value, cause) {
|
|
12260
12239
|
try {
|
|
12261
|
-
const
|
|
12262
|
-
const
|
|
12263
|
-
const
|
|
12264
|
-
requiredMap2(contextValue, "FLOW.QUERY diagnostic context"),
|
|
12265
|
-
"FLOW.QUERY diagnostic context"
|
|
12266
|
-
);
|
|
12267
|
-
const position = decodePosition(field(mapping, "position"));
|
|
12240
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY diagnostic");
|
|
12241
|
+
const context = decodeDiagnosticContext(field(mapping2, "context"));
|
|
12242
|
+
const position = decodePosition(field(mapping2, "position"));
|
|
12268
12243
|
return new FlowQueryError({
|
|
12269
|
-
code:
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
12244
|
+
code: requiredBoundedText2(
|
|
12245
|
+
mapping2,
|
|
12246
|
+
"code",
|
|
12247
|
+
"FLOW.QUERY diagnostic",
|
|
12248
|
+
DIAGNOSTIC_TEXT_BYTES
|
|
12249
|
+
),
|
|
12250
|
+
message: requiredBoundedText2(
|
|
12251
|
+
mapping2,
|
|
12252
|
+
"message",
|
|
12253
|
+
"FLOW.QUERY diagnostic",
|
|
12254
|
+
DIAGNOSTIC_TEXT_BYTES
|
|
12255
|
+
),
|
|
12256
|
+
detail: optionalDiagnosticText(mapping2, "detail"),
|
|
12257
|
+
hint: optionalDiagnosticText(mapping2, "hint"),
|
|
12258
|
+
retryable: requiredBoolean(mapping2, "retryable", "FLOW.QUERY diagnostic"),
|
|
12259
|
+
safeToRetry: requiredBoolean(mapping2, "safe_to_retry", "FLOW.QUERY diagnostic"),
|
|
12275
12260
|
retryAfterMs: nonNegativeInteger(
|
|
12276
|
-
field(
|
|
12261
|
+
field(mapping2, "retry_after_ms"),
|
|
12277
12262
|
"FLOW.QUERY diagnostic retry_after_ms"
|
|
12278
12263
|
),
|
|
12279
12264
|
position,
|
|
@@ -12286,142 +12271,1269 @@ function tryDecodeFlowQueryError(value, cause) {
|
|
|
12286
12271
|
throw error;
|
|
12287
12272
|
}
|
|
12288
12273
|
}
|
|
12289
|
-
function
|
|
12290
|
-
const
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12274
|
+
function optionalDiagnosticText(mapping2, name) {
|
|
12275
|
+
const value = optionalText2(mapping2, name, "FLOW.QUERY diagnostic");
|
|
12276
|
+
if (value != null && import_node_buffer46.Buffer.byteLength(value, "utf8") > DIAGNOSTIC_TEXT_BYTES) {
|
|
12277
|
+
throw decodeError(
|
|
12278
|
+
`FLOW.QUERY diagnostic ${name} exceeds ${DIAGNOSTIC_TEXT_BYTES} bytes`,
|
|
12279
|
+
mapping2
|
|
12280
|
+
);
|
|
12281
|
+
}
|
|
12282
|
+
return value;
|
|
12283
|
+
}
|
|
12284
|
+
function decodeDiagnosticContext(value) {
|
|
12285
|
+
if (value == null) return void 0;
|
|
12286
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY diagnostic context");
|
|
12287
|
+
const size = mapping2 instanceof Map ? mapping2.size : Object.keys(mapping2).length;
|
|
12288
|
+
if (size > DIAGNOSTIC_CONTEXT_ENTRIES) {
|
|
12289
|
+
throw decodeError("FLOW.QUERY diagnostic context contains too many entries", value);
|
|
12290
|
+
}
|
|
12291
|
+
validateDiagnosticContextValue(
|
|
12292
|
+
mapping2,
|
|
12293
|
+
DIAGNOSTIC_CONTEXT_DEPTH,
|
|
12294
|
+
{ remaining: DIAGNOSTIC_CONTEXT_NODES }
|
|
12301
12295
|
);
|
|
12302
|
-
|
|
12303
|
-
|
|
12304
|
-
|
|
12296
|
+
return freezeMetadataMap(mapping2, "FLOW.QUERY diagnostic context");
|
|
12297
|
+
}
|
|
12298
|
+
function validateDiagnosticContextValue(value, depth, budget) {
|
|
12299
|
+
consumeDiagnosticContextNode(value, budget);
|
|
12300
|
+
if (value == null || typeof value === "boolean") return;
|
|
12301
|
+
if (typeof value === "number") {
|
|
12302
|
+
if (Number.isSafeInteger(value)) return;
|
|
12303
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid integer", value);
|
|
12305
12304
|
}
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12305
|
+
if (typeof value === "bigint") {
|
|
12306
|
+
if (value >= MIN_SIGNED_64 && value <= MAX_SIGNED_642) return;
|
|
12307
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid integer", value);
|
|
12308
|
+
}
|
|
12309
|
+
const text3 = diagnosticContextText(value);
|
|
12310
|
+
if (text3 != null) {
|
|
12311
|
+
if (import_node_buffer46.Buffer.byteLength(text3, "utf8") <= DIAGNOSTIC_TEXT_BYTES) return;
|
|
12312
|
+
throw decodeError("FLOW.QUERY diagnostic context contains oversized text", value);
|
|
12313
|
+
}
|
|
12314
|
+
if (depth <= 0) {
|
|
12315
|
+
throw decodeError("FLOW.QUERY diagnostic context exceeds its maximum depth", value);
|
|
12316
|
+
}
|
|
12317
|
+
if (Array.isArray(value)) {
|
|
12318
|
+
if (value.length > DIAGNOSTIC_CONTEXT_LIST_ITEMS) {
|
|
12319
|
+
throw decodeError("FLOW.QUERY diagnostic context list is too large", value);
|
|
12310
12320
|
}
|
|
12311
|
-
|
|
12321
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12322
|
+
if (!Object.hasOwn(value, index)) {
|
|
12323
|
+
throw decodeError("FLOW.QUERY diagnostic context list must be dense", value);
|
|
12324
|
+
}
|
|
12325
|
+
validateDiagnosticContextValue(value[index], depth - 1, budget);
|
|
12326
|
+
}
|
|
12327
|
+
return;
|
|
12312
12328
|
}
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
"FLOW.QUERY
|
|
12329
|
+
if (value instanceof Map || isDiagnosticContextRecord(value)) {
|
|
12330
|
+
const entries = value instanceof Map ? value.entries() : Object.entries(value);
|
|
12331
|
+
const size = value instanceof Map ? value.size : Object.keys(value).length;
|
|
12332
|
+
if (size > DIAGNOSTIC_CONTEXT_ENTRIES) {
|
|
12333
|
+
throw decodeError("FLOW.QUERY diagnostic context map is too large", value);
|
|
12334
|
+
}
|
|
12335
|
+
for (const [rawKey, item] of entries) {
|
|
12336
|
+
const key = diagnosticContextText(rawKey);
|
|
12337
|
+
if (key == null || key.length === 0 || import_node_buffer46.Buffer.byteLength(key, "utf8") > DIAGNOSTIC_CONTEXT_KEY_BYTES) {
|
|
12338
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid key", value);
|
|
12339
|
+
}
|
|
12340
|
+
validateDiagnosticContextValue(item, depth - 1, budget);
|
|
12341
|
+
}
|
|
12342
|
+
return;
|
|
12343
|
+
}
|
|
12344
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an unsupported value", value);
|
|
12345
|
+
}
|
|
12346
|
+
function consumeDiagnosticContextNode(value, budget) {
|
|
12347
|
+
if (budget.remaining <= 0) {
|
|
12348
|
+
throw decodeError("FLOW.QUERY diagnostic context exceeds its node limit", value);
|
|
12349
|
+
}
|
|
12350
|
+
budget.remaining -= 1;
|
|
12351
|
+
}
|
|
12352
|
+
function diagnosticContextText(value) {
|
|
12353
|
+
if (typeof value === "string") return value.isWellFormed() ? value : void 0;
|
|
12354
|
+
if (!import_node_buffer46.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return void 0;
|
|
12355
|
+
try {
|
|
12356
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
12357
|
+
} catch {
|
|
12358
|
+
return void 0;
|
|
12359
|
+
}
|
|
12360
|
+
}
|
|
12361
|
+
function isDiagnosticContextRecord(value) {
|
|
12362
|
+
if (typeof value !== "object" || value == null) return false;
|
|
12363
|
+
const prototype = Object.getPrototypeOf(value);
|
|
12364
|
+
return prototype === Object.prototype || prototype === null;
|
|
12365
|
+
}
|
|
12366
|
+
function decodePosition(value) {
|
|
12367
|
+
if (value == null) return void 0;
|
|
12368
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY diagnostic position");
|
|
12369
|
+
return Object.freeze({
|
|
12370
|
+
byte: positiveInteger(field(mapping2, "byte"), "FLOW.QUERY diagnostic position byte"),
|
|
12371
|
+
line: positiveInteger(field(mapping2, "line"), "FLOW.QUERY diagnostic position line"),
|
|
12372
|
+
column: positiveInteger(
|
|
12373
|
+
field(mapping2, "column"),
|
|
12374
|
+
"FLOW.QUERY diagnostic position column"
|
|
12375
|
+
)
|
|
12376
|
+
});
|
|
12377
|
+
}
|
|
12378
|
+
|
|
12379
|
+
// src/flow-query-index-contract.ts
|
|
12380
|
+
var import_node_buffer47 = require("buffer");
|
|
12381
|
+
var FLOW_QUERY_BUILD_PHASES = ["pending", "snapshot", "backfill", "done"];
|
|
12382
|
+
var FLOW_QUERY_VALIDATION_PHASES = [
|
|
12383
|
+
"pending",
|
|
12384
|
+
"source",
|
|
12385
|
+
"index",
|
|
12386
|
+
"counter",
|
|
12387
|
+
"cleanup",
|
|
12388
|
+
"done"
|
|
12389
|
+
];
|
|
12390
|
+
var FLOW_QUERY_RETIREMENT_PHASES = [
|
|
12391
|
+
"pending",
|
|
12392
|
+
"fence",
|
|
12393
|
+
"index",
|
|
12394
|
+
"counter",
|
|
12395
|
+
"reverse",
|
|
12396
|
+
"cleanup",
|
|
12397
|
+
"done"
|
|
12398
|
+
];
|
|
12399
|
+
var IDENTIFIER = /^[A-Za-z0-9_.:-]+$/u;
|
|
12400
|
+
var UNQUOTED_METADATA = /^[A-Za-z0-9_-]+$/u;
|
|
12401
|
+
var ATTRIBUTE_SELECTOR = /^attribute\['((?:[^']|'')*)'\]$/u;
|
|
12402
|
+
var STATE_META_SELECTOR = /^state_meta\['((?:[^']|'')*)'\]\['((?:[^']|'')*)'\]$/u;
|
|
12403
|
+
var INTEGER_FIELDS = /* @__PURE__ */ new Set([
|
|
12404
|
+
"version",
|
|
12405
|
+
"priority",
|
|
12406
|
+
"created_at_ms",
|
|
12407
|
+
"updated_at_ms",
|
|
12408
|
+
"next_run_at_ms",
|
|
12409
|
+
"lease_deadline_ms",
|
|
12410
|
+
"attempts",
|
|
12411
|
+
"max_active_ms"
|
|
12412
|
+
]);
|
|
12413
|
+
var BUILTIN_FIELDS = /* @__PURE__ */ new Set([
|
|
12414
|
+
...INTEGER_FIELDS,
|
|
12415
|
+
"partition_key",
|
|
12416
|
+
"run_id",
|
|
12417
|
+
"event_id",
|
|
12418
|
+
"type",
|
|
12419
|
+
"state",
|
|
12420
|
+
"run_state",
|
|
12421
|
+
"parent_flow_id",
|
|
12422
|
+
"root_flow_id",
|
|
12423
|
+
"correlation_id"
|
|
12424
|
+
]);
|
|
12425
|
+
var RETIREMENT_PROGRESS_FIELDS = [
|
|
12426
|
+
"phase_counts",
|
|
12427
|
+
"current_phases",
|
|
12428
|
+
"completed_shards",
|
|
12429
|
+
"total_shards",
|
|
12430
|
+
"deleted_entries",
|
|
12431
|
+
"deleted_bytes",
|
|
12432
|
+
"rewritten_reverse_rows"
|
|
12433
|
+
];
|
|
12434
|
+
function validateFlowQueryIndexContract(status, expectedId) {
|
|
12435
|
+
let previousId;
|
|
12436
|
+
let previousVersion;
|
|
12437
|
+
for (const index of status.indexes) {
|
|
12438
|
+
const version = BigInt(index.version);
|
|
12439
|
+
if (previousId != null && (index.id < previousId || index.id === previousId && previousVersion != null && version <= previousVersion)) {
|
|
12440
|
+
fail("indexes must be uniquely sorted by id and version", status.raw);
|
|
12441
|
+
}
|
|
12442
|
+
if (expectedId != null && index.id !== expectedId) {
|
|
12443
|
+
fail("filtered indexes do not match the requested id", status.raw);
|
|
12444
|
+
}
|
|
12445
|
+
previousId = index.id;
|
|
12446
|
+
previousVersion = version;
|
|
12447
|
+
validateIndex(index, status);
|
|
12448
|
+
}
|
|
12449
|
+
if (expectedId != null && status.indexes.length === 0) {
|
|
12450
|
+
fail("filtered indexes do not match the requested id", status.raw);
|
|
12451
|
+
}
|
|
12452
|
+
const hasUnavailableStatistics = status.indexes.some(
|
|
12453
|
+
(index) => index.statistics.status === "unavailable"
|
|
12454
|
+
);
|
|
12455
|
+
if (status.services.statisticsStore === "unavailable") {
|
|
12456
|
+
if (status.indexes.some((index) => index.statistics.status !== "unavailable")) {
|
|
12457
|
+
fail("statistics must be unavailable when the service is unavailable", status.raw);
|
|
12458
|
+
}
|
|
12459
|
+
} else if (hasUnavailableStatistics) {
|
|
12460
|
+
fail("statistics cannot be unavailable while the service is ready", status.raw);
|
|
12461
|
+
}
|
|
12462
|
+
}
|
|
12463
|
+
function validateIndex(index, status) {
|
|
12464
|
+
if (!IDENTIFIER.test(index.id) || index.workloads.some((workload) => !IDENTIFIER.test(workload))) {
|
|
12465
|
+
fail("index identity contains invalid characters", index.raw);
|
|
12466
|
+
}
|
|
12467
|
+
const first = index.fields[0];
|
|
12468
|
+
if (first?.name !== "partition_key" || first.direction !== "asc" || first.encoding !== "hashed") {
|
|
12469
|
+
fail("index must begin with partition_key asc hashed", index.raw);
|
|
12470
|
+
}
|
|
12471
|
+
let attributeFields = 0;
|
|
12472
|
+
for (const indexField of index.fields) {
|
|
12473
|
+
if (indexField.encoding === "hashed" && indexField.direction !== "asc") {
|
|
12474
|
+
fail("hashed index fields must be ascending", index.raw);
|
|
12475
|
+
}
|
|
12476
|
+
const kind = fieldKind(indexField.name);
|
|
12477
|
+
if (kind == null) fail("index contains an unsupported field selector", index.raw);
|
|
12478
|
+
if (indexField.encoding === "ordered" && kind !== "integer") {
|
|
12479
|
+
fail("ordered index fields must be integers", index.raw);
|
|
12480
|
+
}
|
|
12481
|
+
if (kind === "attribute") attributeFields += 1;
|
|
12482
|
+
}
|
|
12483
|
+
if (attributeFields > 1) fail("index may contain at most one attribute field", index.raw);
|
|
12484
|
+
for (const prefix of index.countPrefixes) {
|
|
12485
|
+
if (index.fields.slice(0, prefix).some((field3) => field3.encoding !== "hashed")) {
|
|
12486
|
+
fail("count prefixes may cover only hashed fields", index.raw);
|
|
12487
|
+
}
|
|
12488
|
+
}
|
|
12489
|
+
if (index.coveringFields.length > 0) {
|
|
12490
|
+
if (index.coveringFields.some((field3) => fieldKind(field3) == null)) {
|
|
12491
|
+
fail("index contains an unsupported covering field selector", index.raw);
|
|
12492
|
+
}
|
|
12493
|
+
const required = /* @__PURE__ */ new Set(["run_id", "version", ...index.fields.map((field3) => field3.name)]);
|
|
12494
|
+
if ([...required].some((field3) => !index.coveringFields.includes(field3))) {
|
|
12495
|
+
fail("index covering fields omit an identity or index field", index.raw);
|
|
12496
|
+
}
|
|
12497
|
+
}
|
|
12498
|
+
if (index.countPrefixes.length > 0 !== (index.format.counter != null)) {
|
|
12499
|
+
fail("index counter format is inconsistent with count prefixes", index.raw);
|
|
12500
|
+
}
|
|
12501
|
+
validateProgress(index.build, FLOW_QUERY_BUILD_PHASES, "build");
|
|
12502
|
+
validateProgress(index.validation, FLOW_QUERY_VALIDATION_PHASES, "validation");
|
|
12503
|
+
if (index.retirement.status === "not_applicable") {
|
|
12504
|
+
if (RETIREMENT_PROGRESS_FIELDS.some((name) => hasKey(index.retirement.raw, name))) {
|
|
12505
|
+
fail("not_applicable retirement must not contain progress", index.retirement.raw);
|
|
12506
|
+
}
|
|
12507
|
+
} else {
|
|
12508
|
+
const retirement = index.retirement;
|
|
12509
|
+
if (retirement.phaseCounts == null || retirement.currentPhases == null || retirement.completedShards == null || retirement.totalShards == null) {
|
|
12510
|
+
fail("retirement progress is incomplete", retirement.raw);
|
|
12511
|
+
}
|
|
12512
|
+
validateProgress(
|
|
12513
|
+
{
|
|
12514
|
+
phaseCounts: retirement.phaseCounts,
|
|
12515
|
+
currentPhases: retirement.currentPhases,
|
|
12516
|
+
completedShards: retirement.completedShards,
|
|
12517
|
+
totalShards: retirement.totalShards,
|
|
12518
|
+
raw: retirement.raw
|
|
12519
|
+
},
|
|
12520
|
+
FLOW_QUERY_RETIREMENT_PHASES,
|
|
12521
|
+
"retirement"
|
|
12522
|
+
);
|
|
12523
|
+
}
|
|
12524
|
+
const totals = new Set(
|
|
12525
|
+
[
|
|
12526
|
+
index.coverage.totalShards,
|
|
12527
|
+
index.build.totalShards,
|
|
12528
|
+
index.validation.totalShards,
|
|
12529
|
+
...index.retirement.totalShards == null ? [] : [index.retirement.totalShards]
|
|
12530
|
+
].map(indexInteger)
|
|
12531
|
+
);
|
|
12532
|
+
if (totals.size !== 1) fail("index shard totals are inconsistent", index.raw);
|
|
12533
|
+
if (!sameIndexInteger(index.coverage.completeShards, index.build.completedShards)) {
|
|
12534
|
+
fail("coverage and build completion are inconsistent", index.raw);
|
|
12535
|
+
}
|
|
12536
|
+
if (index.coverage.validation !== index.validation.status) {
|
|
12537
|
+
fail("coverage and validation status are inconsistent", index.raw);
|
|
12538
|
+
}
|
|
12539
|
+
const queryable = index.state === "active" && sameIndexInteger(
|
|
12540
|
+
index.coverage.completeShards,
|
|
12541
|
+
index.coverage.totalShards
|
|
12542
|
+
) && index.coverage.validation === "passed";
|
|
12543
|
+
if (index.queryable !== queryable) fail("index queryable flag is inconsistent", index.raw);
|
|
12544
|
+
validateLifecycle(index);
|
|
12545
|
+
validateValidation(index);
|
|
12546
|
+
validateStatistics(index, status);
|
|
12547
|
+
}
|
|
12548
|
+
function validateProgress(progress, phases, section) {
|
|
12549
|
+
const entries = Object.entries(progress.phaseCounts);
|
|
12550
|
+
if (entries.length === 0 || entries.some(
|
|
12551
|
+
([phase, count]) => !phases.includes(phase) || indexInteger(count) <= 0n
|
|
12552
|
+
) || entries.reduce((sum, [, count]) => sum + indexInteger(count), 0n) !== indexInteger(progress.totalShards)) {
|
|
12553
|
+
fail(`${section} phase_counts are invalid`, progress.raw);
|
|
12554
|
+
}
|
|
12555
|
+
const current = phases.filter((phase) => Object.hasOwn(progress.phaseCounts, phase));
|
|
12556
|
+
if (current.length !== progress.currentPhases.length || current.some((phase, position) => phase !== progress.currentPhases[position])) {
|
|
12557
|
+
fail(`${section} current_phases are inconsistent`, progress.raw);
|
|
12558
|
+
}
|
|
12559
|
+
if (!sameIndexInteger(
|
|
12560
|
+
progress.completedShards,
|
|
12561
|
+
progress.phaseCounts.done ?? 0
|
|
12562
|
+
)) {
|
|
12563
|
+
fail(`${section} completed_shards is inconsistent`, progress.raw);
|
|
12564
|
+
}
|
|
12565
|
+
}
|
|
12566
|
+
function validateLifecycle(index) {
|
|
12567
|
+
const built = sameIndexInteger(
|
|
12568
|
+
index.build.completedShards,
|
|
12569
|
+
index.build.totalShards
|
|
12570
|
+
);
|
|
12571
|
+
const validation = index.validation.status;
|
|
12572
|
+
const retirement = index.retirement.status;
|
|
12573
|
+
const valid = index.state === "building" && !built && validation === "pending" && retirement === "not_applicable" || index.state === "validating" && built && (validation === "pending" || validation === "passed") && retirement === "not_applicable" || index.state === "active" && built && validation === "passed" && retirement === "not_applicable" || index.state === "retiring" && built && validation !== "pending" && retirement !== "not_applicable" || index.state === "failed" && validation !== "pending" && retirement !== "not_applicable";
|
|
12574
|
+
if (!valid) fail("index lifecycle fields are inconsistent", index.raw);
|
|
12575
|
+
}
|
|
12576
|
+
function validateValidation(index) {
|
|
12577
|
+
const validation = index.validation;
|
|
12578
|
+
const valid = validation.status === "pending" && indexInteger(validation.mismatches) === 0n && validation.failureReason == null && validation.validatedAtMs == null || validation.status === "passed" && indexInteger(validation.mismatches) === 0n && validation.failureReason == null && validation.validatedAtMs != null || validation.status === "failed" && indexInteger(validation.mismatches) > 0n && Boolean(validation.failureReason) && validation.validatedAtMs != null;
|
|
12579
|
+
if (!valid) fail("validation status fields are inconsistent", validation.raw);
|
|
12580
|
+
}
|
|
12581
|
+
function validateStatistics(index, status) {
|
|
12582
|
+
const statistics = index.statistics;
|
|
12583
|
+
const times = [
|
|
12584
|
+
statistics.oldestCollectedAtMs,
|
|
12585
|
+
statistics.newestCollectedAtMs,
|
|
12586
|
+
statistics.oldestAgeMs,
|
|
12587
|
+
statistics.newestAgeMs
|
|
12588
|
+
];
|
|
12589
|
+
if (indexInteger(statistics.samples) === 0n) {
|
|
12590
|
+
if (statistics.status !== "missing" && statistics.status !== "unavailable" || times.some((value) => value != null)) {
|
|
12591
|
+
fail("empty statistics fields are inconsistent", statistics.raw);
|
|
12592
|
+
}
|
|
12593
|
+
return;
|
|
12594
|
+
}
|
|
12595
|
+
if (times.some((value) => value == null)) {
|
|
12596
|
+
fail("sampled statistics require timestamps and ages", statistics.raw);
|
|
12597
|
+
}
|
|
12598
|
+
const [oldest, newest, oldestAge, newestAge] = times;
|
|
12599
|
+
if (indexInteger(oldest) > indexInteger(newest) || indexInteger(oldestAge) !== indexAge(status.observedAtMs, oldest) || indexInteger(newestAge) !== indexAge(status.observedAtMs, newest)) {
|
|
12600
|
+
fail("statistics timestamps or ages are inconsistent", statistics.raw);
|
|
12601
|
+
}
|
|
12602
|
+
const expected = sameIndexInteger(statistics.freshSamples, statistics.samples) ? ["fresh"] : indexInteger(statistics.freshSamples) === 0n ? indexInteger(statistics.futureSamples) > 0n ? ["stale", "future"] : ["stale"] : ["mixed"];
|
|
12603
|
+
if (!expected.includes(statistics.status)) {
|
|
12604
|
+
fail("statistics status does not match sample counters", statistics.raw);
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
function fieldKind(name) {
|
|
12608
|
+
if (BUILTIN_FIELDS.has(name)) return INTEGER_FIELDS.has(name) ? "integer" : "keyword";
|
|
12609
|
+
const parts = name.split(".");
|
|
12610
|
+
if (parts.length === 2 && parts[0] === "attribute" && validUnquoted(parts[1] ?? "")) return "attribute";
|
|
12611
|
+
if (parts.length === 3 && parts[0] === "state_meta" && validUnquoted(parts[1] ?? "") && validUnquoted(parts[2] ?? "")) return "state_meta";
|
|
12612
|
+
const attribute = ATTRIBUTE_SELECTOR.exec(name);
|
|
12613
|
+
if (attribute != null) {
|
|
12614
|
+
const metadata = (attribute[1] ?? "").replaceAll("''", "'");
|
|
12615
|
+
if (validMetadata(metadata, true) && name === externalSelector("attribute", metadata)) return "attribute";
|
|
12616
|
+
}
|
|
12617
|
+
const stateMeta = STATE_META_SELECTOR.exec(name);
|
|
12618
|
+
if (stateMeta != null) {
|
|
12619
|
+
const state = (stateMeta[1] ?? "").replaceAll("''", "'");
|
|
12620
|
+
const metadata = (stateMeta[2] ?? "").replaceAll("''", "'");
|
|
12621
|
+
if (validMetadata(state, false) && validMetadata(metadata, true) && name === externalSelector("state_meta", state, metadata)) return "state_meta";
|
|
12622
|
+
}
|
|
12623
|
+
return void 0;
|
|
12624
|
+
}
|
|
12625
|
+
function validUnquoted(value) {
|
|
12626
|
+
return !value.startsWith("__") && UNQUOTED_METADATA.test(value) && import_node_buffer47.Buffer.byteLength(value, "ascii") <= 64;
|
|
12627
|
+
}
|
|
12628
|
+
function validMetadata(value, rejectReserved) {
|
|
12629
|
+
return value.length > 0 && import_node_buffer47.Buffer.byteLength(value, "utf8") <= 64 && (!rejectReserved || !value.startsWith("__"));
|
|
12630
|
+
}
|
|
12631
|
+
function externalSelector(root, ...segments) {
|
|
12632
|
+
return segments.every(validUnquoted) ? [root, ...segments].join(".") : root + segments.map((segment) => `['${segment.replaceAll("'", "''")}']`).join("");
|
|
12633
|
+
}
|
|
12634
|
+
function sameIndexInteger(left, right) {
|
|
12635
|
+
return indexInteger(left) === indexInteger(right);
|
|
12636
|
+
}
|
|
12637
|
+
function indexAge(observedAtMs, collectedAtMs) {
|
|
12638
|
+
const age = indexInteger(observedAtMs) - indexInteger(collectedAtMs);
|
|
12639
|
+
return age < 0n ? 0n : age;
|
|
12640
|
+
}
|
|
12641
|
+
function indexInteger(value) {
|
|
12642
|
+
return BigInt(value);
|
|
12643
|
+
}
|
|
12644
|
+
function fail(message, raw) {
|
|
12645
|
+
throw decodeError(`FLOW.QUERY.INDEXES ${message}`, raw);
|
|
12646
|
+
}
|
|
12647
|
+
|
|
12648
|
+
// src/flow-query-index-decode.ts
|
|
12649
|
+
var MAX_UNSIGNED_64 = (1n << 64n) - 1n;
|
|
12650
|
+
function decodeUniqueTextArray(value, context, maximum, maximumBytes) {
|
|
12651
|
+
if (!Array.isArray(value) || value.length > maximum) {
|
|
12652
|
+
throw decodeError(`${context} must be a bounded array`, value);
|
|
12653
|
+
}
|
|
12654
|
+
const result = new Array(value.length);
|
|
12655
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12656
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12657
|
+
if (!Object.hasOwn(value, index)) {
|
|
12658
|
+
throw decodeError(`${context} must be dense`, value);
|
|
12659
|
+
}
|
|
12660
|
+
const text3 = boundedText(
|
|
12661
|
+
value[index],
|
|
12662
|
+
`${context} entry ${index}`,
|
|
12663
|
+
maximumBytes
|
|
12664
|
+
);
|
|
12665
|
+
if (seen.has(text3)) {
|
|
12666
|
+
throw decodeError(`${context} contains duplicates`, value);
|
|
12667
|
+
}
|
|
12668
|
+
seen.add(text3);
|
|
12669
|
+
result[index] = text3;
|
|
12670
|
+
}
|
|
12671
|
+
return Object.freeze(result);
|
|
12672
|
+
}
|
|
12673
|
+
function requiredChoice(mapping2, name, context, choices) {
|
|
12674
|
+
const value = requiredBoundedText2(mapping2, name, context, 64);
|
|
12675
|
+
if (!choices.includes(value)) {
|
|
12676
|
+
throw decodeError(`${context} ${name} is unsupported`, mapping2);
|
|
12677
|
+
}
|
|
12678
|
+
return value;
|
|
12679
|
+
}
|
|
12680
|
+
function optionalBoundedText(mapping2, name, context, maximumBytes) {
|
|
12681
|
+
const value = field(mapping2, name);
|
|
12682
|
+
if (value == null) return void 0;
|
|
12683
|
+
return boundedText(value, `${context} ${name}`, maximumBytes);
|
|
12684
|
+
}
|
|
12685
|
+
function optionalIndexInteger(mapping2, name, context) {
|
|
12686
|
+
const value = field(mapping2, name);
|
|
12687
|
+
return value == null ? void 0 : unsignedIndexInteger(value, `${context} ${name}`);
|
|
12688
|
+
}
|
|
12689
|
+
function indexCounter(mapping2, name, section) {
|
|
12690
|
+
return unsignedIndexInteger(
|
|
12691
|
+
field(mapping2, name),
|
|
12692
|
+
`FLOW.QUERY.INDEXES index ${section} ${name}`
|
|
12693
|
+
);
|
|
12694
|
+
}
|
|
12695
|
+
function unsignedIndexInteger(value, context) {
|
|
12696
|
+
return boundedInteger(value, MAX_UNSIGNED_64, context);
|
|
12697
|
+
}
|
|
12698
|
+
function positiveIndexInteger(value, context) {
|
|
12699
|
+
return positiveBoundedInteger(value, MAX_UNSIGNED_64, context);
|
|
12700
|
+
}
|
|
12701
|
+
function indexInteger2(value) {
|
|
12702
|
+
return BigInt(value);
|
|
12703
|
+
}
|
|
12704
|
+
|
|
12705
|
+
// src/flow-query-index-lifecycle-response.ts
|
|
12706
|
+
function decodeIndexCoverage(value) {
|
|
12707
|
+
const context = "FLOW.QUERY.INDEXES index coverage";
|
|
12708
|
+
const mapping2 = requiredMap2(value, context);
|
|
12709
|
+
const completeShards = unsignedIndexInteger(
|
|
12710
|
+
field(mapping2, "complete_shards"),
|
|
12711
|
+
`${context} complete_shards`
|
|
12712
|
+
);
|
|
12713
|
+
const totalShards = positiveIndexInteger(
|
|
12714
|
+
field(mapping2, "total_shards"),
|
|
12715
|
+
`${context} total_shards`
|
|
12716
|
+
);
|
|
12717
|
+
if (indexInteger2(completeShards) > indexInteger2(totalShards)) {
|
|
12718
|
+
throw decodeError(`${context} complete_shards exceeds total_shards`, value);
|
|
12719
|
+
}
|
|
12720
|
+
return Object.freeze({
|
|
12721
|
+
completeShards,
|
|
12722
|
+
totalShards,
|
|
12723
|
+
validation: requiredChoice(mapping2, "validation", context, [
|
|
12724
|
+
"pending",
|
|
12725
|
+
"passed",
|
|
12726
|
+
"failed"
|
|
12727
|
+
]),
|
|
12728
|
+
raw: freezeMap(mapping2)
|
|
12729
|
+
});
|
|
12730
|
+
}
|
|
12731
|
+
function decodeIndexBuild(value) {
|
|
12732
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY.INDEXES index build");
|
|
12733
|
+
const progress = decodeIndexProgress(
|
|
12734
|
+
mapping2,
|
|
12735
|
+
"build",
|
|
12736
|
+
FLOW_QUERY_BUILD_PHASES
|
|
12737
|
+
);
|
|
12738
|
+
return Object.freeze({
|
|
12739
|
+
...progress,
|
|
12740
|
+
scannedRecords: indexCounter(mapping2, "scanned_records", "build"),
|
|
12741
|
+
writtenEntries: indexCounter(mapping2, "written_entries", "build"),
|
|
12742
|
+
writtenBytes: indexCounter(mapping2, "written_bytes", "build")
|
|
12743
|
+
});
|
|
12744
|
+
}
|
|
12745
|
+
function decodeIndexValidation(value) {
|
|
12746
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY.INDEXES index validation");
|
|
12747
|
+
if (!hasKey(mapping2, "failure_reason") || !hasKey(mapping2, "validated_at_ms")) {
|
|
12748
|
+
throw decodeError(
|
|
12749
|
+
"FLOW.QUERY.INDEXES index validation is missing nullable fields",
|
|
12750
|
+
value
|
|
12751
|
+
);
|
|
12752
|
+
}
|
|
12753
|
+
const progress = decodeIndexProgress(
|
|
12754
|
+
mapping2,
|
|
12755
|
+
"validation",
|
|
12756
|
+
FLOW_QUERY_VALIDATION_PHASES
|
|
12757
|
+
);
|
|
12758
|
+
return Object.freeze({
|
|
12759
|
+
...progress,
|
|
12760
|
+
status: requiredChoice(
|
|
12761
|
+
mapping2,
|
|
12762
|
+
"status",
|
|
12763
|
+
"FLOW.QUERY.INDEXES index validation",
|
|
12764
|
+
["pending", "passed", "failed"]
|
|
12765
|
+
),
|
|
12766
|
+
checkedRecords: indexCounter(mapping2, "checked_records", "validation"),
|
|
12767
|
+
checkedEntries: indexCounter(mapping2, "checked_entries", "validation"),
|
|
12768
|
+
mismatches: indexCounter(mapping2, "mismatches", "validation"),
|
|
12769
|
+
failureReason: optionalBoundedText(
|
|
12770
|
+
mapping2,
|
|
12771
|
+
"failure_reason",
|
|
12772
|
+
"FLOW.QUERY.INDEXES index validation",
|
|
12773
|
+
128
|
|
12774
|
+
),
|
|
12775
|
+
validatedAtMs: optionalIndexInteger(
|
|
12776
|
+
mapping2,
|
|
12777
|
+
"validated_at_ms",
|
|
12778
|
+
"FLOW.QUERY.INDEXES index validation"
|
|
12779
|
+
)
|
|
12780
|
+
});
|
|
12781
|
+
}
|
|
12782
|
+
function decodeIndexRetirement(value) {
|
|
12783
|
+
const context = "FLOW.QUERY.INDEXES index retirement";
|
|
12784
|
+
const mapping2 = requiredMap2(value, context);
|
|
12785
|
+
const status = requiredChoice(mapping2, "status", context, [
|
|
12786
|
+
"not_applicable",
|
|
12787
|
+
"pending",
|
|
12788
|
+
"complete"
|
|
12789
|
+
]);
|
|
12790
|
+
if (status === "not_applicable") {
|
|
12791
|
+
return Object.freeze({ status, raw: freezeMap(mapping2) });
|
|
12792
|
+
}
|
|
12793
|
+
const completedShards = unsignedIndexInteger(
|
|
12794
|
+
field(mapping2, "completed_shards"),
|
|
12795
|
+
`${context} completed_shards`
|
|
12796
|
+
);
|
|
12797
|
+
const totalShards = positiveIndexInteger(
|
|
12798
|
+
field(mapping2, "total_shards"),
|
|
12799
|
+
`${context} total_shards`
|
|
12800
|
+
);
|
|
12801
|
+
if (indexInteger2(completedShards) > indexInteger2(totalShards)) {
|
|
12802
|
+
throw decodeError(
|
|
12803
|
+
`${context} completed_shards exceeds total_shards`,
|
|
12804
|
+
mapping2
|
|
12805
|
+
);
|
|
12806
|
+
}
|
|
12807
|
+
return Object.freeze({
|
|
12808
|
+
status,
|
|
12809
|
+
phaseCounts: decodePhaseCounts(
|
|
12810
|
+
field(mapping2, "phase_counts"),
|
|
12811
|
+
"retirement"
|
|
12812
|
+
),
|
|
12813
|
+
currentPhases: decodeAllowedPhases(
|
|
12814
|
+
field(mapping2, "current_phases"),
|
|
12815
|
+
"retirement",
|
|
12816
|
+
FLOW_QUERY_RETIREMENT_PHASES
|
|
12817
|
+
),
|
|
12818
|
+
completedShards,
|
|
12819
|
+
totalShards,
|
|
12820
|
+
deletedEntries: indexCounter(mapping2, "deleted_entries", "retirement"),
|
|
12821
|
+
deletedBytes: indexCounter(mapping2, "deleted_bytes", "retirement"),
|
|
12822
|
+
rewrittenReverseRows: indexCounter(
|
|
12823
|
+
mapping2,
|
|
12824
|
+
"rewritten_reverse_rows",
|
|
12825
|
+
"retirement"
|
|
12826
|
+
),
|
|
12827
|
+
raw: freezeMap(mapping2)
|
|
12828
|
+
});
|
|
12829
|
+
}
|
|
12830
|
+
function decodeIndexStatistics(value) {
|
|
12831
|
+
const context = "FLOW.QUERY.INDEXES index statistics";
|
|
12832
|
+
const mapping2 = requiredMap2(value, context);
|
|
12833
|
+
for (const name of [
|
|
12834
|
+
"oldest_collected_at_ms",
|
|
12835
|
+
"newest_collected_at_ms",
|
|
12836
|
+
"oldest_age_ms",
|
|
12837
|
+
"newest_age_ms"
|
|
12838
|
+
]) {
|
|
12839
|
+
if (!hasKey(mapping2, name)) {
|
|
12840
|
+
throw decodeError(
|
|
12841
|
+
`${context} is missing required nullable fields`,
|
|
12842
|
+
value
|
|
12843
|
+
);
|
|
12844
|
+
}
|
|
12845
|
+
}
|
|
12846
|
+
const samples = indexCounter(mapping2, "samples", "statistics");
|
|
12847
|
+
const freshSamples = indexCounter(mapping2, "fresh_samples", "statistics");
|
|
12848
|
+
const staleSamples = indexCounter(mapping2, "stale_samples", "statistics");
|
|
12849
|
+
const futureSamples = indexCounter(mapping2, "future_samples", "statistics");
|
|
12850
|
+
if (indexInteger2(freshSamples) + indexInteger2(staleSamples) !== indexInteger2(samples) || indexInteger2(futureSamples) > indexInteger2(staleSamples)) {
|
|
12851
|
+
throw decodeError(`${context} counters are inconsistent`, value);
|
|
12852
|
+
}
|
|
12853
|
+
return Object.freeze({
|
|
12854
|
+
status: requiredChoice(mapping2, "status", context, [
|
|
12855
|
+
"fresh",
|
|
12856
|
+
"stale",
|
|
12857
|
+
"future",
|
|
12858
|
+
"mixed",
|
|
12859
|
+
"missing",
|
|
12860
|
+
"unavailable"
|
|
12861
|
+
]),
|
|
12862
|
+
samples,
|
|
12863
|
+
freshSamples,
|
|
12864
|
+
staleSamples,
|
|
12865
|
+
futureSamples,
|
|
12866
|
+
oldestCollectedAtMs: optionalIndexInteger(
|
|
12867
|
+
mapping2,
|
|
12868
|
+
"oldest_collected_at_ms",
|
|
12869
|
+
context
|
|
12870
|
+
),
|
|
12871
|
+
newestCollectedAtMs: optionalIndexInteger(
|
|
12872
|
+
mapping2,
|
|
12873
|
+
"newest_collected_at_ms",
|
|
12874
|
+
context
|
|
12875
|
+
),
|
|
12876
|
+
oldestAgeMs: optionalIndexInteger(mapping2, "oldest_age_ms", context),
|
|
12877
|
+
newestAgeMs: optionalIndexInteger(mapping2, "newest_age_ms", context),
|
|
12878
|
+
raw: freezeMap(mapping2)
|
|
12879
|
+
});
|
|
12880
|
+
}
|
|
12881
|
+
function decodeIndexProgress(mapping2, section, allowedPhases) {
|
|
12882
|
+
const context = `FLOW.QUERY.INDEXES index ${section}`;
|
|
12883
|
+
const completedShards = unsignedIndexInteger(
|
|
12884
|
+
field(mapping2, "completed_shards"),
|
|
12885
|
+
`${context} completed_shards`
|
|
12886
|
+
);
|
|
12887
|
+
const totalShards = positiveIndexInteger(
|
|
12888
|
+
field(mapping2, "total_shards"),
|
|
12889
|
+
`${context} total_shards`
|
|
12890
|
+
);
|
|
12891
|
+
if (indexInteger2(completedShards) > indexInteger2(totalShards)) {
|
|
12892
|
+
throw decodeError(
|
|
12893
|
+
`${context} completed_shards exceeds total_shards`,
|
|
12894
|
+
mapping2
|
|
12895
|
+
);
|
|
12896
|
+
}
|
|
12897
|
+
return Object.freeze({
|
|
12898
|
+
scope: requiredChoice(mapping2, "scope", context, ["catalog_build"]),
|
|
12899
|
+
phaseCounts: decodePhaseCounts(field(mapping2, "phase_counts"), section),
|
|
12900
|
+
currentPhases: decodeAllowedPhases(
|
|
12901
|
+
field(mapping2, "current_phases"),
|
|
12902
|
+
section,
|
|
12903
|
+
allowedPhases
|
|
12318
12904
|
),
|
|
12319
|
-
|
|
12320
|
-
|
|
12905
|
+
completedShards,
|
|
12906
|
+
totalShards,
|
|
12907
|
+
raw: freezeMap(mapping2)
|
|
12908
|
+
});
|
|
12909
|
+
}
|
|
12910
|
+
function decodePhaseCounts(value, section) {
|
|
12911
|
+
const context = `FLOW.QUERY.INDEXES index ${section} phase_counts`;
|
|
12912
|
+
const mapping2 = requiredMap2(value, context);
|
|
12913
|
+
const entries = mapping2 instanceof Map ? [...mapping2.entries()] : Object.entries(mapping2);
|
|
12914
|
+
if (entries.length > 16) {
|
|
12915
|
+
throw decodeError(`${context} contains too many entries`, value);
|
|
12916
|
+
}
|
|
12917
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
12918
|
+
for (const [rawPhase, rawCount] of entries) {
|
|
12919
|
+
const phase = boundedText(rawPhase, `${context} phase`, 64);
|
|
12920
|
+
if (Object.hasOwn(result, phase)) {
|
|
12921
|
+
throw decodeError(`${context} contains duplicate phases`, value);
|
|
12922
|
+
}
|
|
12923
|
+
result[phase] = unsignedIndexInteger(rawCount, `${context} ${phase}`);
|
|
12924
|
+
}
|
|
12925
|
+
return Object.freeze(result);
|
|
12926
|
+
}
|
|
12927
|
+
function decodeAllowedPhases(value, section, allowed) {
|
|
12928
|
+
const phases = decodeUniqueTextArray(
|
|
12929
|
+
value,
|
|
12930
|
+
`FLOW.QUERY.INDEXES index ${section} current_phases`,
|
|
12931
|
+
allowed.length,
|
|
12932
|
+
64
|
|
12933
|
+
);
|
|
12934
|
+
if (phases.some((phase) => !allowed.includes(phase))) {
|
|
12935
|
+
throw decodeError(
|
|
12936
|
+
`FLOW.QUERY.INDEXES index ${section} current_phases are invalid`,
|
|
12937
|
+
value
|
|
12938
|
+
);
|
|
12939
|
+
}
|
|
12940
|
+
return phases;
|
|
12941
|
+
}
|
|
12942
|
+
|
|
12943
|
+
// src/flow-query-index-response.ts
|
|
12944
|
+
var FLOW_QUERY_INDEXES_CONTRACT = "ferric.flow.query.indexes/v1";
|
|
12945
|
+
function decodeFlowQueryIndexStatus(value, expectedId) {
|
|
12946
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY.INDEXES");
|
|
12947
|
+
requireContract(
|
|
12948
|
+
mapping2,
|
|
12949
|
+
"contract_version",
|
|
12950
|
+
FLOW_QUERY_INDEXES_CONTRACT,
|
|
12951
|
+
"FLOW.QUERY.INDEXES"
|
|
12952
|
+
);
|
|
12953
|
+
const registry = requiredMap2(
|
|
12954
|
+
field(mapping2, "registry"),
|
|
12955
|
+
"FLOW.QUERY.INDEXES registry"
|
|
12956
|
+
);
|
|
12957
|
+
const services = decodeIndexServices(field(mapping2, "services"));
|
|
12958
|
+
const rawIndexes = field(mapping2, "indexes");
|
|
12959
|
+
if (!Array.isArray(rawIndexes) || rawIndexes.length > 32) {
|
|
12960
|
+
throw decodeError(
|
|
12961
|
+
"FLOW.QUERY.INDEXES indexes must contain at most 32 entries",
|
|
12962
|
+
value
|
|
12963
|
+
);
|
|
12964
|
+
}
|
|
12965
|
+
const indexes = new Array(rawIndexes.length);
|
|
12966
|
+
for (let index = 0; index < rawIndexes.length; index += 1) {
|
|
12967
|
+
if (!Object.hasOwn(rawIndexes, index)) {
|
|
12968
|
+
throw decodeError(
|
|
12969
|
+
"FLOW.QUERY.INDEXES indexes must be a dense array",
|
|
12970
|
+
value
|
|
12971
|
+
);
|
|
12972
|
+
}
|
|
12973
|
+
indexes[index] = decodeIndex(rawIndexes[index], index);
|
|
12974
|
+
}
|
|
12975
|
+
const status = Object.freeze({
|
|
12976
|
+
contractVersion: FLOW_QUERY_INDEXES_CONTRACT,
|
|
12977
|
+
observedAtMs: unsignedIndexInteger(
|
|
12978
|
+
field(mapping2, "observed_at_ms"),
|
|
12979
|
+
"FLOW.QUERY.INDEXES observed_at_ms"
|
|
12980
|
+
),
|
|
12981
|
+
statisticsMaxAgeMs: unsignedIndexInteger(
|
|
12982
|
+
field(mapping2, "statistics_max_age_ms"),
|
|
12321
12983
|
"FLOW.QUERY.INDEXES statistics_max_age_ms"
|
|
12322
12984
|
),
|
|
12323
12985
|
registry: Object.freeze({
|
|
12324
|
-
epoch:
|
|
12986
|
+
epoch: unsignedIndexInteger(
|
|
12325
12987
|
field(registry, "epoch"),
|
|
12326
|
-
MAX_UNSIGNED_64,
|
|
12327
12988
|
"FLOW.QUERY.INDEXES epoch"
|
|
12328
12989
|
),
|
|
12329
|
-
catalogVersion:
|
|
12990
|
+
catalogVersion: positiveIndexInteger(
|
|
12330
12991
|
field(registry, "catalog_version"),
|
|
12331
|
-
MAX_UNSIGNED_64,
|
|
12332
12992
|
"FLOW.QUERY.INDEXES catalog_version"
|
|
12333
12993
|
)
|
|
12334
12994
|
}),
|
|
12335
12995
|
services,
|
|
12336
12996
|
indexes: Object.freeze(indexes),
|
|
12337
|
-
raw: freezeMap(
|
|
12997
|
+
raw: freezeMap(mapping2)
|
|
12998
|
+
});
|
|
12999
|
+
validateFlowQueryIndexContract(status, expectedId);
|
|
13000
|
+
return status;
|
|
13001
|
+
}
|
|
13002
|
+
function decodeIndex(value, index) {
|
|
13003
|
+
const mapping2 = requiredMap2(value, `FLOW.QUERY.INDEXES index ${index}`);
|
|
13004
|
+
const fields = decodeIndexFields(field(mapping2, "fields"));
|
|
13005
|
+
return Object.freeze({
|
|
13006
|
+
id: requiredBoundedText2(mapping2, "id", "FLOW.QUERY.INDEXES index", 64),
|
|
13007
|
+
version: positiveIndexInteger(
|
|
13008
|
+
field(mapping2, "version"),
|
|
13009
|
+
"FLOW.QUERY.INDEXES index version"
|
|
13010
|
+
),
|
|
13011
|
+
buildId: requiredBoundedText2(
|
|
13012
|
+
mapping2,
|
|
13013
|
+
"build_id",
|
|
13014
|
+
"FLOW.QUERY.INDEXES index",
|
|
13015
|
+
128
|
|
13016
|
+
),
|
|
13017
|
+
source: requiredChoice(mapping2, "source", "FLOW.QUERY.INDEXES index", [
|
|
13018
|
+
"runs"
|
|
13019
|
+
]),
|
|
13020
|
+
state: requiredChoice(mapping2, "state", "FLOW.QUERY.INDEXES index", [
|
|
13021
|
+
"building",
|
|
13022
|
+
"validating",
|
|
13023
|
+
"active",
|
|
13024
|
+
"retiring",
|
|
13025
|
+
"failed"
|
|
13026
|
+
]),
|
|
13027
|
+
queryable: requiredBoolean(
|
|
13028
|
+
mapping2,
|
|
13029
|
+
"queryable",
|
|
13030
|
+
"FLOW.QUERY.INDEXES index"
|
|
13031
|
+
),
|
|
13032
|
+
fields,
|
|
13033
|
+
workloads: decodeUniqueTextArray(
|
|
13034
|
+
field(mapping2, "workloads"),
|
|
13035
|
+
"FLOW.QUERY.INDEXES index workloads",
|
|
13036
|
+
16,
|
|
13037
|
+
64
|
|
13038
|
+
),
|
|
13039
|
+
countPrefixes: decodeCountPrefixes(
|
|
13040
|
+
field(mapping2, "count_prefixes"),
|
|
13041
|
+
fields.length
|
|
13042
|
+
),
|
|
13043
|
+
coveringFields: decodeCoveringFields(mapping2),
|
|
13044
|
+
format: decodeIndexFormat(mapping2),
|
|
13045
|
+
coverage: decodeIndexCoverage(field(mapping2, "coverage")),
|
|
13046
|
+
build: decodeIndexBuild(field(mapping2, "build")),
|
|
13047
|
+
validation: decodeIndexValidation(field(mapping2, "validation")),
|
|
13048
|
+
retirement: decodeIndexRetirement(field(mapping2, "retirement")),
|
|
13049
|
+
statistics: decodeIndexStatistics(field(mapping2, "statistics")),
|
|
13050
|
+
raw: freezeMap(mapping2)
|
|
13051
|
+
});
|
|
13052
|
+
}
|
|
13053
|
+
function decodeIndexServices(value) {
|
|
13054
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY.INDEXES services");
|
|
13055
|
+
const choices = ["ready", "unavailable"];
|
|
13056
|
+
return Object.freeze({
|
|
13057
|
+
registry: requiredChoice(
|
|
13058
|
+
mapping2,
|
|
13059
|
+
"registry",
|
|
13060
|
+
"FLOW.QUERY.INDEXES services",
|
|
13061
|
+
choices
|
|
13062
|
+
),
|
|
13063
|
+
lifecycleWorker: requiredChoice(
|
|
13064
|
+
mapping2,
|
|
13065
|
+
"lifecycle_worker",
|
|
13066
|
+
"FLOW.QUERY.INDEXES services",
|
|
13067
|
+
choices
|
|
13068
|
+
),
|
|
13069
|
+
statisticsStore: requiredChoice(
|
|
13070
|
+
mapping2,
|
|
13071
|
+
"statistics_store",
|
|
13072
|
+
"FLOW.QUERY.INDEXES services",
|
|
13073
|
+
choices
|
|
13074
|
+
),
|
|
13075
|
+
statisticsWorker: requiredChoice(
|
|
13076
|
+
mapping2,
|
|
13077
|
+
"statistics_worker",
|
|
13078
|
+
"FLOW.QUERY.INDEXES services",
|
|
13079
|
+
choices
|
|
13080
|
+
),
|
|
13081
|
+
raw: freezeMap(mapping2)
|
|
13082
|
+
});
|
|
13083
|
+
}
|
|
13084
|
+
function decodeIndexFields(value) {
|
|
13085
|
+
const context = "FLOW.QUERY.INDEXES index fields";
|
|
13086
|
+
if (!Array.isArray(value) || value.length < 2 || value.length > 8) {
|
|
13087
|
+
throw decodeError(`${context} must contain 2 to 8 entries`, value);
|
|
13088
|
+
}
|
|
13089
|
+
const fields = new Array(value.length);
|
|
13090
|
+
const names = /* @__PURE__ */ new Set();
|
|
13091
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13092
|
+
if (!Object.hasOwn(value, index)) {
|
|
13093
|
+
throw decodeError(`${context} must be dense`, value);
|
|
13094
|
+
}
|
|
13095
|
+
const mapping2 = requiredMap2(
|
|
13096
|
+
value[index],
|
|
13097
|
+
`FLOW.QUERY.INDEXES index field ${index}`
|
|
13098
|
+
);
|
|
13099
|
+
const name = requiredBoundedText2(
|
|
13100
|
+
mapping2,
|
|
13101
|
+
"name",
|
|
13102
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13103
|
+
512
|
|
13104
|
+
);
|
|
13105
|
+
if (names.has(name)) {
|
|
13106
|
+
throw decodeError(`${context} contain duplicates`, value);
|
|
13107
|
+
}
|
|
13108
|
+
names.add(name);
|
|
13109
|
+
fields[index] = Object.freeze({
|
|
13110
|
+
name,
|
|
13111
|
+
direction: requiredChoice(
|
|
13112
|
+
mapping2,
|
|
13113
|
+
"direction",
|
|
13114
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13115
|
+
["asc", "desc"]
|
|
13116
|
+
),
|
|
13117
|
+
encoding: requiredChoice(
|
|
13118
|
+
mapping2,
|
|
13119
|
+
"encoding",
|
|
13120
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13121
|
+
["hashed", "ordered"]
|
|
13122
|
+
),
|
|
13123
|
+
raw: freezeMap(mapping2)
|
|
13124
|
+
});
|
|
13125
|
+
}
|
|
13126
|
+
return Object.freeze(fields);
|
|
13127
|
+
}
|
|
13128
|
+
function decodeCountPrefixes(value, fieldCount) {
|
|
13129
|
+
const context = "FLOW.QUERY.INDEXES index count_prefixes";
|
|
13130
|
+
if (!Array.isArray(value) || value.length > fieldCount) {
|
|
13131
|
+
throw decodeError(`${context} are invalid`, value);
|
|
13132
|
+
}
|
|
13133
|
+
const prefixes = new Array(value.length);
|
|
13134
|
+
let previous = 0;
|
|
13135
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13136
|
+
if (!Object.hasOwn(value, index)) {
|
|
13137
|
+
throw decodeError(`${context} must be dense`, value);
|
|
13138
|
+
}
|
|
13139
|
+
const prefix = positiveInteger(value[index], `${context} entry`);
|
|
13140
|
+
if (prefix > fieldCount || prefix <= previous) {
|
|
13141
|
+
throw decodeError(`${context} are invalid`, value);
|
|
13142
|
+
}
|
|
13143
|
+
prefixes[index] = prefix;
|
|
13144
|
+
previous = prefix;
|
|
13145
|
+
}
|
|
13146
|
+
return Object.freeze(prefixes);
|
|
13147
|
+
}
|
|
13148
|
+
function decodeCoveringFields(mapping2) {
|
|
13149
|
+
const raw = field(mapping2, "covering_fields");
|
|
13150
|
+
if (!Array.isArray(raw) || raw.length > 32) {
|
|
13151
|
+
throw decodeError(
|
|
13152
|
+
"FLOW.QUERY.INDEXES index covering_fields must contain at most 32 entries",
|
|
13153
|
+
raw
|
|
13154
|
+
);
|
|
13155
|
+
}
|
|
13156
|
+
const fields = new Array(raw.length);
|
|
13157
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13158
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
13159
|
+
if (!Object.hasOwn(raw, index)) {
|
|
13160
|
+
throw decodeError(
|
|
13161
|
+
"FLOW.QUERY.INDEXES index covering_fields must be dense",
|
|
13162
|
+
raw
|
|
13163
|
+
);
|
|
13164
|
+
}
|
|
13165
|
+
const value = boundedText(
|
|
13166
|
+
raw[index],
|
|
13167
|
+
`FLOW.QUERY.INDEXES index covering_fields entry ${index}`,
|
|
13168
|
+
512
|
|
13169
|
+
);
|
|
13170
|
+
if (seen.has(value)) {
|
|
13171
|
+
throw decodeError(
|
|
13172
|
+
"FLOW.QUERY.INDEXES index covering_fields contains duplicates",
|
|
13173
|
+
raw
|
|
13174
|
+
);
|
|
13175
|
+
}
|
|
13176
|
+
seen.add(value);
|
|
13177
|
+
fields[index] = value;
|
|
13178
|
+
}
|
|
13179
|
+
return Object.freeze(fields);
|
|
13180
|
+
}
|
|
13181
|
+
function decodeIndexFormat(mapping2) {
|
|
13182
|
+
const raw = requiredMap2(
|
|
13183
|
+
field(mapping2, "format"),
|
|
13184
|
+
"FLOW.QUERY.INDEXES index format"
|
|
13185
|
+
);
|
|
13186
|
+
if (!hasKey(raw, "counter")) {
|
|
13187
|
+
throw decodeError(
|
|
13188
|
+
"FLOW.QUERY.INDEXES index format counter is missing",
|
|
13189
|
+
raw
|
|
13190
|
+
);
|
|
13191
|
+
}
|
|
13192
|
+
const counterValue = field(raw, "counter");
|
|
13193
|
+
const counter = counterValue === null ? void 0 : boundedText(
|
|
13194
|
+
counterValue,
|
|
13195
|
+
"FLOW.QUERY.INDEXES index format counter",
|
|
13196
|
+
128
|
|
13197
|
+
);
|
|
13198
|
+
return Object.freeze({
|
|
13199
|
+
queryRow: requiredBoundedText2(
|
|
13200
|
+
raw,
|
|
13201
|
+
"query_row",
|
|
13202
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13203
|
+
128
|
|
13204
|
+
),
|
|
13205
|
+
key: requiredBoundedText2(
|
|
13206
|
+
raw,
|
|
13207
|
+
"key",
|
|
13208
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13209
|
+
128
|
|
13210
|
+
),
|
|
13211
|
+
entry: requiredBoundedText2(
|
|
13212
|
+
raw,
|
|
13213
|
+
"entry",
|
|
13214
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13215
|
+
128
|
|
13216
|
+
),
|
|
13217
|
+
reverse: requiredBoundedText2(
|
|
13218
|
+
raw,
|
|
13219
|
+
"reverse",
|
|
13220
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13221
|
+
128
|
|
13222
|
+
),
|
|
13223
|
+
counter,
|
|
13224
|
+
raw: freezeMap(raw)
|
|
13225
|
+
});
|
|
13226
|
+
}
|
|
13227
|
+
|
|
13228
|
+
// src/flow-query-response.ts
|
|
13229
|
+
var FLOW_QUERY_RESULT_CONTRACT = "ferric.flow.query.result/v1";
|
|
13230
|
+
var FLOW_EXPLAIN_CONTRACT = "ferric.flow.explain/v1";
|
|
13231
|
+
var USAGE_FIELDS2 = [
|
|
13232
|
+
["range_seeks", "rangeSeeks"],
|
|
13233
|
+
["range_pages", "rangePages"],
|
|
13234
|
+
["scanned_entries", "scannedEntries"],
|
|
13235
|
+
["scanned_bytes", "scannedBytes"],
|
|
13236
|
+
["hydrated_records", "hydratedRecords"],
|
|
13237
|
+
["residual_checks", "residualChecks"],
|
|
13238
|
+
["duplicate_entries", "duplicateEntries"],
|
|
13239
|
+
["result_records", "resultRecords"],
|
|
13240
|
+
["response_bytes", "responseBytes"],
|
|
13241
|
+
["memory_high_water_bytes", "memoryHighWaterBytes"],
|
|
13242
|
+
["wall_time_us", "wallTimeUs"]
|
|
13243
|
+
];
|
|
13244
|
+
var MAX_SIGNED_643 = (1n << 63n) - 1n;
|
|
13245
|
+
var QUALITY_VALUES2 = {
|
|
13246
|
+
exactness: ["authoritative", "projected_exact", "exact", "not_applicable"],
|
|
13247
|
+
freshness: ["current", "projection_watermark", "not_applicable"],
|
|
13248
|
+
coverage: ["complete", "unavailable"],
|
|
13249
|
+
pagination: ["none", "complete", "authenticated_seek", "live_seek"]
|
|
13250
|
+
};
|
|
13251
|
+
function decodeFlowQueryResult(value) {
|
|
13252
|
+
const result = decodeFlowQueryResponse(value, (mapping2) => freezeMap(mapping2));
|
|
13253
|
+
if (result.kind === "records") {
|
|
13254
|
+
return Object.freeze({
|
|
13255
|
+
kind: "records",
|
|
13256
|
+
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
13257
|
+
records: Object.freeze(result.records),
|
|
13258
|
+
page: result.page,
|
|
13259
|
+
quality: result.quality,
|
|
13260
|
+
usage: result.usage,
|
|
13261
|
+
raw: result.raw
|
|
13262
|
+
});
|
|
13263
|
+
}
|
|
13264
|
+
return Object.freeze({
|
|
13265
|
+
kind: "count",
|
|
13266
|
+
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
13267
|
+
count: result.count,
|
|
13268
|
+
quality: result.quality,
|
|
13269
|
+
usage: result.usage,
|
|
13270
|
+
raw: result.raw
|
|
13271
|
+
});
|
|
13272
|
+
}
|
|
13273
|
+
function decodeFlowQueryRecords(value, decodeRecord) {
|
|
13274
|
+
const result = decodeFlowQueryResponse(
|
|
13275
|
+
value,
|
|
13276
|
+
(mapping2, index) => decodeRecord(mapping2 instanceof Map ? freezeMap(mapping2) : mapping2, index)
|
|
13277
|
+
);
|
|
13278
|
+
if (result.kind === "count") {
|
|
13279
|
+
throw new FerricStoreError("Flow record convenience query returned a count result", {
|
|
13280
|
+
raw: result.raw
|
|
13281
|
+
});
|
|
13282
|
+
}
|
|
13283
|
+
return result.records;
|
|
13284
|
+
}
|
|
13285
|
+
function decodeFlowQueryResponse(value, decodeRecord) {
|
|
13286
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY result");
|
|
13287
|
+
requireContract(mapping2, "version", FLOW_QUERY_RESULT_CONTRACT, "FLOW.QUERY result");
|
|
13288
|
+
const quality = decodeQuality(field(mapping2, "quality"));
|
|
13289
|
+
const usage = decodeUsage(field(mapping2, "usage"));
|
|
13290
|
+
const hasRecords = hasKey(mapping2, "records");
|
|
13291
|
+
const hasCount = hasKey(mapping2, "result");
|
|
13292
|
+
if (hasRecords === hasCount) {
|
|
13293
|
+
throw decodeError("FLOW.QUERY result must contain exactly one records or count shape", value);
|
|
13294
|
+
}
|
|
13295
|
+
const raw = freezeMap(mapping2);
|
|
13296
|
+
if (hasRecords) {
|
|
13297
|
+
const rawRecords = field(mapping2, "records");
|
|
13298
|
+
if (!Array.isArray(rawRecords) || rawRecords.length > 100) {
|
|
13299
|
+
throw decodeError("FLOW.QUERY records must be an array of at most 100 maps", value);
|
|
13300
|
+
}
|
|
13301
|
+
const records = new Array(rawRecords.length);
|
|
13302
|
+
for (let index = 0; index < rawRecords.length; index += 1) {
|
|
13303
|
+
if (!Object.hasOwn(rawRecords, index)) {
|
|
13304
|
+
throw decodeError("FLOW.QUERY records must be a dense array", value);
|
|
13305
|
+
}
|
|
13306
|
+
records[index] = decodeRecord(
|
|
13307
|
+
requiredMap2(rawRecords[index], `FLOW.QUERY record ${index}`),
|
|
13308
|
+
index
|
|
13309
|
+
);
|
|
13310
|
+
}
|
|
13311
|
+
if (usage.resultRecords !== records.length || usage.resultRecords > usage.scannedEntries) {
|
|
13312
|
+
throw decodeError("FLOW.QUERY usage result_records is inconsistent with records", value);
|
|
13313
|
+
}
|
|
13314
|
+
return {
|
|
13315
|
+
kind: "records",
|
|
13316
|
+
records,
|
|
13317
|
+
page: decodePage(field(mapping2, "page")),
|
|
13318
|
+
quality,
|
|
13319
|
+
usage,
|
|
13320
|
+
raw
|
|
13321
|
+
};
|
|
13322
|
+
}
|
|
13323
|
+
if (hasKey(mapping2, "page")) {
|
|
13324
|
+
throw decodeError("FLOW.QUERY count result contains an unexpected page", value);
|
|
13325
|
+
}
|
|
13326
|
+
const countResult = requiredMap2(field(mapping2, "result"), "FLOW.QUERY count result");
|
|
13327
|
+
if (requiredText2(countResult, "kind", "FLOW.QUERY count result") !== "count") {
|
|
13328
|
+
throw decodeError("FLOW.QUERY count result kind must be count", value);
|
|
13329
|
+
}
|
|
13330
|
+
const count = boundedInteger(
|
|
13331
|
+
field(countResult, "value"),
|
|
13332
|
+
MAX_SIGNED_643,
|
|
13333
|
+
"FLOW.QUERY count value"
|
|
13334
|
+
);
|
|
13335
|
+
if (usage.resultRecords !== 1) {
|
|
13336
|
+
throw decodeError("FLOW.QUERY count usage result_records must be 1", value);
|
|
13337
|
+
}
|
|
13338
|
+
return {
|
|
13339
|
+
kind: "count",
|
|
13340
|
+
count,
|
|
13341
|
+
quality,
|
|
13342
|
+
usage,
|
|
13343
|
+
raw
|
|
13344
|
+
};
|
|
13345
|
+
}
|
|
13346
|
+
function decodeFlowExplainResult(value) {
|
|
13347
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY explain");
|
|
13348
|
+
requireContract(mapping2, "version", FLOW_EXPLAIN_CONTRACT, "FLOW.QUERY explain");
|
|
13349
|
+
const queryFingerprint = requiredText2(mapping2, "query_fingerprint", "FLOW.QUERY explain");
|
|
13350
|
+
if (!/^[0-9a-f]{64}$/iu.test(queryFingerprint)) {
|
|
13351
|
+
throw decodeError("FLOW.QUERY explain query_fingerprint is invalid", value);
|
|
13352
|
+
}
|
|
13353
|
+
const status = requiredText2(mapping2, "status", "FLOW.QUERY explain");
|
|
13354
|
+
if (status !== "planned" && status !== "rejected" && status !== "executed") {
|
|
13355
|
+
throw decodeError(`FLOW.QUERY explain status ${JSON.stringify(status)} is unsupported`, value);
|
|
13356
|
+
}
|
|
13357
|
+
const plan = freezeMetadataMap(
|
|
13358
|
+
requiredMap2(field(mapping2, "plan"), "FLOW.QUERY explain plan"),
|
|
13359
|
+
"FLOW.QUERY explain plan"
|
|
13360
|
+
);
|
|
13361
|
+
const estimate = freezeMetadataMap(
|
|
13362
|
+
requiredMap2(field(mapping2, "estimate"), "FLOW.QUERY explain estimate"),
|
|
13363
|
+
"FLOW.QUERY explain estimate"
|
|
13364
|
+
);
|
|
13365
|
+
const bounds = freezeMetadataMap(
|
|
13366
|
+
requiredMap2(field(mapping2, "bounds"), "FLOW.QUERY explain bounds"),
|
|
13367
|
+
"FLOW.QUERY explain bounds"
|
|
13368
|
+
);
|
|
13369
|
+
const capabilities = decodeExplainCapabilities(mapping2);
|
|
13370
|
+
const extendedFields = ["stats", "quality", "pressure", "decision", "alternatives"];
|
|
13371
|
+
const extendedPresence = extendedFields.map((name) => hasKey(mapping2, name));
|
|
13372
|
+
const specialized = capabilities != null && !extendedPresence.some(Boolean);
|
|
13373
|
+
let stats;
|
|
13374
|
+
let quality;
|
|
13375
|
+
let pressure;
|
|
13376
|
+
let decision;
|
|
13377
|
+
let alternatives;
|
|
13378
|
+
if (specialized) {
|
|
13379
|
+
if (status !== "planned") {
|
|
13380
|
+
throw decodeError("FLOW.QUERY specialized explain must be planned", value);
|
|
13381
|
+
}
|
|
13382
|
+
if (hasKey(mapping2, "actual") || hasKey(mapping2, "diagnostic")) {
|
|
13383
|
+
throw decodeError("FLOW.QUERY specialized explain has extended status fields", value);
|
|
13384
|
+
}
|
|
13385
|
+
alternatives = Object.freeze([]);
|
|
13386
|
+
} else {
|
|
13387
|
+
if (!extendedPresence.every(Boolean) || !hasKey(mapping2, "actual") || !hasKey(mapping2, "diagnostic")) {
|
|
13388
|
+
throw decodeError("FLOW.QUERY explain is missing required v1 fields", value);
|
|
13389
|
+
}
|
|
13390
|
+
stats = freezeMetadataMap(
|
|
13391
|
+
requiredMap2(field(mapping2, "stats"), "FLOW.QUERY explain stats"),
|
|
13392
|
+
"FLOW.QUERY explain stats"
|
|
13393
|
+
);
|
|
13394
|
+
quality = decodeQuality(field(mapping2, "quality"));
|
|
13395
|
+
pressure = freezeMetadataMap(
|
|
13396
|
+
requiredMap2(field(mapping2, "pressure"), "FLOW.QUERY explain pressure"),
|
|
13397
|
+
"FLOW.QUERY explain pressure"
|
|
13398
|
+
);
|
|
13399
|
+
decision = freezeMetadataMap(
|
|
13400
|
+
requiredMap2(field(mapping2, "decision"), "FLOW.QUERY explain decision"),
|
|
13401
|
+
"FLOW.QUERY explain decision"
|
|
13402
|
+
);
|
|
13403
|
+
alternatives = decodeExplainAlternatives(field(mapping2, "alternatives"));
|
|
13404
|
+
}
|
|
13405
|
+
const actualValue = field(mapping2, "actual");
|
|
13406
|
+
let actual;
|
|
13407
|
+
if (status === "executed") {
|
|
13408
|
+
if (actualValue == null) {
|
|
13409
|
+
throw decodeError("FLOW.QUERY executed explain is missing actual usage", value);
|
|
13410
|
+
}
|
|
13411
|
+
actual = decodeUsage(actualValue);
|
|
13412
|
+
} else if (actualValue != null) {
|
|
13413
|
+
throw decodeError("FLOW.QUERY non-executed explain contains actual usage", value);
|
|
13414
|
+
}
|
|
13415
|
+
const diagnosticValue = field(mapping2, "diagnostic");
|
|
13416
|
+
let diagnostic;
|
|
13417
|
+
if (status === "rejected") {
|
|
13418
|
+
diagnostic = tryDecodeFlowQueryError(diagnosticValue);
|
|
13419
|
+
if (diagnostic == null) {
|
|
13420
|
+
throw decodeError("FLOW.QUERY rejected explain has an invalid diagnostic", value);
|
|
13421
|
+
}
|
|
13422
|
+
} else if (diagnosticValue != null) {
|
|
13423
|
+
throw decodeError("FLOW.QUERY non-rejected explain contains a diagnostic", value);
|
|
13424
|
+
}
|
|
13425
|
+
return Object.freeze({
|
|
13426
|
+
version: FLOW_EXPLAIN_CONTRACT,
|
|
13427
|
+
queryFingerprint,
|
|
13428
|
+
status,
|
|
13429
|
+
plan,
|
|
13430
|
+
estimate,
|
|
13431
|
+
stats,
|
|
13432
|
+
quality,
|
|
13433
|
+
bounds,
|
|
13434
|
+
pressure,
|
|
13435
|
+
decision,
|
|
13436
|
+
alternatives,
|
|
13437
|
+
capabilities,
|
|
13438
|
+
actual,
|
|
13439
|
+
diagnostic,
|
|
13440
|
+
raw: freezeMap(mapping2)
|
|
12338
13441
|
});
|
|
12339
13442
|
}
|
|
12340
|
-
function
|
|
12341
|
-
|
|
13443
|
+
function decodeExplainCapabilities(mapping2) {
|
|
13444
|
+
if (!hasKey(mapping2, "capabilities")) return void 0;
|
|
13445
|
+
const value = requiredMap2(
|
|
13446
|
+
field(mapping2, "capabilities"),
|
|
13447
|
+
"FLOW.QUERY explain capabilities"
|
|
13448
|
+
);
|
|
12342
13449
|
return Object.freeze({
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
"FLOW.QUERY.INDEXES index version"
|
|
12348
|
-
),
|
|
12349
|
-
buildId: requiredText2(mapping, "build_id", "FLOW.QUERY.INDEXES index"),
|
|
12350
|
-
state: requiredText2(mapping, "state", "FLOW.QUERY.INDEXES index"),
|
|
12351
|
-
queryable: requiredBoolean(mapping, "queryable", "FLOW.QUERY.INDEXES index"),
|
|
12352
|
-
coveringFields: decodeCoveringFields(mapping),
|
|
12353
|
-
format: decodeIndexFormat(mapping),
|
|
12354
|
-
raw: freezeMap(mapping)
|
|
13450
|
+
requested: decodeExplainCapabilityList(field(value, "requested"), "requested"),
|
|
13451
|
+
available: decodeExplainCapabilityList(field(value, "available"), "available"),
|
|
13452
|
+
missing: decodeExplainCapabilityList(field(value, "missing"), "missing"),
|
|
13453
|
+
raw: freezeMetadataMap(value, "FLOW.QUERY explain capabilities")
|
|
12355
13454
|
});
|
|
12356
13455
|
}
|
|
12357
|
-
function
|
|
12358
|
-
|
|
12359
|
-
if (!Array.isArray(raw) || raw.length > 32) {
|
|
13456
|
+
function decodeExplainCapabilityList(value, name) {
|
|
13457
|
+
if (!Array.isArray(value) || value.length > 64) {
|
|
12360
13458
|
throw decodeError(
|
|
12361
|
-
|
|
12362
|
-
|
|
13459
|
+
`FLOW.QUERY explain capabilities ${name} must contain at most 64 entries`,
|
|
13460
|
+
value
|
|
12363
13461
|
);
|
|
12364
13462
|
}
|
|
12365
|
-
const
|
|
13463
|
+
const result = new Array(value.length);
|
|
12366
13464
|
const seen = /* @__PURE__ */ new Set();
|
|
12367
|
-
for (let index = 0; index <
|
|
12368
|
-
if (!Object.hasOwn(
|
|
12369
|
-
throw decodeError(
|
|
13465
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13466
|
+
if (!Object.hasOwn(value, index)) {
|
|
13467
|
+
throw decodeError(`FLOW.QUERY explain capabilities ${name} must be dense`, value);
|
|
12370
13468
|
}
|
|
12371
|
-
const
|
|
12372
|
-
|
|
12373
|
-
`FLOW.QUERY
|
|
12374
|
-
|
|
13469
|
+
const capability = boundedText(
|
|
13470
|
+
value[index],
|
|
13471
|
+
`FLOW.QUERY explain capabilities ${name} entry ${index}`,
|
|
13472
|
+
128
|
|
12375
13473
|
);
|
|
12376
|
-
if (seen.has(
|
|
12377
|
-
throw decodeError(
|
|
13474
|
+
if (seen.has(capability)) {
|
|
13475
|
+
throw decodeError(
|
|
13476
|
+
`FLOW.QUERY explain capabilities ${name} contains duplicates`,
|
|
13477
|
+
value
|
|
13478
|
+
);
|
|
12378
13479
|
}
|
|
12379
|
-
seen.add(
|
|
12380
|
-
|
|
13480
|
+
seen.add(capability);
|
|
13481
|
+
result[index] = capability;
|
|
12381
13482
|
}
|
|
12382
|
-
return Object.freeze(
|
|
13483
|
+
return Object.freeze(result);
|
|
12383
13484
|
}
|
|
12384
|
-
function
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
throw decodeError("FLOW.QUERY.INDEXES index format counter is missing", raw);
|
|
13485
|
+
function decodeExplainAlternatives(value) {
|
|
13486
|
+
if (!Array.isArray(value) || value.length > 31) {
|
|
13487
|
+
throw decodeError("FLOW.QUERY explain alternatives must be an array of at most 31 maps", value);
|
|
12388
13488
|
}
|
|
12389
|
-
const
|
|
12390
|
-
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
}
|
|
13489
|
+
const alternatives = new Array(value.length);
|
|
13490
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13491
|
+
if (!Object.hasOwn(value, index)) {
|
|
13492
|
+
throw decodeError("FLOW.QUERY explain alternatives must be dense", value);
|
|
13493
|
+
}
|
|
13494
|
+
alternatives[index] = freezeMetadataMap(
|
|
13495
|
+
requiredMap2(value[index], `FLOW.QUERY explain alternative ${index}`),
|
|
13496
|
+
`FLOW.QUERY explain alternative ${index}`
|
|
13497
|
+
);
|
|
13498
|
+
}
|
|
13499
|
+
return Object.freeze(alternatives);
|
|
12399
13500
|
}
|
|
12400
13501
|
function decodeQuality(value) {
|
|
12401
|
-
const
|
|
13502
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY quality");
|
|
12402
13503
|
return Object.freeze({
|
|
12403
|
-
exactness:
|
|
12404
|
-
freshness:
|
|
12405
|
-
coverage:
|
|
12406
|
-
pagination:
|
|
13504
|
+
exactness: decodeQualityValue(mapping2, "exactness", QUALITY_VALUES2.exactness),
|
|
13505
|
+
freshness: decodeQualityValue(mapping2, "freshness", QUALITY_VALUES2.freshness),
|
|
13506
|
+
coverage: decodeQualityValue(mapping2, "coverage", QUALITY_VALUES2.coverage),
|
|
13507
|
+
pagination: decodeQualityValue(mapping2, "pagination", QUALITY_VALUES2.pagination)
|
|
12407
13508
|
});
|
|
12408
13509
|
}
|
|
13510
|
+
function decodeQualityValue(mapping2, name, allowed) {
|
|
13511
|
+
const value = requiredBoundedText2(mapping2, name, "FLOW.QUERY quality", 64);
|
|
13512
|
+
if (!allowed.includes(value)) {
|
|
13513
|
+
throw decodeError(`FLOW.QUERY quality ${name} is unsupported`, mapping2);
|
|
13514
|
+
}
|
|
13515
|
+
return value;
|
|
13516
|
+
}
|
|
12409
13517
|
function decodeUsage(value) {
|
|
12410
|
-
const
|
|
13518
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY usage");
|
|
12411
13519
|
const usage = /* @__PURE__ */ Object.create(null);
|
|
12412
13520
|
for (const [wireName, property] of USAGE_FIELDS2) {
|
|
12413
13521
|
usage[property] = nonNegativeInteger(
|
|
12414
|
-
field(
|
|
13522
|
+
field(mapping2, wireName),
|
|
12415
13523
|
`FLOW.QUERY usage ${wireName}`
|
|
12416
13524
|
);
|
|
12417
13525
|
}
|
|
12418
|
-
|
|
13526
|
+
const decoded = usage;
|
|
13527
|
+
if (decoded.hydratedRecords > decoded.scannedEntries || decoded.duplicateEntries > decoded.scannedEntries || decoded.rangePages > decoded.scannedEntries + decoded.rangeSeeks || decoded.residualChecks > decoded.scannedEntries * 12) {
|
|
13528
|
+
throw decodeError("FLOW.QUERY usage counters are inconsistent", value);
|
|
13529
|
+
}
|
|
13530
|
+
return Object.freeze(decoded);
|
|
12419
13531
|
}
|
|
12420
13532
|
function decodePage(value) {
|
|
12421
|
-
const
|
|
12422
|
-
const hasMore = requiredBoolean(
|
|
12423
|
-
const cursor = optionalText2(
|
|
12424
|
-
if (cursor != null && (!cursor.startsWith("fqc1_") ||
|
|
13533
|
+
const mapping2 = requiredMap2(value, "FLOW.QUERY page");
|
|
13534
|
+
const hasMore = requiredBoolean(mapping2, "has_more", "FLOW.QUERY page");
|
|
13535
|
+
const cursor = optionalText2(mapping2, "cursor", "FLOW.QUERY page");
|
|
13536
|
+
if (cursor != null && (!cursor.startsWith("fqc1_") || import_node_buffer48.Buffer.byteLength(cursor) < 16 || import_node_buffer48.Buffer.byteLength(cursor) > 4096)) {
|
|
12425
13537
|
throw decodeError("FLOW.QUERY page cursor is invalid", value);
|
|
12426
13538
|
}
|
|
12427
13539
|
if (hasMore !== (cursor != null)) {
|
|
@@ -12429,26 +13541,14 @@ function decodePage(value) {
|
|
|
12429
13541
|
}
|
|
12430
13542
|
return Object.freeze({ hasMore, ...cursor == null ? {} : { cursor } });
|
|
12431
13543
|
}
|
|
12432
|
-
function decodePosition(value) {
|
|
12433
|
-
if (value == null) return void 0;
|
|
12434
|
-
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic position");
|
|
12435
|
-
return Object.freeze({
|
|
12436
|
-
byte: positiveInteger(field(mapping, "byte"), "FLOW.QUERY diagnostic position byte"),
|
|
12437
|
-
line: positiveInteger(field(mapping, "line"), "FLOW.QUERY diagnostic position line"),
|
|
12438
|
-
column: positiveInteger(
|
|
12439
|
-
field(mapping, "column"),
|
|
12440
|
-
"FLOW.QUERY diagnostic position column"
|
|
12441
|
-
)
|
|
12442
|
-
});
|
|
12443
|
-
}
|
|
12444
13544
|
|
|
12445
13545
|
// src/client-core.ts
|
|
12446
|
-
var
|
|
13546
|
+
var import_node_buffer53 = require("buffer");
|
|
12447
13547
|
|
|
12448
13548
|
// src/client-core-helpers.ts
|
|
12449
|
-
var
|
|
13549
|
+
var import_node_buffer49 = require("buffer");
|
|
12450
13550
|
function bgsaveResponse(response) {
|
|
12451
|
-
if ((typeof response === "string" ||
|
|
13551
|
+
if ((typeof response === "string" || import_node_buffer49.Buffer.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
|
|
12452
13552
|
return true;
|
|
12453
13553
|
}
|
|
12454
13554
|
return okResponse(response);
|
|
@@ -12462,7 +13562,7 @@ function fetchOrComputeCompletionToken(options) {
|
|
|
12462
13562
|
"fetch-or-compute completion requires computeToken"
|
|
12463
13563
|
);
|
|
12464
13564
|
}
|
|
12465
|
-
if (!
|
|
13565
|
+
if (!import_node_buffer49.Buffer.isBuffer(options.computeToken)) {
|
|
12466
13566
|
throw new TypeError("fetch-or-compute computeToken must be a Buffer");
|
|
12467
13567
|
}
|
|
12468
13568
|
return options.computeToken;
|
|
@@ -12485,10 +13585,10 @@ function unsupportedClientCaching() {
|
|
|
12485
13585
|
}
|
|
12486
13586
|
|
|
12487
13587
|
// src/client-base.ts
|
|
12488
|
-
var
|
|
13588
|
+
var import_node_buffer51 = require("buffer");
|
|
12489
13589
|
|
|
12490
13590
|
// src/client-executor.ts
|
|
12491
|
-
var
|
|
13591
|
+
var import_node_buffer50 = require("buffer");
|
|
12492
13592
|
var ErrorMappingExecutor = class {
|
|
12493
13593
|
constructor(executor) {
|
|
12494
13594
|
this.executor = executor;
|
|
@@ -12548,12 +13648,12 @@ var ErrorMappingExecutor = class {
|
|
|
12548
13648
|
|
|
12549
13649
|
// src/client-config.ts
|
|
12550
13650
|
function snapshotClientOptions(options) {
|
|
12551
|
-
const
|
|
13651
|
+
const own2 = { ...options };
|
|
12552
13652
|
const snapshot = {
|
|
12553
|
-
...
|
|
12554
|
-
...typeof
|
|
12555
|
-
...
|
|
12556
|
-
...typeof
|
|
13653
|
+
...own2,
|
|
13654
|
+
...typeof own2.autoBatch === "object" && own2.autoBatch != null ? { autoBatch: Object.freeze({ ...own2.autoBatch }) } : {},
|
|
13655
|
+
...own2.backpressure == null ? {} : { backpressure: Object.freeze({ ...own2.backpressure }) },
|
|
13656
|
+
...typeof own2.reconnect === "object" && own2.reconnect != null ? { reconnect: Object.freeze({ ...own2.reconnect }) } : {}
|
|
12557
13657
|
};
|
|
12558
13658
|
return Object.freeze(snapshot);
|
|
12559
13659
|
}
|
|
@@ -12822,14 +13922,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
|
|
|
12822
13922
|
};
|
|
12823
13923
|
|
|
12824
13924
|
// src/store-utilities.ts
|
|
12825
|
-
var
|
|
13925
|
+
var import_node_buffer52 = require("buffer");
|
|
12826
13926
|
function encode(codec, value) {
|
|
12827
13927
|
return codec.encode(value);
|
|
12828
13928
|
}
|
|
12829
13929
|
function decode(codec, value) {
|
|
12830
13930
|
if (value == null) return null;
|
|
12831
|
-
if (
|
|
12832
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
13931
|
+
if (import_node_buffer52.Buffer.isBuffer(value)) return codec.decode(value);
|
|
13932
|
+
if (value instanceof Uint8Array) return codec.decode(import_node_buffer52.Buffer.from(value));
|
|
12833
13933
|
return value;
|
|
12834
13934
|
}
|
|
12835
13935
|
function number(value) {
|
|
@@ -14742,33 +15842,511 @@ var FerricStoreClientCore = class extends FerricStoreAdministrationClient {
|
|
|
14742
15842
|
}
|
|
14743
15843
|
};
|
|
14744
15844
|
|
|
14745
|
-
// src/
|
|
14746
|
-
var
|
|
14747
|
-
|
|
14748
|
-
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
|
|
14752
|
-
|
|
14753
|
-
|
|
14754
|
-
|
|
15845
|
+
// src/schedule-request.ts
|
|
15846
|
+
var MAX_EXACT_INTEGER = Number.MAX_SAFE_INTEGER;
|
|
15847
|
+
var SCHEDULE_KINDS = /* @__PURE__ */ new Set(["one_shot", "delay", "interval", "cron"]);
|
|
15848
|
+
var RECURRING_KINDS = /* @__PURE__ */ new Set(["interval", "cron"]);
|
|
15849
|
+
var OVERLAP_POLICIES = /* @__PURE__ */ new Set([
|
|
15850
|
+
"allow",
|
|
15851
|
+
"skip",
|
|
15852
|
+
"queue_after_previous",
|
|
15853
|
+
"fail_schedule"
|
|
15854
|
+
]);
|
|
15855
|
+
var SCHEDULE_STATES = /* @__PURE__ */ new Set([
|
|
15856
|
+
"active",
|
|
15857
|
+
"paused",
|
|
15858
|
+
"running",
|
|
15859
|
+
"completed",
|
|
15860
|
+
"failed",
|
|
15861
|
+
"cancelled",
|
|
15862
|
+
"all"
|
|
15863
|
+
]);
|
|
15864
|
+
var TARGET_FIELDS = /* @__PURE__ */ new Set([
|
|
15865
|
+
"correlation_id",
|
|
15866
|
+
"id",
|
|
15867
|
+
"id_prefix",
|
|
15868
|
+
"parent_flow_id",
|
|
15869
|
+
"partition_key",
|
|
15870
|
+
"payload",
|
|
15871
|
+
"payload_ref",
|
|
15872
|
+
"priority",
|
|
15873
|
+
"root_flow_id",
|
|
15874
|
+
"run_at_ms",
|
|
15875
|
+
"state",
|
|
15876
|
+
"type",
|
|
15877
|
+
"value_refs",
|
|
15878
|
+
"values"
|
|
15879
|
+
]);
|
|
15880
|
+
var TARGET_TEXT_FIELDS = [
|
|
15881
|
+
"state",
|
|
15882
|
+
"id",
|
|
15883
|
+
"id_prefix",
|
|
15884
|
+
"partition_key",
|
|
15885
|
+
"correlation_id",
|
|
15886
|
+
"parent_flow_id",
|
|
15887
|
+
"root_flow_id",
|
|
15888
|
+
"payload_ref"
|
|
15889
|
+
];
|
|
15890
|
+
var INTERNAL_SCHEDULE_TYPE = "__ferricstore_schedule";
|
|
15891
|
+
var INTERNAL_SCHEDULE_ID_PREFIX = "__ferricstore_schedule__:";
|
|
15892
|
+
function validateScheduleCreate(id, options) {
|
|
15893
|
+
requiredText3(id, "id");
|
|
15894
|
+
if (!mapping(options)) throw new TypeError("schedule options must be a mapping");
|
|
15895
|
+
const kind = effectiveKind(options);
|
|
15896
|
+
validateTiming(kind, options);
|
|
15897
|
+
const recurring = RECURRING_KINDS.has(kind);
|
|
15898
|
+
validateTarget(options.target, recurring);
|
|
15899
|
+
nonNegativeInteger2(options.atMs, "at_ms");
|
|
15900
|
+
nonNegativeInteger2(options.delayMs, "delay_ms");
|
|
15901
|
+
nonNegativeInteger2(options.startAtMs, "start_at_ms");
|
|
15902
|
+
positiveInteger2(options.everyMs, "every_ms");
|
|
15903
|
+
positiveInteger2(options.overlapRetryMs, "overlap_retry_ms");
|
|
15904
|
+
positiveInteger2(options.maxFires, "max_fires");
|
|
15905
|
+
nonNegativeInteger2(options.endAtMs, "end_at_ms");
|
|
15906
|
+
nonNegativeInteger2(options.nowMs, "now_ms");
|
|
15907
|
+
optionalBoolean(options.overwrite, "overwrite");
|
|
15908
|
+
if (kind === "delay") {
|
|
15909
|
+
if (options.delayMs == null) throw new TypeError("delay_ms is required for delay schedules");
|
|
15910
|
+
if (options.nowMs != null && options.nowMs > MAX_EXACT_INTEGER - options.delayMs) {
|
|
15911
|
+
throw new TypeError("now_ms plus delay_ms exceeds the exact integer range");
|
|
15912
|
+
}
|
|
15913
|
+
}
|
|
15914
|
+
if (kind === "interval" && options.everyMs == null) {
|
|
15915
|
+
throw new TypeError("every_ms is required for interval schedules");
|
|
15916
|
+
}
|
|
15917
|
+
if (kind === "cron") {
|
|
15918
|
+
requiredText3(options.cron, "cron");
|
|
15919
|
+
optionalText3(options.timezone, "timezone");
|
|
15920
|
+
} else if (options.timezone != null) {
|
|
15921
|
+
throw new TypeError("timezone is only supported for cron schedules");
|
|
15922
|
+
}
|
|
15923
|
+
if (kind === "interval") {
|
|
15924
|
+
if (options.catchupPolicy != null && options.catchupPolicy !== "fire_once") {
|
|
15925
|
+
throw new TypeError("catchup_policy must be fire_once");
|
|
15926
|
+
}
|
|
15927
|
+
} else if (options.catchupPolicy != null) {
|
|
15928
|
+
throw new TypeError("catchup_policy is only supported for interval schedules");
|
|
15929
|
+
}
|
|
15930
|
+
if (recurring) {
|
|
15931
|
+
if (options.overlapPolicy != null && !OVERLAP_POLICIES.has(options.overlapPolicy)) {
|
|
15932
|
+
throw new TypeError(
|
|
15933
|
+
"overlap_policy must be allow, skip, queue_after_previous, or fail_schedule"
|
|
15934
|
+
);
|
|
15935
|
+
}
|
|
15936
|
+
if (options.overlapRetryMs != null && options.overlapPolicy !== "queue_after_previous") {
|
|
15937
|
+
throw new TypeError("overlap_retry_ms requires overlap_policy queue_after_previous");
|
|
15938
|
+
}
|
|
15939
|
+
const firstRun = knownFirstRun(kind, options);
|
|
15940
|
+
if (options.endAtMs != null && firstRun != null && options.endAtMs < firstRun) {
|
|
15941
|
+
throw new TypeError("end_at_ms must be at or after first run");
|
|
15942
|
+
}
|
|
15943
|
+
} else {
|
|
15944
|
+
if (options.overlapPolicy != null) {
|
|
15945
|
+
throw new TypeError("overlap_policy is only supported for recurring schedules");
|
|
15946
|
+
}
|
|
15947
|
+
if (options.overlapRetryMs != null) {
|
|
15948
|
+
throw new TypeError("overlap_retry_ms requires overlap_policy queue_after_previous");
|
|
15949
|
+
}
|
|
15950
|
+
if (options.maxFires != null) {
|
|
15951
|
+
throw new TypeError("max_fires is only supported for recurring schedules");
|
|
15952
|
+
}
|
|
15953
|
+
if (options.endAtMs != null) {
|
|
15954
|
+
throw new TypeError("end_at_ms is only supported for recurring schedules");
|
|
15955
|
+
}
|
|
14755
15956
|
}
|
|
14756
|
-
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
15957
|
+
}
|
|
15958
|
+
function validateScheduleID(id) {
|
|
15959
|
+
requiredText3(id, "id");
|
|
15960
|
+
}
|
|
15961
|
+
function validateScheduleFire(id, options) {
|
|
15962
|
+
validateScheduleID(id);
|
|
15963
|
+
nonNegativeInteger2(options.fireAtMs, "fire_at_ms");
|
|
15964
|
+
nonNegativeInteger2(options.nowMs, "now_ms");
|
|
15965
|
+
}
|
|
15966
|
+
function validateScheduleStatus(id, nowMs2) {
|
|
15967
|
+
validateScheduleID(id);
|
|
15968
|
+
nonNegativeInteger2(nowMs2, "now_ms");
|
|
15969
|
+
}
|
|
15970
|
+
function validateScheduleFireDue(options) {
|
|
15971
|
+
if (!mapping(options)) throw new TypeError("schedule fire-due options must be a mapping");
|
|
15972
|
+
nonNegativeInteger2(options.nowMs, "now_ms");
|
|
15973
|
+
optionalText3(options.worker, "worker");
|
|
15974
|
+
positiveInteger2(options.leaseMs, "lease_ms");
|
|
15975
|
+
nonNegativeInteger2(options.blockMs, "block_ms");
|
|
15976
|
+
positiveInteger2(options.limit, "limit");
|
|
15977
|
+
const leaseMs = options.leaseMs ?? 3e4;
|
|
15978
|
+
if (options.nowMs != null && options.nowMs > MAX_EXACT_INTEGER - leaseMs) {
|
|
15979
|
+
throw new TypeError("now_ms plus lease_ms exceeds the exact integer range");
|
|
14760
15980
|
}
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
15981
|
+
}
|
|
15982
|
+
function validateScheduleList(options) {
|
|
15983
|
+
if (!mapping(options)) throw new TypeError("schedule list options must be a mapping");
|
|
15984
|
+
if (options.kind != null && !SCHEDULE_KINDS.has(options.kind)) {
|
|
15985
|
+
throw new TypeError("kind must be one_shot, delay, interval, or cron");
|
|
14765
15986
|
}
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
15987
|
+
if (options.state != null && !SCHEDULE_STATES.has(options.state)) {
|
|
15988
|
+
throw new TypeError("state is invalid");
|
|
15989
|
+
}
|
|
15990
|
+
optionalText3(options.timezone, "timezone");
|
|
15991
|
+
optionalText3(options.targetType, "target_type");
|
|
15992
|
+
nonNegativeInteger2(options.fromMs, "from_ms");
|
|
15993
|
+
nonNegativeInteger2(options.toMs, "to_ms");
|
|
15994
|
+
if (options.fromMs != null && options.toMs != null && options.fromMs > options.toMs) {
|
|
15995
|
+
throw new TypeError("from_ms must not exceed to_ms");
|
|
15996
|
+
}
|
|
15997
|
+
positiveInteger2(options.count, "count");
|
|
15998
|
+
optionalBoolean(options.rev, "rev");
|
|
15999
|
+
}
|
|
16000
|
+
function effectiveKind(options) {
|
|
16001
|
+
if (options.kind != null) {
|
|
16002
|
+
if (!SCHEDULE_KINDS.has(options.kind)) {
|
|
16003
|
+
throw new TypeError("kind must be one_shot, delay, interval, or cron");
|
|
16004
|
+
}
|
|
16005
|
+
return options.kind;
|
|
16006
|
+
}
|
|
16007
|
+
if (options.cron != null) return "cron";
|
|
16008
|
+
if (options.everyMs != null) return "interval";
|
|
16009
|
+
if (options.delayMs != null) return "delay";
|
|
16010
|
+
return "one_shot";
|
|
16011
|
+
}
|
|
16012
|
+
function validateTiming(kind, options) {
|
|
16013
|
+
if (options.atMs != null && options.startAtMs != null) {
|
|
16014
|
+
throw new TypeError("cannot set both at_ms and start_at_ms");
|
|
16015
|
+
}
|
|
16016
|
+
if (options.delayMs != null && kind !== "delay") {
|
|
16017
|
+
throw new TypeError("delay_ms is only supported for delay schedules");
|
|
16018
|
+
}
|
|
16019
|
+
if (options.everyMs != null && kind !== "interval") {
|
|
16020
|
+
throw new TypeError("every_ms is only supported for interval schedules");
|
|
16021
|
+
}
|
|
16022
|
+
if (options.cron != null && kind !== "cron") {
|
|
16023
|
+
throw new TypeError("cron is only supported for cron schedules");
|
|
16024
|
+
}
|
|
16025
|
+
if (kind === "delay" && (options.atMs != null || options.startAtMs != null)) {
|
|
16026
|
+
throw new TypeError("at_ms and start_at_ms are not supported for delay schedules");
|
|
16027
|
+
}
|
|
16028
|
+
}
|
|
16029
|
+
function validateTarget(value, recurring) {
|
|
16030
|
+
if (!mapping(value)) throw new TypeError("target must be a mapping with a non-empty type");
|
|
16031
|
+
const target = value;
|
|
16032
|
+
for (const key of Object.keys(target)) {
|
|
16033
|
+
if (!TARGET_FIELDS.has(key)) throw new TypeError(`target contains unknown field ${key}`);
|
|
14770
16034
|
}
|
|
16035
|
+
const type = own(target, "type");
|
|
16036
|
+
requiredText3(type, "target type");
|
|
16037
|
+
if (type === INTERNAL_SCHEDULE_TYPE) {
|
|
16038
|
+
throw new TypeError("target type is reserved for internal use");
|
|
16039
|
+
}
|
|
16040
|
+
for (const key of TARGET_TEXT_FIELDS) optionalText3(own(target, key), `target ${key}`);
|
|
16041
|
+
const id = own(target, "id");
|
|
16042
|
+
const idPrefix = own(target, "id_prefix");
|
|
16043
|
+
if (id != null && idPrefix != null) {
|
|
16044
|
+
throw new TypeError("target cannot set both id and id_prefix");
|
|
16045
|
+
}
|
|
16046
|
+
if (recurring && id != null) {
|
|
16047
|
+
throw new TypeError("target id is not supported for recurring schedules; use id_prefix");
|
|
16048
|
+
}
|
|
16049
|
+
if (typeof id === "string" && id.startsWith(INTERNAL_SCHEDULE_ID_PREFIX)) {
|
|
16050
|
+
throw new TypeError("target id is reserved for internal use");
|
|
16051
|
+
}
|
|
16052
|
+
if (typeof idPrefix === "string" && idPrefix.startsWith(INTERNAL_SCHEDULE_ID_PREFIX)) {
|
|
16053
|
+
throw new TypeError("target id_prefix is reserved for internal use");
|
|
16054
|
+
}
|
|
16055
|
+
nonNegativeInteger2(own(target, "run_at_ms"), "target run_at_ms");
|
|
16056
|
+
const priority = own(target, "priority");
|
|
16057
|
+
if (priority != null && (typeof priority !== "number" || !Number.isSafeInteger(priority) || priority < 0 || priority > 2)) {
|
|
16058
|
+
throw new TypeError("target priority must be an integer between 0 and 2");
|
|
16059
|
+
}
|
|
16060
|
+
}
|
|
16061
|
+
function knownFirstRun(kind, options) {
|
|
16062
|
+
if (kind === "delay") {
|
|
16063
|
+
if (options.nowMs == null || options.delayMs == null) return void 0;
|
|
16064
|
+
return options.nowMs + options.delayMs;
|
|
16065
|
+
}
|
|
16066
|
+
if (kind === "cron") return options.startAtMs ?? options.atMs ?? options.nowMs;
|
|
16067
|
+
return options.atMs ?? options.startAtMs ?? options.nowMs;
|
|
16068
|
+
}
|
|
16069
|
+
function requiredText3(value, name) {
|
|
16070
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
16071
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
16072
|
+
}
|
|
16073
|
+
}
|
|
16074
|
+
function optionalText3(value, name) {
|
|
16075
|
+
if (value != null) requiredText3(value, name);
|
|
16076
|
+
}
|
|
16077
|
+
function nonNegativeInteger2(value, name) {
|
|
16078
|
+
if (value != null && (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)) {
|
|
16079
|
+
throw new TypeError(`${name} must be a non-negative exact integer`);
|
|
16080
|
+
}
|
|
16081
|
+
}
|
|
16082
|
+
function positiveInteger2(value, name) {
|
|
16083
|
+
if (value != null && (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0)) {
|
|
16084
|
+
throw new TypeError(`${name} must be a positive exact integer`);
|
|
16085
|
+
}
|
|
16086
|
+
}
|
|
16087
|
+
function optionalBoolean(value, name) {
|
|
16088
|
+
if (value != null && typeof value !== "boolean") {
|
|
16089
|
+
throw new TypeError(`${name} must be a boolean`);
|
|
16090
|
+
}
|
|
16091
|
+
}
|
|
16092
|
+
function mapping(value) {
|
|
16093
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16094
|
+
}
|
|
16095
|
+
function own(mapping2, key) {
|
|
16096
|
+
return Object.prototype.hasOwnProperty.call(mapping2, key) ? mapping2[key] : void 0;
|
|
16097
|
+
}
|
|
16098
|
+
|
|
16099
|
+
// src/schedule-response.ts
|
|
16100
|
+
var SCHEDULE_INTEGER_FIELDS = [
|
|
16101
|
+
"end_at_ms",
|
|
16102
|
+
"last_catchup_at_ms",
|
|
16103
|
+
"last_fire_at_ms",
|
|
16104
|
+
"last_overlap_at_ms",
|
|
16105
|
+
"last_skipped_at_ms",
|
|
16106
|
+
"max_fires",
|
|
16107
|
+
"next_run_at_ms",
|
|
16108
|
+
"overlap_queued_due_at_ms"
|
|
16109
|
+
];
|
|
16110
|
+
var REQUIRED_SCHEDULE_INTEGER_FIELDS = [
|
|
16111
|
+
"attempts",
|
|
16112
|
+
"coalesced_count",
|
|
16113
|
+
"fire_count",
|
|
16114
|
+
"last_coalesced_count",
|
|
16115
|
+
"skipped_count"
|
|
16116
|
+
];
|
|
16117
|
+
var OPTIONAL_SCHEDULE_TEXT_FIELDS = [
|
|
16118
|
+
"cron",
|
|
16119
|
+
"end_reason",
|
|
16120
|
+
"flow_id",
|
|
16121
|
+
"last_overlap_reason",
|
|
16122
|
+
"last_overlap_target_id",
|
|
16123
|
+
"last_planning_error",
|
|
16124
|
+
"last_target_id",
|
|
16125
|
+
"timezone"
|
|
16126
|
+
];
|
|
16127
|
+
var SCHEDULE_KINDS2 = /* @__PURE__ */ new Set(["one_shot", "delay", "interval", "cron"]);
|
|
16128
|
+
var SCHEDULE_STATES2 = /* @__PURE__ */ new Set([
|
|
16129
|
+
"active",
|
|
16130
|
+
"paused",
|
|
16131
|
+
"running",
|
|
16132
|
+
"completed",
|
|
16133
|
+
"failed",
|
|
16134
|
+
"cancelled"
|
|
16135
|
+
]);
|
|
16136
|
+
var SCHEDULE_OVERLAP_POLICIES = /* @__PURE__ */ new Set([
|
|
16137
|
+
"allow",
|
|
16138
|
+
"skip",
|
|
16139
|
+
"queue_after_previous",
|
|
16140
|
+
"fail_schedule"
|
|
16141
|
+
]);
|
|
16142
|
+
function scheduleRecordResponse(value, context) {
|
|
16143
|
+
const record = adminRecordResponse(value, context);
|
|
16144
|
+
if (typeof record.id !== "string" || record.id.length === 0) {
|
|
16145
|
+
throw new TypeError(`${context} response missing id`);
|
|
16146
|
+
}
|
|
16147
|
+
if (typeof record.kind !== "string" || !SCHEDULE_KINDS2.has(record.kind)) {
|
|
16148
|
+
throw new TypeError(`${context} response missing or invalid kind`);
|
|
16149
|
+
}
|
|
16150
|
+
if (typeof record.state !== "string" || !SCHEDULE_STATES2.has(record.state)) {
|
|
16151
|
+
throw new TypeError(`${context} response missing or invalid state`);
|
|
16152
|
+
}
|
|
16153
|
+
if (typeof record.target !== "object" || record.target == null || Array.isArray(record.target)) {
|
|
16154
|
+
throw new TypeError(`${context} response missing or invalid target`);
|
|
16155
|
+
}
|
|
16156
|
+
const target = record.target;
|
|
16157
|
+
if (typeof target.type !== "string" || target.type.length === 0) {
|
|
16158
|
+
throw new TypeError(`${context} response missing or invalid target type`);
|
|
16159
|
+
}
|
|
16160
|
+
if (!("catchup_policy" in record) || record.kind === "interval" && record.catchup_policy !== "fire_once" || record.kind !== "interval" && record.catchup_policy != null) {
|
|
16161
|
+
throw new TypeError(`${context} returned an invalid catchup_policy`);
|
|
16162
|
+
}
|
|
16163
|
+
if (typeof record.overlap_policy !== "string" || !SCHEDULE_OVERLAP_POLICIES.has(record.overlap_policy)) {
|
|
16164
|
+
throw new TypeError(`${context} response missing or invalid overlap_policy`);
|
|
16165
|
+
}
|
|
16166
|
+
safeNonNegativeInteger(record, "created_at_ms", context, true);
|
|
16167
|
+
const everyMs = requiredNullableNonNegativeInteger(record, "every_ms", context);
|
|
16168
|
+
const cron = requiredNullableResponseText(record, "cron", context);
|
|
16169
|
+
const timezone = requiredNullableResponseText(record, "timezone", context);
|
|
16170
|
+
const overlapRetryMs = requiredNullableNonNegativeInteger(
|
|
16171
|
+
record,
|
|
16172
|
+
"overlap_retry_ms",
|
|
16173
|
+
context
|
|
16174
|
+
);
|
|
16175
|
+
validateRecurrence(record, context, everyMs, cron, timezone, overlapRetryMs);
|
|
16176
|
+
let coalescedCount = 0;
|
|
16177
|
+
let lastCoalescedCount = 0;
|
|
16178
|
+
for (const field3 of REQUIRED_SCHEDULE_INTEGER_FIELDS) {
|
|
16179
|
+
const value2 = safeNonNegativeInteger(record, field3, context, true);
|
|
16180
|
+
if (field3 === "coalesced_count") coalescedCount = value2;
|
|
16181
|
+
if (field3 === "last_coalesced_count") lastCoalescedCount = value2;
|
|
16182
|
+
}
|
|
16183
|
+
for (const field3 of SCHEDULE_INTEGER_FIELDS) {
|
|
16184
|
+
if (record[field3] != null) safeNonNegativeInteger(record, field3, context);
|
|
16185
|
+
}
|
|
16186
|
+
for (const field3 of OPTIONAL_SCHEDULE_TEXT_FIELDS) {
|
|
16187
|
+
optionalResponseText(record, field3, context);
|
|
16188
|
+
}
|
|
16189
|
+
validateCatchupState(record, context, coalescedCount, lastCoalescedCount);
|
|
16190
|
+
return record;
|
|
16191
|
+
}
|
|
16192
|
+
function validateRecurrence(record, context, everyMs, cron, timezone, overlapRetryMs) {
|
|
16193
|
+
if (record.kind === "interval") {
|
|
16194
|
+
if (everyMs == null || everyMs <= 0) {
|
|
16195
|
+
throw new TypeError(`${context} interval every_ms must be positive`);
|
|
16196
|
+
}
|
|
16197
|
+
} else if (everyMs != null) {
|
|
16198
|
+
throw new TypeError(`${context} every_ms is only valid for interval schedules`);
|
|
16199
|
+
}
|
|
16200
|
+
if (record.kind === "cron") {
|
|
16201
|
+
if (cron == null) throw new TypeError(`${context} cron schedule is missing cron`);
|
|
16202
|
+
if (timezone == null) throw new TypeError(`${context} cron schedule is missing timezone`);
|
|
16203
|
+
} else if (cron != null) {
|
|
16204
|
+
throw new TypeError(`${context} cron is only valid for cron schedules`);
|
|
16205
|
+
} else if (timezone != null) {
|
|
16206
|
+
throw new TypeError(`${context} timezone is only valid for cron schedules`);
|
|
16207
|
+
}
|
|
16208
|
+
if (record.kind !== "interval" && record.kind !== "cron" && record.overlap_policy !== "allow") {
|
|
16209
|
+
throw new TypeError(`${context} overlap_policy is only valid for recurring schedules`);
|
|
16210
|
+
}
|
|
16211
|
+
if (overlapRetryMs != null) {
|
|
16212
|
+
if (overlapRetryMs <= 0) {
|
|
16213
|
+
throw new TypeError(`${context} overlap_retry_ms must be positive`);
|
|
16214
|
+
}
|
|
16215
|
+
if (record.overlap_policy !== "queue_after_previous") {
|
|
16216
|
+
throw new TypeError(`${context} overlap_retry_ms requires queue_after_previous`);
|
|
16217
|
+
}
|
|
16218
|
+
}
|
|
16219
|
+
}
|
|
16220
|
+
function validateCatchupState(record, context, coalescedCount, lastCoalescedCount) {
|
|
16221
|
+
const lastCatchupAt = record.last_catchup_at_ms;
|
|
16222
|
+
if (record.kind !== "interval") {
|
|
16223
|
+
if (coalescedCount !== 0) {
|
|
16224
|
+
throw new TypeError(`${context} non-interval coalesced_count must be zero`);
|
|
16225
|
+
}
|
|
16226
|
+
if (lastCoalescedCount !== 0) {
|
|
16227
|
+
throw new TypeError(`${context} non-interval last_coalesced_count must be zero`);
|
|
16228
|
+
}
|
|
16229
|
+
if (lastCatchupAt != null) {
|
|
16230
|
+
throw new TypeError(`${context} non-interval last_catchup_at_ms must be null`);
|
|
16231
|
+
}
|
|
16232
|
+
return;
|
|
16233
|
+
}
|
|
16234
|
+
if (lastCoalescedCount > coalescedCount) {
|
|
16235
|
+
throw new TypeError(`${context} last_coalesced_count exceeds coalesced_count`);
|
|
16236
|
+
}
|
|
16237
|
+
if (lastCoalescedCount > 0 && lastCatchupAt == null) {
|
|
16238
|
+
throw new TypeError(`${context} response missing last_catchup_at_ms after catch-up`);
|
|
16239
|
+
}
|
|
16240
|
+
if (lastCoalescedCount === 0 && lastCatchupAt != null) {
|
|
16241
|
+
throw new TypeError(`${context} last_catchup_at_ms requires a catch-up`);
|
|
16242
|
+
}
|
|
16243
|
+
}
|
|
16244
|
+
function optionalScheduleRecord(value, context) {
|
|
16245
|
+
return value == null ? null : scheduleRecordResponse(value, context);
|
|
16246
|
+
}
|
|
16247
|
+
function scheduleRecordList(value, context) {
|
|
16248
|
+
return arrayResponse(value).map((item) => scheduleRecordResponse(item, context));
|
|
16249
|
+
}
|
|
16250
|
+
function scheduleFireDueResponse(value) {
|
|
16251
|
+
const context = "FLOW.SCHEDULE.FIRE_DUE";
|
|
16252
|
+
const record = adminRecordResponse(value, context);
|
|
16253
|
+
const claimed = safeNonNegativeInteger(record, "claimed", context, true);
|
|
16254
|
+
const fired = safeNonNegativeInteger(record, "fired", context, true);
|
|
16255
|
+
const skipped = safeNonNegativeInteger(record, "skipped", context, true);
|
|
16256
|
+
const coalesced = safeNonNegativeInteger(record, "coalesced", context, true);
|
|
16257
|
+
if (!Array.isArray(record.errors)) {
|
|
16258
|
+
throw new TypeError(`${context} response missing errors`);
|
|
16259
|
+
}
|
|
16260
|
+
for (const error of record.errors) {
|
|
16261
|
+
if (!Array.isArray(error) || error.length !== 2 || typeof error[0] !== "string" || error[0].length === 0 || typeof error[1] !== "string" || error[1].length === 0) {
|
|
16262
|
+
throw new TypeError(`${context} returned an invalid error entry`);
|
|
16263
|
+
}
|
|
16264
|
+
}
|
|
16265
|
+
if (fired + skipped + record.errors.length !== claimed) {
|
|
16266
|
+
throw new TypeError(`${context} outcomes do not equal claimed`);
|
|
16267
|
+
}
|
|
16268
|
+
optionalResponseText(record, "claim_error", context);
|
|
16269
|
+
const lastTargetId = optionalResponseText(record, "last_target_id", context);
|
|
16270
|
+
const lastSkipReason = optionalResponseText(record, "last_skip_reason", context);
|
|
16271
|
+
if (fired > 0 && lastTargetId == null) {
|
|
16272
|
+
throw new TypeError(`${context} response missing last_target_id`);
|
|
16273
|
+
}
|
|
16274
|
+
if (fired === 0 && lastTargetId != null) {
|
|
16275
|
+
throw new TypeError(`${context} last_target_id requires a fired outcome`);
|
|
16276
|
+
}
|
|
16277
|
+
if (skipped > 0 && lastSkipReason == null) {
|
|
16278
|
+
throw new TypeError(`${context} response missing last_skip_reason`);
|
|
16279
|
+
}
|
|
16280
|
+
if (skipped === 0 && lastSkipReason != null) {
|
|
16281
|
+
throw new TypeError(`${context} last_skip_reason requires a skipped outcome`);
|
|
16282
|
+
}
|
|
16283
|
+
if (coalesced > 0 && fired + skipped === 0) {
|
|
16284
|
+
throw new TypeError(`${context} coalesced count requires a fired or skipped outcome`);
|
|
16285
|
+
}
|
|
16286
|
+
return record;
|
|
16287
|
+
}
|
|
16288
|
+
function scheduleFireResponse(value) {
|
|
16289
|
+
const context = "FLOW.SCHEDULE.FIRE";
|
|
16290
|
+
const record = adminRecordResponse(value, context);
|
|
16291
|
+
const schedule = scheduleRecordResponse(record.schedule, `${context} schedule`);
|
|
16292
|
+
const fired = safeNonNegativeInteger(record, "fired", context, true);
|
|
16293
|
+
const skipped = record.skipped == null ? 0 : safeNonNegativeInteger(record, "skipped", context);
|
|
16294
|
+
if (fired > 1 || skipped > 1 || fired + skipped !== 1) {
|
|
16295
|
+
throw new TypeError(`${context} outcomes must equal one`);
|
|
16296
|
+
}
|
|
16297
|
+
if (fired === 1 && (typeof record.target_id !== "string" || record.target_id.length === 0)) {
|
|
16298
|
+
throw new TypeError(`${context} response missing target_id`);
|
|
16299
|
+
}
|
|
16300
|
+
if (skipped === 1 && (typeof record.reason !== "string" || record.reason.length === 0)) {
|
|
16301
|
+
throw new TypeError(`${context} response missing reason`);
|
|
16302
|
+
}
|
|
16303
|
+
if (fired === 0 && record.target_id != null) {
|
|
16304
|
+
throw new TypeError(`${context} target_id requires a fired outcome`);
|
|
16305
|
+
}
|
|
16306
|
+
if (skipped === 0 && record.reason != null) {
|
|
16307
|
+
throw new TypeError(`${context} reason requires a skipped outcome`);
|
|
16308
|
+
}
|
|
16309
|
+
return { ...record, fired, skipped, schedule };
|
|
16310
|
+
}
|
|
16311
|
+
function optionalResponseText(record, field3, context) {
|
|
16312
|
+
const value = record[field3];
|
|
16313
|
+
if (value == null) return void 0;
|
|
16314
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
16315
|
+
throw new TypeError(`${context} ${field3} must be non-empty text`);
|
|
16316
|
+
}
|
|
16317
|
+
return value;
|
|
16318
|
+
}
|
|
16319
|
+
function requiredNullableResponseText(record, field3, context) {
|
|
16320
|
+
if (!(field3 in record)) throw new TypeError(`${context} response missing ${field3}`);
|
|
16321
|
+
if (record[field3] === void 0) {
|
|
16322
|
+
throw new TypeError(`${context} response missing ${field3}`);
|
|
16323
|
+
}
|
|
16324
|
+
return optionalResponseText(record, field3, context) ?? null;
|
|
16325
|
+
}
|
|
16326
|
+
function requiredNullableNonNegativeInteger(record, field3, context) {
|
|
16327
|
+
if (!(field3 in record)) throw new TypeError(`${context} response missing ${field3}`);
|
|
16328
|
+
if (record[field3] === void 0) {
|
|
16329
|
+
throw new TypeError(`${context} response missing ${field3}`);
|
|
16330
|
+
}
|
|
16331
|
+
if (record[field3] === null) return null;
|
|
16332
|
+
return safeNonNegativeInteger(record, field3, context);
|
|
16333
|
+
}
|
|
16334
|
+
function safeNonNegativeInteger(record, field3, context, required = false) {
|
|
16335
|
+
if (!(field3 in record) || record[field3] == null) {
|
|
16336
|
+
if (required) throw new TypeError(`${context} response missing ${field3}`);
|
|
16337
|
+
return 0;
|
|
16338
|
+
}
|
|
16339
|
+
const value = record[field3];
|
|
16340
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
16341
|
+
throw new TypeError(`${context} ${field3} must be a safe non-negative integer`);
|
|
16342
|
+
}
|
|
16343
|
+
return value;
|
|
16344
|
+
}
|
|
16345
|
+
|
|
16346
|
+
// src/client-schedules.ts
|
|
16347
|
+
var FerricStoreScheduleClient = class extends FerricStoreClientCore {
|
|
14771
16348
|
async scheduleCreate(id, options) {
|
|
16349
|
+
validateScheduleCreate(id, options);
|
|
14772
16350
|
const args = ["FLOW.SCHEDULE.CREATE", id];
|
|
14773
16351
|
append(args, "KIND", options.kind);
|
|
14774
16352
|
append(args, "AT_MS", options.atMs);
|
|
@@ -14778,6 +16356,7 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
|
|
|
14778
16356
|
append(args, "CRON", options.cron);
|
|
14779
16357
|
append(args, "TIMEZONE", options.timezone);
|
|
14780
16358
|
append(args, "TARGET", options.target);
|
|
16359
|
+
append(args, "CATCHUP_POLICY", options.catchupPolicy);
|
|
14781
16360
|
append(args, "OVERLAP_POLICY", options.overlapPolicy);
|
|
14782
16361
|
append(args, "OVERLAP_RETRY_MS", options.overlapRetryMs);
|
|
14783
16362
|
append(args, "MAX_FIRES", options.maxFires);
|
|
@@ -14787,34 +16366,55 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
|
|
|
14787
16366
|
for (const [name, value] of Object.entries(options.extraOptions ?? {})) {
|
|
14788
16367
|
args.push(name.toUpperCase(), value);
|
|
14789
16368
|
}
|
|
14790
|
-
return
|
|
16369
|
+
return scheduleRecordResponse(await this.commandArgs(args), "FLOW.SCHEDULE.CREATE");
|
|
14791
16370
|
}
|
|
14792
|
-
async scheduleGet(id
|
|
14793
|
-
|
|
14794
|
-
|
|
14795
|
-
|
|
16371
|
+
async scheduleGet(id) {
|
|
16372
|
+
validateScheduleID(id);
|
|
16373
|
+
return optionalScheduleRecord(
|
|
16374
|
+
await this.commandArgs(["FLOW.SCHEDULE.GET", id]),
|
|
16375
|
+
"FLOW.SCHEDULE.GET"
|
|
16376
|
+
);
|
|
14796
16377
|
}
|
|
14797
16378
|
async scheduleFire(id, options = {}) {
|
|
14798
|
-
|
|
16379
|
+
validateScheduleFire(id, options);
|
|
16380
|
+
const args = ["FLOW.SCHEDULE.FIRE", id];
|
|
16381
|
+
append(args, "FIRE_AT_MS", options.fireAtMs);
|
|
16382
|
+
append(args, "NOW", options.nowMs);
|
|
16383
|
+
return scheduleFireResponse(await this.commandArgs(args));
|
|
14799
16384
|
}
|
|
14800
16385
|
async schedulePause(id, options = {}) {
|
|
14801
|
-
|
|
16386
|
+
validateScheduleStatus(id, options.nowMs);
|
|
16387
|
+
return scheduleRecordResponse(
|
|
16388
|
+
await this.scheduleStatusResponse("FLOW.SCHEDULE.PAUSE", id, options.nowMs),
|
|
16389
|
+
"FLOW.SCHEDULE.PAUSE"
|
|
16390
|
+
);
|
|
14802
16391
|
}
|
|
14803
16392
|
async scheduleResume(id, options = {}) {
|
|
14804
|
-
|
|
16393
|
+
validateScheduleStatus(id, options.nowMs);
|
|
16394
|
+
return scheduleRecordResponse(
|
|
16395
|
+
await this.scheduleStatusResponse("FLOW.SCHEDULE.RESUME", id, options.nowMs),
|
|
16396
|
+
"FLOW.SCHEDULE.RESUME"
|
|
16397
|
+
);
|
|
14805
16398
|
}
|
|
14806
16399
|
async scheduleDelete(id, options = {}) {
|
|
14807
|
-
|
|
16400
|
+
validateScheduleStatus(id, options.nowMs);
|
|
16401
|
+
const response = await this.scheduleStatusResponse("FLOW.SCHEDULE.DELETE", id, options.nowMs);
|
|
16402
|
+
if (!okLike(response)) {
|
|
16403
|
+
throw new TypeError("FLOW.SCHEDULE.DELETE response must be OK");
|
|
16404
|
+
}
|
|
14808
16405
|
}
|
|
14809
16406
|
async scheduleFireDue(options = {}) {
|
|
16407
|
+
validateScheduleFireDue(options);
|
|
14810
16408
|
const args = ["FLOW.SCHEDULE.FIRE_DUE"];
|
|
14811
16409
|
append(args, "NOW", options.nowMs);
|
|
14812
16410
|
append(args, "WORKER", options.worker);
|
|
16411
|
+
append(args, "LEASE_MS", options.leaseMs);
|
|
14813
16412
|
append(args, "BLOCK", options.blockMs);
|
|
14814
16413
|
append(args, "LIMIT", options.limit);
|
|
14815
|
-
return
|
|
16414
|
+
return scheduleFireDueResponse(await this.commandArgs(args));
|
|
14816
16415
|
}
|
|
14817
16416
|
async scheduleList(options = {}) {
|
|
16417
|
+
validateScheduleList(options);
|
|
14818
16418
|
const args = ["FLOW.SCHEDULE.LIST"];
|
|
14819
16419
|
append(args, "KIND", options.kind);
|
|
14820
16420
|
append(args, "STATE", options.state);
|
|
@@ -14824,14 +16424,40 @@ var FerricStoreManagementClient = class extends FerricStoreClientCore {
|
|
|
14824
16424
|
append(args, "TO_MS", options.toMs);
|
|
14825
16425
|
append(args, "COUNT", options.count);
|
|
14826
16426
|
appendBool(args, "REV", options.rev);
|
|
14827
|
-
return
|
|
16427
|
+
return scheduleRecordList(await this.commandArgs(args), "FLOW.SCHEDULE.LIST");
|
|
14828
16428
|
}
|
|
14829
|
-
async
|
|
16429
|
+
async scheduleStatusResponse(command, id, now) {
|
|
14830
16430
|
const args = [command, id];
|
|
14831
16431
|
append(args, "NOW", now);
|
|
14832
|
-
|
|
14833
|
-
|
|
14834
|
-
|
|
16432
|
+
return await this.commandArgs(args);
|
|
16433
|
+
}
|
|
16434
|
+
};
|
|
16435
|
+
|
|
16436
|
+
// src/client-management.ts
|
|
16437
|
+
var FerricStoreManagementClient = class extends FerricStoreScheduleClient {
|
|
16438
|
+
async stats(type, options = {}) {
|
|
16439
|
+
const args = ["FLOW.STATS", type];
|
|
16440
|
+
append(args, "STATE", options.state);
|
|
16441
|
+
append(args, "COUNT", options.count);
|
|
16442
|
+
append(args, "PARTITION", options.partitionKey);
|
|
16443
|
+
appendAttributes(args, options.attributes);
|
|
16444
|
+
appendBool(args, "CONSISTENT_PROJECTION", options.consistentProjection);
|
|
16445
|
+
return adminRecordResponse(await this.commandArgs(args), "FLOW.STATS");
|
|
16446
|
+
}
|
|
16447
|
+
async countByState(type, state, options = {}) {
|
|
16448
|
+
const stats = await this.stats(type, { ...options, state });
|
|
16449
|
+
if (!("count" in stats)) throw new TypeError("FLOW.STATS response missing count");
|
|
16450
|
+
return integer(stats.count);
|
|
16451
|
+
}
|
|
16452
|
+
async attributes(type, options = {}) {
|
|
16453
|
+
const args = ["FLOW.ATTRIBUTES", type];
|
|
16454
|
+
appendAttributeQueryOptions(args, options);
|
|
16455
|
+
return adminRecordList(await this.commandArgs(args), "FLOW.ATTRIBUTES");
|
|
16456
|
+
}
|
|
16457
|
+
async attributeValues(type, attribute, options = {}) {
|
|
16458
|
+
const args = ["FLOW.ATTRIBUTE_VALUES", type, attribute];
|
|
16459
|
+
appendAttributeQueryOptions(args, options);
|
|
16460
|
+
return adminRecordList(await this.commandArgs(args), "FLOW.ATTRIBUTE_VALUES");
|
|
14835
16461
|
}
|
|
14836
16462
|
async effectReserve(id, effectKey, effectType, options) {
|
|
14837
16463
|
const args = [
|
|
@@ -15064,7 +16690,7 @@ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
|
|
|
15064
16690
|
args.push(indexId);
|
|
15065
16691
|
}
|
|
15066
16692
|
try {
|
|
15067
|
-
return decodeFlowQueryIndexStatus(await this.commandArgs(args));
|
|
16693
|
+
return decodeFlowQueryIndexStatus(await this.commandArgs(args), indexId);
|
|
15068
16694
|
} catch (error) {
|
|
15069
16695
|
this.throwFlowQueryError(error);
|
|
15070
16696
|
}
|
|
@@ -15126,7 +16752,7 @@ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
|
|
|
15126
16752
|
if (hasFlowExplainPrefix(query)) {
|
|
15127
16753
|
throw new TypeError("query already contains an EXPLAIN prefix");
|
|
15128
16754
|
}
|
|
15129
|
-
return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query
|
|
16755
|
+
return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query, params));
|
|
15130
16756
|
}
|
|
15131
16757
|
throwFlowQueryError(error) {
|
|
15132
16758
|
if (error instanceof FerricStoreError) {
|
|
@@ -15159,7 +16785,7 @@ function throwIfClosed(signal) {
|
|
|
15159
16785
|
}
|
|
15160
16786
|
|
|
15161
16787
|
// src/flow-policy.ts
|
|
15162
|
-
var
|
|
16788
|
+
var import_node_buffer54 = require("buffer");
|
|
15163
16789
|
var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
|
|
15164
16790
|
function assertFlowPolicyGeneration(value) {
|
|
15165
16791
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
@@ -15169,15 +16795,15 @@ function assertFlowPolicyGeneration(value) {
|
|
|
15169
16795
|
function flowPolicySnapshotFromResp(value) {
|
|
15170
16796
|
const policy = requiredRecord(value, "FLOW policy snapshot");
|
|
15171
16797
|
const maxActiveMs = optionalPositiveInteger(field(policy, "max_active_ms"), "max_active_ms");
|
|
15172
|
-
const state =
|
|
16798
|
+
const state = optionalText4(field(policy, "state"), "state");
|
|
15173
16799
|
const mode = optionalMode(field(policy, "mode"), "mode");
|
|
15174
16800
|
const version = optionalVersion(field(policy, "version"));
|
|
15175
|
-
const indexedStateMeta =
|
|
16801
|
+
const indexedStateMeta = optionalText4(field(policy, "indexed_state_meta"), "indexed_state_meta");
|
|
15176
16802
|
const governance = optionalRecord(field(policy, "governance"), "governance");
|
|
15177
16803
|
const states = optionalStates(field(policy, "states"));
|
|
15178
16804
|
return {
|
|
15179
|
-
type:
|
|
15180
|
-
generation:
|
|
16805
|
+
type: requiredText4(field(policy, "type"), "type"),
|
|
16806
|
+
generation: nonNegativeInteger3(field(policy, "generation"), "generation"),
|
|
15181
16807
|
...state == null ? {} : { state },
|
|
15182
16808
|
...version == null ? {} : { version },
|
|
15183
16809
|
...mode == null ? {} : { mode },
|
|
@@ -15195,21 +16821,21 @@ function retrySnapshot(value, context) {
|
|
|
15195
16821
|
const retry2 = requiredRecord(value, `FLOW policy ${context}`);
|
|
15196
16822
|
const backoff = requiredRecord(field(retry2, "backoff"), `FLOW policy ${context}.backoff`);
|
|
15197
16823
|
return {
|
|
15198
|
-
maxRetries:
|
|
16824
|
+
maxRetries: nonNegativeInteger3(field(retry2, "max_retries"), `${context}.max_retries`),
|
|
15199
16825
|
backoff: {
|
|
15200
16826
|
kind: backoffKind(field(backoff, "kind"), `${context}.backoff.kind`),
|
|
15201
|
-
baseMs:
|
|
15202
|
-
maxMs:
|
|
15203
|
-
jitterPct:
|
|
16827
|
+
baseMs: nonNegativeInteger3(field(backoff, "base_ms"), `${context}.backoff.base_ms`),
|
|
16828
|
+
maxMs: nonNegativeInteger3(field(backoff, "max_ms"), `${context}.backoff.max_ms`),
|
|
16829
|
+
jitterPct: nonNegativeInteger3(field(backoff, "jitter_pct"), `${context}.backoff.jitter_pct`)
|
|
15204
16830
|
},
|
|
15205
|
-
exhaustedTo:
|
|
16831
|
+
exhaustedTo: requiredText4(field(retry2, "exhausted_to"), `${context}.exhausted_to`)
|
|
15206
16832
|
};
|
|
15207
16833
|
}
|
|
15208
16834
|
function retentionSnapshot(value, context) {
|
|
15209
16835
|
const retention = requiredRecord(value, `FLOW policy ${context}`);
|
|
15210
16836
|
return {
|
|
15211
|
-
ttlMs:
|
|
15212
|
-
historyMaxEvents:
|
|
16837
|
+
ttlMs: nonNegativeInteger3(field(retention, "ttl_ms"), `${context}.ttl_ms`),
|
|
16838
|
+
historyMaxEvents: nonNegativeInteger3(
|
|
15213
16839
|
field(retention, "history_max_events"),
|
|
15214
16840
|
`${context}.history_max_events`
|
|
15215
16841
|
)
|
|
@@ -15245,11 +16871,11 @@ function requiredRecord(value, context) {
|
|
|
15245
16871
|
if (value instanceof Map) {
|
|
15246
16872
|
const result = {};
|
|
15247
16873
|
for (const [key, item] of value.entries()) {
|
|
15248
|
-
setOwnValue(result,
|
|
16874
|
+
setOwnValue(result, requiredText4(key, `${context} key`), item);
|
|
15249
16875
|
}
|
|
15250
16876
|
return result;
|
|
15251
16877
|
}
|
|
15252
|
-
if (typeof value === "object" && value != null && !Array.isArray(value) && !
|
|
16878
|
+
if (typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer54.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return value;
|
|
15253
16879
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
15254
16880
|
}
|
|
15255
16881
|
function optionalRecord(value, context) {
|
|
@@ -15264,21 +16890,21 @@ function stringArray(value, context) {
|
|
|
15264
16890
|
if (!Object.hasOwn(value, index)) {
|
|
15265
16891
|
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
15266
16892
|
}
|
|
15267
|
-
result[index] =
|
|
16893
|
+
result[index] = requiredText4(value[index], `${context}[${index}]`);
|
|
15268
16894
|
}
|
|
15269
16895
|
return result;
|
|
15270
16896
|
}
|
|
15271
|
-
function
|
|
16897
|
+
function requiredText4(value, context) {
|
|
15272
16898
|
if (typeof value === "string") return value;
|
|
15273
|
-
if (
|
|
15274
|
-
return
|
|
16899
|
+
if (import_node_buffer54.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
16900
|
+
return import_node_buffer54.Buffer.from(value).toString("utf8");
|
|
15275
16901
|
}
|
|
15276
16902
|
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
15277
16903
|
}
|
|
15278
|
-
function
|
|
15279
|
-
return value == null ? void 0 :
|
|
16904
|
+
function optionalText4(value, context) {
|
|
16905
|
+
return value == null ? void 0 : requiredText4(value, context);
|
|
15280
16906
|
}
|
|
15281
|
-
function
|
|
16907
|
+
function nonNegativeInteger3(value, context) {
|
|
15282
16908
|
let parsed;
|
|
15283
16909
|
try {
|
|
15284
16910
|
parsed = integer(value);
|
|
@@ -15290,26 +16916,26 @@ function nonNegativeInteger2(value, context) {
|
|
|
15290
16916
|
}
|
|
15291
16917
|
function optionalPositiveInteger(value, context) {
|
|
15292
16918
|
if (value == null) return void 0;
|
|
15293
|
-
const parsed =
|
|
16919
|
+
const parsed = nonNegativeInteger3(value, context);
|
|
15294
16920
|
if (parsed === 0) throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
15295
16921
|
return parsed;
|
|
15296
16922
|
}
|
|
15297
16923
|
function optionalVersion(value) {
|
|
15298
16924
|
if (value == null) return void 0;
|
|
15299
16925
|
if (typeof value === "number" || typeof value === "bigint") {
|
|
15300
|
-
return
|
|
16926
|
+
return nonNegativeInteger3(value, "version");
|
|
15301
16927
|
}
|
|
15302
|
-
return
|
|
16928
|
+
return requiredText4(value, "version");
|
|
15303
16929
|
}
|
|
15304
16930
|
function backoffKind(value, context) {
|
|
15305
|
-
const kind =
|
|
16931
|
+
const kind = requiredText4(value, context).toLowerCase();
|
|
15306
16932
|
if (kind === "none" || kind === "fixed" || kind === "linear" || kind === "exponential") {
|
|
15307
16933
|
return kind;
|
|
15308
16934
|
}
|
|
15309
16935
|
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
15310
16936
|
}
|
|
15311
16937
|
function requiredMode(value, context) {
|
|
15312
|
-
const mode =
|
|
16938
|
+
const mode = requiredText4(value, context).toLowerCase();
|
|
15313
16939
|
if (mode === "fifo" || mode === "parallel") return mode;
|
|
15314
16940
|
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
15315
16941
|
}
|
|
@@ -15527,7 +17153,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreFlowQueryClient {
|
|
|
15527
17153
|
};
|
|
15528
17154
|
|
|
15529
17155
|
// src/flow-many-snapshot.ts
|
|
15530
|
-
var
|
|
17156
|
+
var import_node_buffer56 = require("buffer");
|
|
15531
17157
|
var encodedOptionFields = ["error", "payload", "reason", "result"];
|
|
15532
17158
|
function snapshotCreateItem(item, codec) {
|
|
15533
17159
|
const snapshot = {
|
|
@@ -15567,7 +17193,7 @@ function snapshotFlowManyOptions(options, codec) {
|
|
|
15567
17193
|
}
|
|
15568
17194
|
function snapshotClaimedItem(item) {
|
|
15569
17195
|
const wire = item[CLAIMED_ITEM_WIRE];
|
|
15570
|
-
const leaseToken =
|
|
17196
|
+
const leaseToken = import_node_buffer56.Buffer.from(wire?.leaseToken ?? item.leaseToken);
|
|
15571
17197
|
const snapshot = {
|
|
15572
17198
|
...item,
|
|
15573
17199
|
fencingToken: wire?.fencingToken ?? item.fencingToken,
|
|
@@ -15584,15 +17210,15 @@ function snapshotClaimedItem(item) {
|
|
|
15584
17210
|
function snapshotFencedItem(item) {
|
|
15585
17211
|
return Object.freeze({
|
|
15586
17212
|
...item,
|
|
15587
|
-
...item.leaseToken == null ? {} : { leaseToken:
|
|
17213
|
+
...item.leaseToken == null ? {} : { leaseToken: import_node_buffer56.Buffer.from(item.leaseToken) }
|
|
15588
17214
|
});
|
|
15589
17215
|
}
|
|
15590
17216
|
function snapshotClaimedItemWire(wire, leaseToken) {
|
|
15591
17217
|
return Object.freeze({
|
|
15592
17218
|
fencingToken: wire.fencingToken,
|
|
15593
|
-
id:
|
|
17219
|
+
id: import_node_buffer56.Buffer.from(wire.id),
|
|
15594
17220
|
leaseToken,
|
|
15595
|
-
partitionKey: wire.partitionKey == null ? wire.partitionKey :
|
|
17221
|
+
partitionKey: wire.partitionKey == null ? wire.partitionKey : import_node_buffer56.Buffer.from(wire.partitionKey)
|
|
15596
17222
|
});
|
|
15597
17223
|
}
|
|
15598
17224
|
function snapshotArray(values) {
|
|
@@ -15603,7 +17229,7 @@ function snapshotArray(values) {
|
|
|
15603
17229
|
return Object.freeze(snapshot);
|
|
15604
17230
|
}
|
|
15605
17231
|
function snapshotStateMeta(stateMeta) {
|
|
15606
|
-
return snapshotRecord(stateMeta, (value) =>
|
|
17232
|
+
return snapshotRecord(stateMeta, (value) => import_node_buffer56.Buffer.isBuffer(value) ? import_node_buffer56.Buffer.from(value) : value);
|
|
15607
17233
|
}
|
|
15608
17234
|
function snapshotCommandRecord(values) {
|
|
15609
17235
|
const seen = /* @__PURE__ */ new WeakMap();
|
|
@@ -15621,7 +17247,7 @@ function snapshotRecord(values, capture) {
|
|
|
15621
17247
|
}
|
|
15622
17248
|
function snapshotCommandArgument(value, seen) {
|
|
15623
17249
|
if (typeof value !== "object" || value == null) return value;
|
|
15624
|
-
if (
|
|
17250
|
+
if (import_node_buffer56.Buffer.isBuffer(value) || value instanceof Uint8Array) return import_node_buffer56.Buffer.from(value);
|
|
15625
17251
|
const objectValue = value;
|
|
15626
17252
|
const existing = seen.get(objectValue);
|
|
15627
17253
|
if (existing != null) return existing;
|
|
@@ -16609,7 +18235,7 @@ function nativeOptionsForBootstrap(options, signal) {
|
|
|
16609
18235
|
}
|
|
16610
18236
|
|
|
16611
18237
|
// src/flow-query-projection.ts
|
|
16612
|
-
var
|
|
18238
|
+
var import_node_buffer57 = require("buffer");
|
|
16613
18239
|
var MAX_PROJECTION_FIELDS = 32;
|
|
16614
18240
|
var MAX_DYNAMIC_NAME_BYTES = 64;
|
|
16615
18241
|
var FIELD_BRAND = /* @__PURE__ */ Symbol("FerricStoreFlowProjectionField");
|
|
@@ -16677,20 +18303,38 @@ function projectFlowQuery(query, shape, ...fields) {
|
|
|
16677
18303
|
if (containsReturnKeyword(query)) {
|
|
16678
18304
|
throw new TypeError("Flow query already contains a RETURN clause");
|
|
16679
18305
|
}
|
|
16680
|
-
const
|
|
16681
|
-
const base = trimmed.endsWith(";") ? trimmed.slice(0, -1).trimEnd() : trimmed;
|
|
18306
|
+
const base = stripOptionalTerminator(query);
|
|
16682
18307
|
const result = `${base} RETURN ${shape.toUpperCase()} (${selectors.join(", ")})`;
|
|
16683
|
-
if (
|
|
18308
|
+
if (import_node_buffer57.Buffer.byteLength(result, "utf8") > FLOW_QUERY_MAX_BYTES) {
|
|
16684
18309
|
throw new TypeError(`FLOW.QUERY query exceeds ${FLOW_QUERY_MAX_BYTES} bytes`);
|
|
16685
18310
|
}
|
|
16686
18311
|
return result;
|
|
16687
18312
|
}
|
|
18313
|
+
function stripOptionalTerminator(query) {
|
|
18314
|
+
const trimmed = trimFlowQueryAsciiWhitespace(query);
|
|
18315
|
+
if (!trimmed.endsWith(";")) return trimmed;
|
|
18316
|
+
const base = trimFlowQueryAsciiWhitespace(trimmed.slice(0, -1));
|
|
18317
|
+
if (base.endsWith(";")) {
|
|
18318
|
+
throw new TypeError("Flow query accepts at most one trailing semicolon");
|
|
18319
|
+
}
|
|
18320
|
+
return base;
|
|
18321
|
+
}
|
|
16688
18322
|
function querySource(query) {
|
|
16689
|
-
const
|
|
16690
|
-
if (
|
|
18323
|
+
const source = trimFlowQueryAsciiWhitespaceStart(query);
|
|
18324
|
+
if (!matchesFlowQueryAsciiKeyword(source, 0, "FROM") || !isFlowQueryAsciiWhitespaceCode(source.charCodeAt(4))) {
|
|
16691
18325
|
throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
|
|
16692
18326
|
}
|
|
16693
|
-
|
|
18327
|
+
let offset = 4;
|
|
18328
|
+
while (isFlowQueryAsciiWhitespaceCode(source.charCodeAt(offset))) offset += 1;
|
|
18329
|
+
for (const candidate of ["runs", "events"]) {
|
|
18330
|
+
if (matchesFlowQueryAsciiKeyword(source, offset, candidate.toUpperCase())) {
|
|
18331
|
+
const boundary = source[offset + candidate.length];
|
|
18332
|
+
if (boundary == null || isFlowQueryAsciiWhitespaceCode(boundary.charCodeAt(0))) {
|
|
18333
|
+
return candidate;
|
|
18334
|
+
}
|
|
18335
|
+
}
|
|
18336
|
+
}
|
|
18337
|
+
throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
|
|
16694
18338
|
}
|
|
16695
18339
|
function containsReturnKeyword(query) {
|
|
16696
18340
|
let quoted = false;
|
|
@@ -16721,7 +18365,7 @@ function quoteName(value, allowPrivate) {
|
|
|
16721
18365
|
throw new TypeError("Flow query projection metadata name must be text");
|
|
16722
18366
|
}
|
|
16723
18367
|
validateUnicodeScalarText2(value);
|
|
16724
|
-
const size =
|
|
18368
|
+
const size = import_node_buffer57.Buffer.byteLength(value, "utf8");
|
|
16725
18369
|
if (size === 0 || size > MAX_DYNAMIC_NAME_BYTES || !allowPrivate && value.startsWith("__")) {
|
|
16726
18370
|
throw new TypeError(
|
|
16727
18371
|
`Flow query projection metadata names must be 1..${MAX_DYNAMIC_NAME_BYTES} UTF-8 bytes`
|
|
@@ -16755,7 +18399,7 @@ function complete(options = {}) {
|
|
|
16755
18399
|
function retry(options = {}) {
|
|
16756
18400
|
return brandOutcome({ ...options, kind: "retry" });
|
|
16757
18401
|
}
|
|
16758
|
-
function
|
|
18402
|
+
function fail2(options = {}) {
|
|
16759
18403
|
return brandOutcome({ ...options, kind: "fail" });
|
|
16760
18404
|
}
|
|
16761
18405
|
function isOutcome(value) {
|
|
@@ -16823,7 +18467,7 @@ var LeaseRenewalGuard = class {
|
|
|
16823
18467
|
if (options.leaseRenewal === false) {
|
|
16824
18468
|
return;
|
|
16825
18469
|
}
|
|
16826
|
-
const intervalMs =
|
|
18470
|
+
const intervalMs = positiveInteger3(options.leaseRenewIntervalMs, Math.max(1, Math.trunc(leaseMs / 2)));
|
|
16827
18471
|
this.timer = setLongInterval(() => this.renew(), intervalMs);
|
|
16828
18472
|
this.timer.unref();
|
|
16829
18473
|
}
|
|
@@ -16895,7 +18539,7 @@ function snapshotLeasedJob(job) {
|
|
|
16895
18539
|
return snapshot;
|
|
16896
18540
|
}
|
|
16897
18541
|
function workerConcurrency(options) {
|
|
16898
|
-
return
|
|
18542
|
+
return positiveInteger3(options.concurrency ?? options.workers, 1);
|
|
16899
18543
|
}
|
|
16900
18544
|
function workerRefillStrategy(options) {
|
|
16901
18545
|
return options.refillStrategy === "wave" ? "wave" : "continuous";
|
|
@@ -16938,18 +18582,18 @@ function workerErrorPayload(error, options, codec) {
|
|
|
16938
18582
|
}
|
|
16939
18583
|
function workerBatchSize(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
|
|
16940
18584
|
return Math.min(
|
|
16941
|
-
|
|
16942
|
-
|
|
18585
|
+
positiveInteger3(options.batchSize, 10),
|
|
18586
|
+
positiveInteger3(flowManyBatchLimit, DEFAULT_FLOW_MANY_BATCH_LIMIT2)
|
|
16943
18587
|
);
|
|
16944
18588
|
}
|
|
16945
18589
|
function workerClaimLimit(options, flowManyBatchLimit = DEFAULT_FLOW_MANY_BATCH_LIMIT2) {
|
|
16946
18590
|
return Math.min(workerBatchSize(options, flowManyBatchLimit), workerConcurrency(options));
|
|
16947
18591
|
}
|
|
16948
18592
|
function workerDrainBatches(options) {
|
|
16949
|
-
return
|
|
18593
|
+
return positiveInteger3(options.claimDrainBatches, 1);
|
|
16950
18594
|
}
|
|
16951
18595
|
function workerLeaseMs(options, fallback = 3e4) {
|
|
16952
|
-
return
|
|
18596
|
+
return positiveInteger3(options.leaseMs, positiveInteger3(fallback, 3e4));
|
|
16953
18597
|
}
|
|
16954
18598
|
function workerIdleSleepMs(options) {
|
|
16955
18599
|
return nonNegativeDuration(options.idleSleepMs, 250);
|
|
@@ -16961,7 +18605,7 @@ function workerClaimBlockMs(options, useBlocking) {
|
|
|
16961
18605
|
if (options.signal == null || !Number.isFinite(options.blockMs) || options.blockMs < 0) {
|
|
16962
18606
|
return options.blockMs;
|
|
16963
18607
|
}
|
|
16964
|
-
const abortPollMs =
|
|
18608
|
+
const abortPollMs = positiveInteger3(options.abortPollMs, 1e3);
|
|
16965
18609
|
return options.blockMs === 0 ? abortPollMs : Math.min(Math.trunc(options.blockMs), abortPollMs);
|
|
16966
18610
|
}
|
|
16967
18611
|
function workerMaxIdleSleepMs(options, idleSleepMs = workerIdleSleepMs(options)) {
|
|
@@ -16972,14 +18616,14 @@ function nextWorkerIdleSleepMs(currentIdleSleepMs, maxIdleSleepMs) {
|
|
|
16972
18616
|
return Math.min(maxIdleSleepMs, Math.max(1, currentIdleSleepMs * 2));
|
|
16973
18617
|
}
|
|
16974
18618
|
async function runContinuousWorkerPool(options) {
|
|
16975
|
-
const concurrency =
|
|
16976
|
-
const maxClaimSize =
|
|
18619
|
+
const concurrency = positiveInteger3(options.concurrency, 1);
|
|
18620
|
+
const maxClaimSize = positiveInteger3(options.maxClaimSize, concurrency);
|
|
16977
18621
|
const initialIdleSleepMs = nonNegativeDuration(options.idleSleepMs, 250);
|
|
16978
18622
|
const maxIdleSleepMs = Math.max(
|
|
16979
18623
|
initialIdleSleepMs,
|
|
16980
18624
|
nonNegativeDuration(options.maxIdleSleepMs, 5e3)
|
|
16981
18625
|
);
|
|
16982
|
-
const refillDelayMs =
|
|
18626
|
+
const refillDelayMs = nonNegativeInteger4(options.refillDelayMs, 0);
|
|
16983
18627
|
const active = /* @__PURE__ */ new Set();
|
|
16984
18628
|
const pending = [];
|
|
16985
18629
|
let pendingIndex = 0;
|
|
@@ -17095,10 +18739,10 @@ function normalizeWorkflowWorkerConfig(options) {
|
|
|
17095
18739
|
...captured
|
|
17096
18740
|
});
|
|
17097
18741
|
}
|
|
17098
|
-
function
|
|
18742
|
+
function positiveInteger3(value, fallback) {
|
|
17099
18743
|
return value == null || !Number.isFinite(value) ? fallback : Math.max(1, Math.trunc(value));
|
|
17100
18744
|
}
|
|
17101
|
-
function
|
|
18745
|
+
function nonNegativeInteger4(value, fallback) {
|
|
17102
18746
|
return value == null || !Number.isFinite(value) ? fallback : Math.max(0, Math.trunc(value));
|
|
17103
18747
|
}
|
|
17104
18748
|
function nonNegativeDuration(value, fallback) {
|
|
@@ -17552,7 +19196,7 @@ async function applyQueueException(queue, options, job, error) {
|
|
|
17552
19196
|
const policy = normalizeExceptionPolicy(options.exceptionPolicy);
|
|
17553
19197
|
if (policy === "raise") throw error;
|
|
17554
19198
|
const payload = workerErrorPayload(error, options, queue.client.codec);
|
|
17555
|
-
await applyQueueOutcome(queue, job, policy === "fail" ?
|
|
19199
|
+
await applyQueueOutcome(queue, job, policy === "fail" ? fail2({ error: payload }) : retry({ error: payload }));
|
|
17556
19200
|
}
|
|
17557
19201
|
|
|
17558
19202
|
// src/queue-pending-completions.ts
|
|
@@ -17799,7 +19443,7 @@ var QueueWorker = class {
|
|
|
17799
19443
|
const policy = normalizeExceptionPolicy(this.options.exceptionPolicy);
|
|
17800
19444
|
if (policy !== "raise") {
|
|
17801
19445
|
const payload = workerErrorPayload(error, this.options, this.queue.client.codec);
|
|
17802
|
-
outcome = policy === "fail" ?
|
|
19446
|
+
outcome = policy === "fail" ? fail2({ error: payload }) : retry({ error: payload });
|
|
17803
19447
|
}
|
|
17804
19448
|
}
|
|
17805
19449
|
const stopped = await stopQueueBatchGuards(guards.map((guard) => guard.job), guards);
|
|
@@ -17982,13 +19626,13 @@ var QueueWorker = class {
|
|
|
17982
19626
|
|
|
17983
19627
|
// src/flow-client-options.ts
|
|
17984
19628
|
function snapshotFlowClientOptions(options, context) {
|
|
17985
|
-
const
|
|
17986
|
-
if (typeof
|
|
19629
|
+
const own2 = { ...options };
|
|
19630
|
+
if (typeof own2.type !== "string" || own2.type.length === 0) {
|
|
17987
19631
|
throw new TypeError(`${context} type must be an own non-empty string`);
|
|
17988
19632
|
}
|
|
17989
|
-
const valueConfig =
|
|
19633
|
+
const valueConfig = own2.valueConfig;
|
|
17990
19634
|
return Object.freeze({
|
|
17991
|
-
...
|
|
19635
|
+
...own2,
|
|
17992
19636
|
...valueConfig == null ? {} : { valueConfig: Object.freeze({ ...valueConfig }) }
|
|
17993
19637
|
});
|
|
17994
19638
|
}
|
|
@@ -18411,19 +20055,19 @@ async function applyFail(client, ctx, outcome, returnRecord) {
|
|
|
18411
20055
|
|
|
18412
20056
|
// src/workflow-registration.ts
|
|
18413
20057
|
function createWorkflowStateRegistration(name, handler, options, defaultValueMaxBytes) {
|
|
18414
|
-
const
|
|
18415
|
-
const claimValues =
|
|
18416
|
-
const retryPolicy =
|
|
20058
|
+
const own2 = { ...options };
|
|
20059
|
+
const claimValues = own2.claimValues == null ? void 0 : snapshotOwnStringArray(own2.claimValues, "claimValues");
|
|
20060
|
+
const retryPolicy = own2.retryPolicy == null ? void 0 : Object.freeze({ ...own2.retryPolicy });
|
|
18417
20061
|
return Object.freeze({
|
|
18418
|
-
claimPayload:
|
|
18419
|
-
claimRecord:
|
|
18420
|
-
exceptionPolicy: normalizeExceptionPolicy(
|
|
20062
|
+
claimPayload: own2.claimPayload ?? true,
|
|
20063
|
+
claimRecord: own2.claimRecord ?? true,
|
|
20064
|
+
exceptionPolicy: normalizeExceptionPolicy(own2.exceptionPolicy),
|
|
18421
20065
|
handler,
|
|
18422
|
-
leaseMs:
|
|
18423
|
-
...
|
|
20066
|
+
leaseMs: own2.leaseMs ?? 3e4,
|
|
20067
|
+
...own2.mode == null ? {} : { mode: normalizeStateMode(own2.mode) },
|
|
18424
20068
|
name,
|
|
18425
|
-
returnRecord:
|
|
18426
|
-
valueMaxBytes:
|
|
20069
|
+
returnRecord: own2.returnRecord ?? false,
|
|
20070
|
+
valueMaxBytes: own2.valueMaxBytes ?? defaultValueMaxBytes,
|
|
18427
20071
|
...claimValues == null ? {} : { claimValues },
|
|
18428
20072
|
...retryPolicy == null ? {} : { retryPolicy }
|
|
18429
20073
|
});
|
|
@@ -18712,7 +20356,7 @@ var WorkflowWorker = class {
|
|
|
18712
20356
|
await applyWorkflowOutcome(
|
|
18713
20357
|
this.workflow.client,
|
|
18714
20358
|
ctx,
|
|
18715
|
-
|
|
20359
|
+
fail2({ error: workerErrorPayload(error, this.options, this.workflow.client.codec) }),
|
|
18716
20360
|
registration.returnRecord
|
|
18717
20361
|
);
|
|
18718
20362
|
return;
|
|
@@ -18727,8 +20371,8 @@ var WorkflowWorker = class {
|
|
|
18727
20371
|
};
|
|
18728
20372
|
|
|
18729
20373
|
// src/version.ts
|
|
18730
|
-
var FERRICSTORE_SDK_VERSION = "0.
|
|
18731
|
-
var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.
|
|
20374
|
+
var FERRICSTORE_SDK_VERSION = "0.11.4";
|
|
20375
|
+
var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.4";
|
|
18732
20376
|
var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
|
|
18733
20377
|
// Annotate the CommonJS export names for ESM import in node:
|
|
18734
20378
|
0 && (module.exports = {
|