@ferricstore/ferricstore 0.5.0 → 0.5.2
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 +7 -6
- package/dist/index.cjs +1458 -341
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -10
- package/dist/index.d.ts +95 -10
- package/dist/index.js +1459 -342
- 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/FerricStoreError.html +1 -1
- package/docs/api/classes/FlowAlreadyExistsError.html +1 -1
- package/docs/api/classes/FlowNotFoundError.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 +7 -6
- package/docs/api/interfaces/CompleteOutcome.html +1 -1
- package/docs/api/interfaces/FailOutcome.html +1 -1
- 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/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/NamedValueMutation.html +1 -1
- package/docs/api/interfaces/RetryOutcome.html +1 -1
- package/docs/api/interfaces/TDigestCreateOptions.html +1 -1
- package/docs/api/interfaces/TDigestMergeOptions.html +1 -1
- 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/variables/FERRICSTORE_SDK_VERSION.html +1 -1
- package/docs/api/variables/FlowProjection.html +1 -1
- package/package.json +1 -1
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);
|
|
@@ -5864,7 +5905,10 @@ function isDecodedRecord(value) {
|
|
|
5864
5905
|
// src/protocol-flow-query-result.ts
|
|
5865
5906
|
var CONTRACT = "ferric.flow.query.result/v1";
|
|
5866
5907
|
var MAX_RECORDS = 100;
|
|
5908
|
+
var MIN_CURSOR_BYTES = 16;
|
|
5867
5909
|
var MAX_CURSOR_BYTES = 4096;
|
|
5910
|
+
var CURSOR_PREFIX = import_node_buffer24.Buffer.from("fqc1_");
|
|
5911
|
+
var MAX_SIGNED_64 = (1n << 63n) - 1n;
|
|
5868
5912
|
var RECORD_FIELDS = [
|
|
5869
5913
|
"id",
|
|
5870
5914
|
"type",
|
|
@@ -5928,9 +5972,13 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5928
5972
|
const usage = {};
|
|
5929
5973
|
for (const field3 of USAGE_FIELDS) {
|
|
5930
5974
|
const read = readU64(data, offset);
|
|
5975
|
+
if (BigInt(read.value) > MAX_SIGNED_64) {
|
|
5976
|
+
throw new FerricStoreError("compact FLOW.QUERY usage exceeds signed 64-bit range");
|
|
5977
|
+
}
|
|
5931
5978
|
usage[field3] = read.value;
|
|
5932
5979
|
offset = read.offset;
|
|
5933
5980
|
}
|
|
5981
|
+
validateCompactUsage(usage);
|
|
5934
5982
|
let result;
|
|
5935
5983
|
if (kind === 0) {
|
|
5936
5984
|
const page = readPage(data, offset);
|
|
@@ -5939,6 +5987,7 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5939
5987
|
const count = data.readUInt32BE(offset);
|
|
5940
5988
|
offset += 4;
|
|
5941
5989
|
if (count > MAX_RECORDS) throw new FerricStoreError("compact FLOW.QUERY page exceeds 100 records");
|
|
5990
|
+
validateCompactRecordUsage(usage, count);
|
|
5942
5991
|
consumeDecodeItems(count, budget);
|
|
5943
5992
|
const records = new Array(count);
|
|
5944
5993
|
for (let index = 0; index < count; index += 1) {
|
|
@@ -5948,7 +5997,13 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5948
5997
|
}
|
|
5949
5998
|
result = { version: import_node_buffer24.Buffer.from(CONTRACT), records, page: page.value, quality, usage };
|
|
5950
5999
|
} else if (kind === 1) {
|
|
6000
|
+
if (usageInteger(usage, "result_records") !== 1n) {
|
|
6001
|
+
throw new FerricStoreError("compact FLOW.QUERY count usage is inconsistent");
|
|
6002
|
+
}
|
|
5951
6003
|
const count = readU64(data, offset);
|
|
6004
|
+
if (BigInt(count.value) > MAX_SIGNED_64) {
|
|
6005
|
+
throw new FerricStoreError("compact FLOW.QUERY count exceeds signed 64-bit range");
|
|
6006
|
+
}
|
|
5952
6007
|
offset = count.offset;
|
|
5953
6008
|
result = {
|
|
5954
6009
|
version: import_node_buffer24.Buffer.from(CONTRACT),
|
|
@@ -5973,18 +6028,37 @@ function readPage(data, offset) {
|
|
|
5973
6028
|
if (hasMoreCode === 0 && size === NULL_U32) {
|
|
5974
6029
|
return { value: { has_more: false, cursor: null }, offset };
|
|
5975
6030
|
}
|
|
5976
|
-
if (hasMoreCode !== 1 || size
|
|
6031
|
+
if (hasMoreCode !== 1 || size < MIN_CURSOR_BYTES || size === NULL_U32 || size > MAX_CURSOR_BYTES) {
|
|
5977
6032
|
throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
|
|
5978
6033
|
}
|
|
5979
6034
|
requireAvailable(data, offset, size);
|
|
6035
|
+
const cursor = data.subarray(offset, offset + size);
|
|
6036
|
+
if (!cursor.subarray(0, CURSOR_PREFIX.byteLength).equals(CURSOR_PREFIX) || !(0, import_node_buffer24.isUtf8)(cursor)) {
|
|
6037
|
+
throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
|
|
6038
|
+
}
|
|
5980
6039
|
return {
|
|
5981
6040
|
value: {
|
|
5982
6041
|
has_more: true,
|
|
5983
|
-
cursor: detachDecodedBinary(
|
|
6042
|
+
cursor: detachDecodedBinary(cursor, data.byteLength)
|
|
5984
6043
|
},
|
|
5985
6044
|
offset: offset + size
|
|
5986
6045
|
};
|
|
5987
6046
|
}
|
|
6047
|
+
function validateCompactUsage(usage) {
|
|
6048
|
+
const scanned = usageInteger(usage, "scanned_entries");
|
|
6049
|
+
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) {
|
|
6050
|
+
throw new FerricStoreError("compact FLOW.QUERY usage counters are inconsistent");
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6053
|
+
function validateCompactRecordUsage(usage, count) {
|
|
6054
|
+
const resultRecords = usageInteger(usage, "result_records");
|
|
6055
|
+
if (resultRecords !== BigInt(count) || resultRecords > usageInteger(usage, "scanned_entries")) {
|
|
6056
|
+
throw new FerricStoreError("compact FLOW.QUERY record usage is inconsistent");
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
function usageInteger(usage, field3) {
|
|
6060
|
+
return BigInt(usage[field3]);
|
|
6061
|
+
}
|
|
5988
6062
|
function readRecord(data, offset, budget) {
|
|
5989
6063
|
requireAvailable(data, offset, 4);
|
|
5990
6064
|
const bitmap = data.readUInt32BE(offset);
|
|
@@ -8010,6 +8084,63 @@ function nativeStartupPayload(clientName, events) {
|
|
|
8010
8084
|
};
|
|
8011
8085
|
}
|
|
8012
8086
|
|
|
8087
|
+
// src/flow-query-deadline.ts
|
|
8088
|
+
var import_node_buffer31 = require("buffer");
|
|
8089
|
+
function withFlowQueryDeadline(command, timeoutMs, nowMs2) {
|
|
8090
|
+
if (timeoutMs == null) return command;
|
|
8091
|
+
if (command.opcode === OPCODES.pipeline) {
|
|
8092
|
+
return withPipelineQueryDeadlines(command, timeoutMs, nowMs2);
|
|
8093
|
+
}
|
|
8094
|
+
if (command.opcode !== OPCODES.flowQuery) return command;
|
|
8095
|
+
const payload = command.payload;
|
|
8096
|
+
if (payload instanceof Map) {
|
|
8097
|
+
const nextPayload = new Map(payload);
|
|
8098
|
+
nextPayload.set("deadline_ms", flowQueryDeadlineMs(timeoutMs, nowMs2));
|
|
8099
|
+
return { ...command, payload: nextPayload };
|
|
8100
|
+
}
|
|
8101
|
+
if (typeof payload !== "object" || payload == null || Array.isArray(payload) || import_node_buffer31.Buffer.isBuffer(payload) || payload instanceof Uint8Array) {
|
|
8102
|
+
return command;
|
|
8103
|
+
}
|
|
8104
|
+
return {
|
|
8105
|
+
...command,
|
|
8106
|
+
payload: {
|
|
8107
|
+
...payload,
|
|
8108
|
+
deadline_ms: flowQueryDeadlineMs(timeoutMs, nowMs2)
|
|
8109
|
+
}
|
|
8110
|
+
};
|
|
8111
|
+
}
|
|
8112
|
+
function withPipelineQueryDeadlines(command, timeoutMs, nowMs2) {
|
|
8113
|
+
const payload = plainRecord(command.payload);
|
|
8114
|
+
if (payload == null) return command;
|
|
8115
|
+
const rawCommands = payload.commands;
|
|
8116
|
+
if (!Array.isArray(rawCommands)) return command;
|
|
8117
|
+
let commands;
|
|
8118
|
+
let deadlineMs;
|
|
8119
|
+
for (let index = 0; index < rawCommands.length; index += 1) {
|
|
8120
|
+
const rawItem = rawCommands[index];
|
|
8121
|
+
const item = plainRecord(rawItem);
|
|
8122
|
+
if (item?.opcode !== OPCODES.flowQuery) continue;
|
|
8123
|
+
const body = plainRecord(item.body);
|
|
8124
|
+
if (body == null) continue;
|
|
8125
|
+
commands ??= rawCommands.slice();
|
|
8126
|
+
deadlineMs ??= flowQueryDeadlineMs(timeoutMs, nowMs2);
|
|
8127
|
+
commands[index] = { ...item, body: { ...body, deadline_ms: deadlineMs } };
|
|
8128
|
+
}
|
|
8129
|
+
return commands == null ? command : { ...command, payload: { ...payload, commands } };
|
|
8130
|
+
}
|
|
8131
|
+
function flowQueryDeadlineMs(timeoutMs, nowMs2) {
|
|
8132
|
+
return Math.min(
|
|
8133
|
+
Number.MAX_SAFE_INTEGER,
|
|
8134
|
+
(nowMs2 ?? Date.now()) + Math.max(1, Math.ceil(timeoutMs))
|
|
8135
|
+
);
|
|
8136
|
+
}
|
|
8137
|
+
function plainRecord(value) {
|
|
8138
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer31.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
8139
|
+
return void 0;
|
|
8140
|
+
}
|
|
8141
|
+
return value;
|
|
8142
|
+
}
|
|
8143
|
+
|
|
8013
8144
|
// src/native-adapter.ts
|
|
8014
8145
|
var NativeAdapter = class _NativeAdapter {
|
|
8015
8146
|
socket;
|
|
@@ -8215,7 +8346,11 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
8215
8346
|
let frame;
|
|
8216
8347
|
try {
|
|
8217
8348
|
requestId = this.requestScheduler.nextRequestId();
|
|
8218
|
-
frame = encodeRequest(
|
|
8349
|
+
frame = encodeRequest(
|
|
8350
|
+
withFlowQueryDeadline(command, timeoutMs),
|
|
8351
|
+
requestId,
|
|
8352
|
+
this.capabilities.requestFrameBytes
|
|
8353
|
+
);
|
|
8219
8354
|
} catch (error) {
|
|
8220
8355
|
if (hasFlowControlCredit) this.flowControl.release(laneId);
|
|
8221
8356
|
return Promise.reject(error instanceof Error ? error : new FerricStoreError(String(error), { raw: error }));
|
|
@@ -8360,10 +8495,10 @@ function executeCommandArgs(executor, args) {
|
|
|
8360
8495
|
}
|
|
8361
8496
|
|
|
8362
8497
|
// src/reconnecting-executor.ts
|
|
8363
|
-
var
|
|
8498
|
+
var import_node_buffer34 = require("buffer");
|
|
8364
8499
|
|
|
8365
8500
|
// src/command-retry-policy.ts
|
|
8366
|
-
var
|
|
8501
|
+
var import_node_buffer33 = require("buffer");
|
|
8367
8502
|
function isCasMutation(args) {
|
|
8368
8503
|
const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
|
|
8369
8504
|
const name = commandName2(args[offset]);
|
|
@@ -8377,8 +8512,8 @@ function isCasMutation(args) {
|
|
|
8377
8512
|
}
|
|
8378
8513
|
function commandName2(value) {
|
|
8379
8514
|
if (typeof value === "string") return value.toUpperCase();
|
|
8380
|
-
if (
|
|
8381
|
-
return
|
|
8515
|
+
if (import_node_buffer33.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
8516
|
+
return import_node_buffer33.Buffer.from(value).toString("utf8").toUpperCase();
|
|
8382
8517
|
}
|
|
8383
8518
|
return void 0;
|
|
8384
8519
|
}
|
|
@@ -8590,15 +8725,15 @@ function normalizeNonNegativeInteger2(value, fallback) {
|
|
|
8590
8725
|
}
|
|
8591
8726
|
|
|
8592
8727
|
// src/topology.ts
|
|
8593
|
-
var
|
|
8728
|
+
var import_node_buffer37 = require("buffer");
|
|
8594
8729
|
|
|
8595
8730
|
// src/topology-routing.ts
|
|
8596
|
-
var
|
|
8731
|
+
var import_node_buffer36 = require("buffer");
|
|
8597
8732
|
|
|
8598
8733
|
// src/flow-partition-route-cache.ts
|
|
8599
|
-
var
|
|
8734
|
+
var import_node_buffer35 = require("buffer");
|
|
8600
8735
|
var import_node_crypto = require("crypto");
|
|
8601
|
-
var AUTO_PREFIX =
|
|
8736
|
+
var AUTO_PREFIX = import_node_buffer35.Buffer.from("__flow_auto__:", "ascii");
|
|
8602
8737
|
var MAX_CACHEABLE_PARTITION_BYTES = 4 * 1024;
|
|
8603
8738
|
var MAX_CACHE_BYTES = 1 * 1024 * 1024;
|
|
8604
8739
|
var MAX_CACHE_ENTRIES = 1024;
|
|
@@ -8608,10 +8743,10 @@ var cacheBytes = 0;
|
|
|
8608
8743
|
var cacheHits = 0;
|
|
8609
8744
|
var cacheMisses = 0;
|
|
8610
8745
|
function flowLogicalPartitionRoutingKey(value) {
|
|
8611
|
-
if (typeof value !== "string" && !
|
|
8746
|
+
if (typeof value !== "string" && !import_node_buffer35.Buffer.isBuffer(value)) return void 0;
|
|
8612
8747
|
const autoBucket = flowAutoBucket(value);
|
|
8613
8748
|
if (autoBucket != null) return `{fa:${autoBucket}}`;
|
|
8614
|
-
const bytes2 =
|
|
8749
|
+
const bytes2 = import_node_buffer35.Buffer.isBuffer(value) ? value : import_node_buffer35.Buffer.from(value);
|
|
8615
8750
|
if (bytes2.byteLength > MAX_CACHEABLE_PARTITION_BYTES) return hashRoute(bytes2);
|
|
8616
8751
|
const cacheKey = bytes2.toString("base64");
|
|
8617
8752
|
const cached = routeCache.get(cacheKey);
|
|
@@ -8685,7 +8820,7 @@ function routingKeyFromProtocolPayload(name, command) {
|
|
|
8685
8820
|
"scope"
|
|
8686
8821
|
]) {
|
|
8687
8822
|
const value = getField(command.payload, field3);
|
|
8688
|
-
if (typeof value === "string" ||
|
|
8823
|
+
if (typeof value === "string" || import_node_buffer36.Buffer.isBuffer(value)) {
|
|
8689
8824
|
return value;
|
|
8690
8825
|
}
|
|
8691
8826
|
}
|
|
@@ -8733,7 +8868,7 @@ function flowRoutingData(name, args) {
|
|
|
8733
8868
|
if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
|
|
8734
8869
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
8735
8870
|
}
|
|
8736
|
-
if (
|
|
8871
|
+
if (import_node_buffer36.Buffer.isBuffer(partition)) {
|
|
8737
8872
|
const text3 = partition.toString("utf8").toUpperCase();
|
|
8738
8873
|
if (text3 !== "AUTO" && text3 !== "MIXED") {
|
|
8739
8874
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
@@ -8824,17 +8959,17 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
|
|
|
8824
8959
|
return { handled: false };
|
|
8825
8960
|
}
|
|
8826
8961
|
function isRoutingKey(value) {
|
|
8827
|
-
return typeof value === "string" ||
|
|
8962
|
+
return typeof value === "string" || import_node_buffer36.Buffer.isBuffer(value);
|
|
8828
8963
|
}
|
|
8829
8964
|
function flowAutoIdRoutingKey(value) {
|
|
8830
|
-
if (typeof value !== "string" && !
|
|
8965
|
+
if (typeof value !== "string" && !import_node_buffer36.Buffer.isBuffer(value)) {
|
|
8831
8966
|
return void 0;
|
|
8832
8967
|
}
|
|
8833
|
-
const bucket = (
|
|
8968
|
+
const bucket = (import_node_buffer36.Buffer.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
|
|
8834
8969
|
return `{fa:${bucket}}`;
|
|
8835
8970
|
}
|
|
8836
8971
|
function flowClaimLogicalPartitionRoutingKey(value) {
|
|
8837
|
-
if (typeof value !== "string" && !
|
|
8972
|
+
if (typeof value !== "string" && !import_node_buffer36.Buffer.isBuffer(value)) return void 0;
|
|
8838
8973
|
const selector = commandPart(value);
|
|
8839
8974
|
if (selector === "AUTO" || selector === "ANY") return void 0;
|
|
8840
8975
|
if (selector === "GLOBAL") return "{f}";
|
|
@@ -8849,7 +8984,7 @@ function singleShardFlowClaimPartitionKey(values) {
|
|
|
8849
8984
|
return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
|
|
8850
8985
|
}
|
|
8851
8986
|
function singleShardKey(keys) {
|
|
8852
|
-
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !
|
|
8987
|
+
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !import_node_buffer36.Buffer.isBuffer(key))) {
|
|
8853
8988
|
return void 0;
|
|
8854
8989
|
}
|
|
8855
8990
|
const usable = keys;
|
|
@@ -8882,7 +9017,7 @@ function routedKeyGroups(keys, routeKey) {
|
|
|
8882
9017
|
const groups = /* @__PURE__ */ new Map();
|
|
8883
9018
|
for (let index = 0; index < keys.length; index += 1) {
|
|
8884
9019
|
const key = keys[index];
|
|
8885
|
-
if (typeof key !== "string" && !
|
|
9020
|
+
if (typeof key !== "string" && !import_node_buffer36.Buffer.isBuffer(key)) return void 0;
|
|
8886
9021
|
const route = routeKey(key);
|
|
8887
9022
|
const groupKey = `${route.endpointKey}\0${route.laneId}`;
|
|
8888
9023
|
const group = groups.get(groupKey);
|
|
@@ -9971,7 +10106,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
9971
10106
|
};
|
|
9972
10107
|
|
|
9973
10108
|
// src/response-map-preservation.ts
|
|
9974
|
-
var
|
|
10109
|
+
var import_node_buffer38 = require("buffer");
|
|
9975
10110
|
function toStringKeyMapPreservingValues(value) {
|
|
9976
10111
|
if (value == null) return void 0;
|
|
9977
10112
|
const result = {};
|
|
@@ -9981,7 +10116,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
9981
10116
|
}
|
|
9982
10117
|
return result;
|
|
9983
10118
|
}
|
|
9984
|
-
if (typeof value === "object" && !Array.isArray(value) && !
|
|
10119
|
+
if (typeof value === "object" && !Array.isArray(value) && !import_node_buffer38.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
9985
10120
|
for (const [key, item] of Object.entries(value)) {
|
|
9986
10121
|
setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
|
|
9987
10122
|
}
|
|
@@ -9990,7 +10125,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
9990
10125
|
return void 0;
|
|
9991
10126
|
}
|
|
9992
10127
|
function normalizeMapStructurePreservingBytes(value) {
|
|
9993
|
-
if (
|
|
10128
|
+
if (import_node_buffer38.Buffer.isBuffer(value) || value instanceof Uint8Array) return value;
|
|
9994
10129
|
if (value instanceof Map) {
|
|
9995
10130
|
const result = {};
|
|
9996
10131
|
for (const [key, item] of value.entries()) {
|
|
@@ -10012,7 +10147,7 @@ function normalizeMapStructurePreservingBytes(value) {
|
|
|
10012
10147
|
}
|
|
10013
10148
|
|
|
10014
10149
|
// src/native-kv-responses.ts
|
|
10015
|
-
var
|
|
10150
|
+
var import_node_buffer39 = require("buffer");
|
|
10016
10151
|
function rateLimitResultFromResp(value) {
|
|
10017
10152
|
if (!Array.isArray(value) || value.length !== 4) {
|
|
10018
10153
|
throw new TypeError("RATELIMIT.ADD returned an unexpected response");
|
|
@@ -10069,13 +10204,13 @@ function fetchOrComputeResultFromResp(value, codec) {
|
|
|
10069
10204
|
}
|
|
10070
10205
|
function decodePayload(codec, value) {
|
|
10071
10206
|
if (value == null) return null;
|
|
10072
|
-
if (
|
|
10073
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
10074
|
-
if (typeof value === "string") return codec.decode(
|
|
10207
|
+
if (import_node_buffer39.Buffer.isBuffer(value)) return codec.decode(value);
|
|
10208
|
+
if (value instanceof Uint8Array) return codec.decode(import_node_buffer39.Buffer.from(value));
|
|
10209
|
+
if (typeof value === "string") return codec.decode(import_node_buffer39.Buffer.from(value));
|
|
10075
10210
|
return normalizeRefMeta(value);
|
|
10076
10211
|
}
|
|
10077
10212
|
function requiredResponseString(value, context) {
|
|
10078
|
-
if (typeof value !== "string" && !
|
|
10213
|
+
if (typeof value !== "string" && !import_node_buffer39.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
10079
10214
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
10080
10215
|
}
|
|
10081
10216
|
const result = text(value);
|
|
@@ -10092,7 +10227,7 @@ function requiredNonNegativeInteger(value, context) {
|
|
|
10092
10227
|
return result;
|
|
10093
10228
|
}
|
|
10094
10229
|
function responseBytes(value, context) {
|
|
10095
|
-
if (typeof value !== "string" && !
|
|
10230
|
+
if (typeof value !== "string" && !import_node_buffer39.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
10096
10231
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
10097
10232
|
}
|
|
10098
10233
|
return bytes(value);
|
|
@@ -10775,7 +10910,7 @@ function groupAutoPartitionItems(items) {
|
|
|
10775
10910
|
}
|
|
10776
10911
|
|
|
10777
10912
|
// src/client-values.ts
|
|
10778
|
-
var
|
|
10913
|
+
var import_node_buffer40 = require("buffer");
|
|
10779
10914
|
async function valueMGetEntries(client, refs, options = {}) {
|
|
10780
10915
|
const refCount = refs.length;
|
|
10781
10916
|
if (refCount === 0) {
|
|
@@ -10810,12 +10945,12 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
10810
10945
|
const item = response[index];
|
|
10811
10946
|
if (item == null) {
|
|
10812
10947
|
entries[index] = { found: false };
|
|
10813
|
-
} else if (
|
|
10948
|
+
} else if (import_node_buffer40.Buffer.isBuffer(item)) {
|
|
10814
10949
|
entries[index] = { found: true, value: client.codec.decode(item) };
|
|
10815
10950
|
} else if (item instanceof Uint8Array) {
|
|
10816
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10951
|
+
entries[index] = { found: true, value: client.codec.decode(import_node_buffer40.Buffer.from(item)) };
|
|
10817
10952
|
} else if (typeof item === "string") {
|
|
10818
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10953
|
+
entries[index] = { found: true, value: client.codec.decode(import_node_buffer40.Buffer.from(item)) };
|
|
10819
10954
|
} else {
|
|
10820
10955
|
entries[index] = { found: true, value: item };
|
|
10821
10956
|
}
|
|
@@ -10824,10 +10959,10 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
10824
10959
|
}
|
|
10825
10960
|
|
|
10826
10961
|
// src/auto-batch.ts
|
|
10827
|
-
var
|
|
10962
|
+
var import_node_buffer42 = require("buffer");
|
|
10828
10963
|
|
|
10829
10964
|
// src/auto-batch-ordering.ts
|
|
10830
|
-
var
|
|
10965
|
+
var import_node_buffer41 = require("buffer");
|
|
10831
10966
|
function autoBatchOrderingPlan(batch) {
|
|
10832
10967
|
const accesses = /* @__PURE__ */ new Map();
|
|
10833
10968
|
const fallbackDependencies = [];
|
|
@@ -10942,13 +11077,13 @@ function flowManyAutoBatchIds(command, name) {
|
|
|
10942
11077
|
return fixedFlowItemIds(
|
|
10943
11078
|
command,
|
|
10944
11079
|
mixed ? 4 : 3,
|
|
10945
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) &&
|
|
11080
|
+
(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
11081
|
);
|
|
10947
11082
|
}
|
|
10948
11083
|
return fixedFlowItemIds(
|
|
10949
11084
|
command,
|
|
10950
11085
|
mixed ? 4 : 3,
|
|
10951
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
11086
|
+
(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
11087
|
);
|
|
10953
11088
|
}
|
|
10954
11089
|
function createManyAutoBatchIds(command) {
|
|
@@ -10961,7 +11096,7 @@ function createManyAutoBatchIds(command) {
|
|
|
10961
11096
|
const ids = fixedFlowItemIds(
|
|
10962
11097
|
command,
|
|
10963
11098
|
width,
|
|
10964
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
11099
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && import_node_buffer41.Buffer.isBuffer(command[itemIndex + width - 1]),
|
|
10965
11100
|
markerIndex
|
|
10966
11101
|
);
|
|
10967
11102
|
if (ids != null) return ids;
|
|
@@ -10979,7 +11114,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
|
|
|
10979
11114
|
let cursor = markerIndex + 2;
|
|
10980
11115
|
for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
|
|
10981
11116
|
const id = command[cursor];
|
|
10982
|
-
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !
|
|
11117
|
+
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !import_node_buffer41.Buffer.isBuffer(command[cursor + 2])) return void 0;
|
|
10983
11118
|
ids.push(id);
|
|
10984
11119
|
cursor += 3;
|
|
10985
11120
|
const afterValues = skipExtendedNamedItems(command, cursor, true);
|
|
@@ -10998,7 +11133,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
|
|
|
10998
11133
|
for (let index = 0; index < count; index += 1) {
|
|
10999
11134
|
const name = command[firstItem + index * 2];
|
|
11000
11135
|
const value = command[firstItem + index * 2 + 1];
|
|
11001
|
-
if (!isAutoBatchResourceValue(name) || (encodedValues ? !
|
|
11136
|
+
if (!isAutoBatchResourceValue(name) || (encodedValues ? !import_node_buffer41.Buffer.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
|
|
11002
11137
|
}
|
|
11003
11138
|
return firstItem + count * 2;
|
|
11004
11139
|
}
|
|
@@ -11013,7 +11148,7 @@ function runStepsManyAutoBatchIds(command) {
|
|
|
11013
11148
|
ids.push(item);
|
|
11014
11149
|
continue;
|
|
11015
11150
|
}
|
|
11016
|
-
if (typeof item !== "object" || item == null || Array.isArray(item) ||
|
|
11151
|
+
if (typeof item !== "object" || item == null || Array.isArray(item) || import_node_buffer41.Buffer.isBuffer(item)) return void 0;
|
|
11017
11152
|
const id = item.id;
|
|
11018
11153
|
if (!isAutoBatchResourceValue(id)) return void 0;
|
|
11019
11154
|
ids.push(id);
|
|
@@ -11054,7 +11189,7 @@ function flowValuePutOwner(command, start) {
|
|
|
11054
11189
|
}
|
|
11055
11190
|
var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
|
|
11056
11191
|
function isAutoBatchResourceValue(value) {
|
|
11057
|
-
return typeof value === "string" ||
|
|
11192
|
+
return typeof value === "string" || import_node_buffer41.Buffer.isBuffer(value);
|
|
11058
11193
|
}
|
|
11059
11194
|
function isFencingToken(value) {
|
|
11060
11195
|
return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
|
|
@@ -11063,7 +11198,7 @@ function nonNegativeItemCount(value) {
|
|
|
11063
11198
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
11064
11199
|
}
|
|
11065
11200
|
function autoBatchResourceKey(namespace, value) {
|
|
11066
|
-
return `${namespace}:${
|
|
11201
|
+
return `${namespace}:${import_node_buffer41.Buffer.from(value).toString("base64")}`;
|
|
11067
11202
|
}
|
|
11068
11203
|
function autoBatchCommandName(command) {
|
|
11069
11204
|
return commandView(command).name ?? null;
|
|
@@ -11472,13 +11607,13 @@ function claimFailure(error) {
|
|
|
11472
11607
|
}
|
|
11473
11608
|
|
|
11474
11609
|
// src/client-flow-support.ts
|
|
11475
|
-
var
|
|
11610
|
+
var import_node_buffer55 = require("buffer");
|
|
11476
11611
|
|
|
11477
11612
|
// src/flow-query-builder.ts
|
|
11478
|
-
var
|
|
11613
|
+
var import_node_buffer44 = require("buffer");
|
|
11479
11614
|
|
|
11480
11615
|
// src/flow-query-metadata.ts
|
|
11481
|
-
var
|
|
11616
|
+
var import_node_buffer43 = require("buffer");
|
|
11482
11617
|
var MAX_FLOW_QUERY_METADATA_KEY_BYTES = 64;
|
|
11483
11618
|
function normalizeStateMeta(value, state) {
|
|
11484
11619
|
if (value == null) return {};
|
|
@@ -11503,7 +11638,7 @@ function normalizeStateMeta(value, state) {
|
|
|
11503
11638
|
function metadataEntries(value, context) {
|
|
11504
11639
|
const entries = objectEntries(value ?? {}, context).map(([rawName, item]) => {
|
|
11505
11640
|
const name = rawName.trim();
|
|
11506
|
-
const size =
|
|
11641
|
+
const size = import_node_buffer43.Buffer.byteLength(name, "utf8");
|
|
11507
11642
|
if (size === 0 || size > MAX_FLOW_QUERY_METADATA_KEY_BYTES || name.startsWith("__")) {
|
|
11508
11643
|
throw new TypeError(`${context} key is invalid or reserved`);
|
|
11509
11644
|
}
|
|
@@ -11527,7 +11662,7 @@ function objectEntries(value, context) {
|
|
|
11527
11662
|
return keys.map((key) => [key, value[key]]);
|
|
11528
11663
|
}
|
|
11529
11664
|
function isPlainRecord(value) {
|
|
11530
|
-
if (typeof value !== "object" || value == null || Array.isArray(value) ||
|
|
11665
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer43.Buffer.isBuffer(value)) {
|
|
11531
11666
|
return false;
|
|
11532
11667
|
}
|
|
11533
11668
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -11597,7 +11732,7 @@ var FlowCollectionQuery = class {
|
|
|
11597
11732
|
const states = /* @__PURE__ */ new Set();
|
|
11598
11733
|
for (const [rawState, metadata] of objectEntries(values, "stateMeta")) {
|
|
11599
11734
|
const state = requiredText(rawState, "stateMeta state").trim();
|
|
11600
|
-
const stateBytes =
|
|
11735
|
+
const stateBytes = import_node_buffer44.Buffer.byteLength(state, "utf8");
|
|
11601
11736
|
if (stateBytes === 0 || stateBytes > MAX_FLOW_QUERY_STATE_BYTES) {
|
|
11602
11737
|
throw new TypeError(
|
|
11603
11738
|
`stateMeta state names must be 1..${MAX_FLOW_QUERY_STATE_BYTES} bytes`
|
|
@@ -11776,7 +11911,7 @@ function requiredPartition(value) {
|
|
|
11776
11911
|
"FLOW.QUERY convenience methods require a partition key"
|
|
11777
11912
|
);
|
|
11778
11913
|
}
|
|
11779
|
-
const size =
|
|
11914
|
+
const size = import_node_buffer44.Buffer.byteLength(value, "utf8");
|
|
11780
11915
|
if (size === 0 || size > MAX_FLOW_QUERY_PARTITION_BYTES) {
|
|
11781
11916
|
throw new TypeError(
|
|
11782
11917
|
`FLOW.QUERY partition key must be 1..${MAX_FLOW_QUERY_PARTITION_BYTES} bytes`
|
|
@@ -11824,20 +11959,23 @@ function requiredText(value, context) {
|
|
|
11824
11959
|
return value;
|
|
11825
11960
|
}
|
|
11826
11961
|
function queryParameter(value, context) {
|
|
11827
|
-
if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" ||
|
|
11962
|
+
if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" || import_node_buffer44.Buffer.isBuffer(value)) {
|
|
11828
11963
|
return value;
|
|
11829
11964
|
}
|
|
11830
11965
|
throw new TypeError(`${context} must be a scalar FLOW.QUERY parameter`);
|
|
11831
11966
|
}
|
|
11832
11967
|
|
|
11833
11968
|
// src/flow-query-response.ts
|
|
11834
|
-
var
|
|
11969
|
+
var import_node_buffer48 = require("buffer");
|
|
11970
|
+
|
|
11971
|
+
// src/flow-query-diagnostic-response.ts
|
|
11972
|
+
var import_node_buffer46 = require("buffer");
|
|
11835
11973
|
|
|
11836
11974
|
// src/flow-query-response-validation.ts
|
|
11837
|
-
var
|
|
11975
|
+
var import_node_buffer45 = require("buffer");
|
|
11838
11976
|
function requiredMap2(value, context) {
|
|
11839
11977
|
if (value instanceof Map) return value;
|
|
11840
|
-
if (typeof value !== "object" || value == null || Array.isArray(value) ||
|
|
11978
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || import_node_buffer45.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
11841
11979
|
throw decodeError(`${context} must be a map`, value);
|
|
11842
11980
|
}
|
|
11843
11981
|
return value;
|
|
@@ -11894,7 +12032,7 @@ function normalizeMetadataValue(value, context, budget, ancestors, depth) {
|
|
|
11894
12032
|
if (!value.isWellFormed()) throw decodeError(`${context} contains invalid text`, value);
|
|
11895
12033
|
return value;
|
|
11896
12034
|
}
|
|
11897
|
-
if (
|
|
12035
|
+
if (import_node_buffer45.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
11898
12036
|
const decoded = strictText2(value);
|
|
11899
12037
|
if (decoded == null) throw decodeError(`${context} contains invalid UTF-8`, value);
|
|
11900
12038
|
return decoded;
|
|
@@ -11973,7 +12111,7 @@ function optionalText2(mapping, name, context) {
|
|
|
11973
12111
|
}
|
|
11974
12112
|
function requiredBoundedText2(mapping, name, context, maximumBytes) {
|
|
11975
12113
|
const value = requiredText2(mapping, name, context);
|
|
11976
|
-
if (
|
|
12114
|
+
if (import_node_buffer45.Buffer.byteLength(value, "utf8") > maximumBytes) {
|
|
11977
12115
|
throw decodeError(
|
|
11978
12116
|
`${context} ${name} exceeds ${maximumBytes} bytes`,
|
|
11979
12117
|
mapping
|
|
@@ -11986,7 +12124,7 @@ function boundedText(value, context, maximumBytes) {
|
|
|
11986
12124
|
if (decoded == null || decoded.length === 0) {
|
|
11987
12125
|
throw decodeError(`${context} must be non-empty text`, value);
|
|
11988
12126
|
}
|
|
11989
|
-
if (
|
|
12127
|
+
if (import_node_buffer45.Buffer.byteLength(decoded, "utf8") > maximumBytes) {
|
|
11990
12128
|
throw decodeError(`${context} exceeds ${maximumBytes} bytes`, value);
|
|
11991
12129
|
}
|
|
11992
12130
|
return decoded;
|
|
@@ -12040,10 +12178,10 @@ function positiveBoundedInteger(value, maximum, context) {
|
|
|
12040
12178
|
function hasKey(mapping, name) {
|
|
12041
12179
|
if (!(mapping instanceof Map)) return Object.hasOwn(mapping, name);
|
|
12042
12180
|
if (mapping.has(name)) return true;
|
|
12043
|
-
const binaryName =
|
|
12181
|
+
const binaryName = import_node_buffer45.Buffer.from(name);
|
|
12044
12182
|
for (const key of mapping.keys()) {
|
|
12045
|
-
if (
|
|
12046
|
-
if (key instanceof Uint8Array &&
|
|
12183
|
+
if (import_node_buffer45.Buffer.isBuffer(key) && key.equals(binaryName)) return true;
|
|
12184
|
+
if (key instanceof Uint8Array && import_node_buffer45.Buffer.from(key).equals(binaryName))
|
|
12047
12185
|
return true;
|
|
12048
12186
|
}
|
|
12049
12187
|
return false;
|
|
@@ -12054,7 +12192,7 @@ function decodeError(message, raw) {
|
|
|
12054
12192
|
function strictText2(value) {
|
|
12055
12193
|
if (typeof value === "string")
|
|
12056
12194
|
return value.isWellFormed() ? value : void 0;
|
|
12057
|
-
if (
|
|
12195
|
+
if (import_node_buffer45.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
12058
12196
|
try {
|
|
12059
12197
|
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
12060
12198
|
} catch {
|
|
@@ -12087,189 +12225,35 @@ var FlowQueryError = class extends FerricStoreError {
|
|
|
12087
12225
|
}
|
|
12088
12226
|
};
|
|
12089
12227
|
|
|
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
|
-
}
|
|
12228
|
+
// src/flow-query-diagnostic-response.ts
|
|
12229
|
+
var MIN_SIGNED_64 = -(1n << 63n);
|
|
12230
|
+
var MAX_SIGNED_642 = (1n << 63n) - 1n;
|
|
12231
|
+
var DIAGNOSTIC_TEXT_BYTES = 1024;
|
|
12232
|
+
var DIAGNOSTIC_CONTEXT_ENTRIES = 16;
|
|
12233
|
+
var DIAGNOSTIC_CONTEXT_LIST_ITEMS = 32;
|
|
12234
|
+
var DIAGNOSTIC_CONTEXT_KEY_BYTES = 128;
|
|
12235
|
+
var DIAGNOSTIC_CONTEXT_DEPTH = 6;
|
|
12236
|
+
var DIAGNOSTIC_CONTEXT_NODES = 512;
|
|
12259
12237
|
function tryDecodeFlowQueryError(value, cause) {
|
|
12260
12238
|
try {
|
|
12261
12239
|
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic");
|
|
12262
|
-
const
|
|
12263
|
-
const context = contextValue == null ? void 0 : freezeMetadataMap(
|
|
12264
|
-
requiredMap2(contextValue, "FLOW.QUERY diagnostic context"),
|
|
12265
|
-
"FLOW.QUERY diagnostic context"
|
|
12266
|
-
);
|
|
12240
|
+
const context = decodeDiagnosticContext(field(mapping, "context"));
|
|
12267
12241
|
const position = decodePosition(field(mapping, "position"));
|
|
12268
12242
|
return new FlowQueryError({
|
|
12269
|
-
code:
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12243
|
+
code: requiredBoundedText2(
|
|
12244
|
+
mapping,
|
|
12245
|
+
"code",
|
|
12246
|
+
"FLOW.QUERY diagnostic",
|
|
12247
|
+
DIAGNOSTIC_TEXT_BYTES
|
|
12248
|
+
),
|
|
12249
|
+
message: requiredBoundedText2(
|
|
12250
|
+
mapping,
|
|
12251
|
+
"message",
|
|
12252
|
+
"FLOW.QUERY diagnostic",
|
|
12253
|
+
DIAGNOSTIC_TEXT_BYTES
|
|
12254
|
+
),
|
|
12255
|
+
detail: optionalDiagnosticText(mapping, "detail"),
|
|
12256
|
+
hint: optionalDiagnosticText(mapping, "hint"),
|
|
12273
12257
|
retryable: requiredBoolean(mapping, "retryable", "FLOW.QUERY diagnostic"),
|
|
12274
12258
|
safeToRetry: requiredBoolean(mapping, "safe_to_retry", "FLOW.QUERY diagnostic"),
|
|
12275
12259
|
retryAfterMs: nonNegativeInteger(
|
|
@@ -12286,49 +12270,724 @@ function tryDecodeFlowQueryError(value, cause) {
|
|
|
12286
12270
|
throw error;
|
|
12287
12271
|
}
|
|
12288
12272
|
}
|
|
12289
|
-
function
|
|
12290
|
-
const
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
);
|
|
12273
|
+
function optionalDiagnosticText(mapping, name) {
|
|
12274
|
+
const value = optionalText2(mapping, name, "FLOW.QUERY diagnostic");
|
|
12275
|
+
if (value != null && import_node_buffer46.Buffer.byteLength(value, "utf8") > DIAGNOSTIC_TEXT_BYTES) {
|
|
12276
|
+
throw decodeError(
|
|
12277
|
+
`FLOW.QUERY diagnostic ${name} exceeds ${DIAGNOSTIC_TEXT_BYTES} bytes`,
|
|
12278
|
+
mapping
|
|
12279
|
+
);
|
|
12280
|
+
}
|
|
12281
|
+
return value;
|
|
12282
|
+
}
|
|
12283
|
+
function decodeDiagnosticContext(value) {
|
|
12284
|
+
if (value == null) return void 0;
|
|
12285
|
+
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic context");
|
|
12286
|
+
const size = mapping instanceof Map ? mapping.size : Object.keys(mapping).length;
|
|
12287
|
+
if (size > DIAGNOSTIC_CONTEXT_ENTRIES) {
|
|
12288
|
+
throw decodeError("FLOW.QUERY diagnostic context contains too many entries", value);
|
|
12289
|
+
}
|
|
12290
|
+
validateDiagnosticContextValue(
|
|
12291
|
+
mapping,
|
|
12292
|
+
DIAGNOSTIC_CONTEXT_DEPTH,
|
|
12293
|
+
{ remaining: DIAGNOSTIC_CONTEXT_NODES }
|
|
12294
|
+
);
|
|
12295
|
+
return freezeMetadataMap(mapping, "FLOW.QUERY diagnostic context");
|
|
12296
|
+
}
|
|
12297
|
+
function validateDiagnosticContextValue(value, depth, budget) {
|
|
12298
|
+
consumeDiagnosticContextNode(value, budget);
|
|
12299
|
+
if (value == null || typeof value === "boolean") return;
|
|
12300
|
+
if (typeof value === "number") {
|
|
12301
|
+
if (Number.isSafeInteger(value)) return;
|
|
12302
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid integer", value);
|
|
12303
|
+
}
|
|
12304
|
+
if (typeof value === "bigint") {
|
|
12305
|
+
if (value >= MIN_SIGNED_64 && value <= MAX_SIGNED_642) return;
|
|
12306
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid integer", value);
|
|
12307
|
+
}
|
|
12308
|
+
const text3 = diagnosticContextText(value);
|
|
12309
|
+
if (text3 != null) {
|
|
12310
|
+
if (import_node_buffer46.Buffer.byteLength(text3, "utf8") <= DIAGNOSTIC_TEXT_BYTES) return;
|
|
12311
|
+
throw decodeError("FLOW.QUERY diagnostic context contains oversized text", value);
|
|
12312
|
+
}
|
|
12313
|
+
if (depth <= 0) {
|
|
12314
|
+
throw decodeError("FLOW.QUERY diagnostic context exceeds its maximum depth", value);
|
|
12315
|
+
}
|
|
12316
|
+
if (Array.isArray(value)) {
|
|
12317
|
+
if (value.length > DIAGNOSTIC_CONTEXT_LIST_ITEMS) {
|
|
12318
|
+
throw decodeError("FLOW.QUERY diagnostic context list is too large", value);
|
|
12319
|
+
}
|
|
12320
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12321
|
+
if (!Object.hasOwn(value, index)) {
|
|
12322
|
+
throw decodeError("FLOW.QUERY diagnostic context list must be dense", value);
|
|
12323
|
+
}
|
|
12324
|
+
validateDiagnosticContextValue(value[index], depth - 1, budget);
|
|
12325
|
+
}
|
|
12326
|
+
return;
|
|
12327
|
+
}
|
|
12328
|
+
if (value instanceof Map || isDiagnosticContextRecord(value)) {
|
|
12329
|
+
const entries = value instanceof Map ? value.entries() : Object.entries(value);
|
|
12330
|
+
const size = value instanceof Map ? value.size : Object.keys(value).length;
|
|
12331
|
+
if (size > DIAGNOSTIC_CONTEXT_ENTRIES) {
|
|
12332
|
+
throw decodeError("FLOW.QUERY diagnostic context map is too large", value);
|
|
12333
|
+
}
|
|
12334
|
+
for (const [rawKey, item] of entries) {
|
|
12335
|
+
const key = diagnosticContextText(rawKey);
|
|
12336
|
+
if (key == null || key.length === 0 || import_node_buffer46.Buffer.byteLength(key, "utf8") > DIAGNOSTIC_CONTEXT_KEY_BYTES) {
|
|
12337
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid key", value);
|
|
12338
|
+
}
|
|
12339
|
+
validateDiagnosticContextValue(item, depth - 1, budget);
|
|
12340
|
+
}
|
|
12341
|
+
return;
|
|
12342
|
+
}
|
|
12343
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an unsupported value", value);
|
|
12344
|
+
}
|
|
12345
|
+
function consumeDiagnosticContextNode(value, budget) {
|
|
12346
|
+
if (budget.remaining <= 0) {
|
|
12347
|
+
throw decodeError("FLOW.QUERY diagnostic context exceeds its node limit", value);
|
|
12348
|
+
}
|
|
12349
|
+
budget.remaining -= 1;
|
|
12350
|
+
}
|
|
12351
|
+
function diagnosticContextText(value) {
|
|
12352
|
+
if (typeof value === "string") return value.isWellFormed() ? value : void 0;
|
|
12353
|
+
if (!import_node_buffer46.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return void 0;
|
|
12354
|
+
try {
|
|
12355
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
12356
|
+
} catch {
|
|
12357
|
+
return void 0;
|
|
12358
|
+
}
|
|
12359
|
+
}
|
|
12360
|
+
function isDiagnosticContextRecord(value) {
|
|
12361
|
+
if (typeof value !== "object" || value == null) return false;
|
|
12362
|
+
const prototype = Object.getPrototypeOf(value);
|
|
12363
|
+
return prototype === Object.prototype || prototype === null;
|
|
12364
|
+
}
|
|
12365
|
+
function decodePosition(value) {
|
|
12366
|
+
if (value == null) return void 0;
|
|
12367
|
+
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic position");
|
|
12368
|
+
return Object.freeze({
|
|
12369
|
+
byte: positiveInteger(field(mapping, "byte"), "FLOW.QUERY diagnostic position byte"),
|
|
12370
|
+
line: positiveInteger(field(mapping, "line"), "FLOW.QUERY diagnostic position line"),
|
|
12371
|
+
column: positiveInteger(
|
|
12372
|
+
field(mapping, "column"),
|
|
12373
|
+
"FLOW.QUERY diagnostic position column"
|
|
12374
|
+
)
|
|
12375
|
+
});
|
|
12376
|
+
}
|
|
12377
|
+
|
|
12378
|
+
// src/flow-query-index-contract.ts
|
|
12379
|
+
var import_node_buffer47 = require("buffer");
|
|
12380
|
+
var FLOW_QUERY_BUILD_PHASES = ["pending", "snapshot", "backfill", "done"];
|
|
12381
|
+
var FLOW_QUERY_VALIDATION_PHASES = [
|
|
12382
|
+
"pending",
|
|
12383
|
+
"source",
|
|
12384
|
+
"index",
|
|
12385
|
+
"counter",
|
|
12386
|
+
"cleanup",
|
|
12387
|
+
"done"
|
|
12388
|
+
];
|
|
12389
|
+
var FLOW_QUERY_RETIREMENT_PHASES = [
|
|
12390
|
+
"pending",
|
|
12391
|
+
"fence",
|
|
12392
|
+
"index",
|
|
12393
|
+
"counter",
|
|
12394
|
+
"reverse",
|
|
12395
|
+
"cleanup",
|
|
12396
|
+
"done"
|
|
12397
|
+
];
|
|
12398
|
+
var IDENTIFIER = /^[A-Za-z0-9_.:-]+$/u;
|
|
12399
|
+
var UNQUOTED_METADATA = /^[A-Za-z0-9_-]+$/u;
|
|
12400
|
+
var ATTRIBUTE_SELECTOR = /^attribute\['((?:[^']|'')*)'\]$/u;
|
|
12401
|
+
var STATE_META_SELECTOR = /^state_meta\['((?:[^']|'')*)'\]\['((?:[^']|'')*)'\]$/u;
|
|
12402
|
+
var INTEGER_FIELDS = /* @__PURE__ */ new Set([
|
|
12403
|
+
"version",
|
|
12404
|
+
"priority",
|
|
12405
|
+
"created_at_ms",
|
|
12406
|
+
"updated_at_ms",
|
|
12407
|
+
"next_run_at_ms",
|
|
12408
|
+
"lease_deadline_ms",
|
|
12409
|
+
"attempts",
|
|
12410
|
+
"max_active_ms"
|
|
12411
|
+
]);
|
|
12412
|
+
var BUILTIN_FIELDS = /* @__PURE__ */ new Set([
|
|
12413
|
+
...INTEGER_FIELDS,
|
|
12414
|
+
"partition_key",
|
|
12415
|
+
"run_id",
|
|
12416
|
+
"event_id",
|
|
12417
|
+
"type",
|
|
12418
|
+
"state",
|
|
12419
|
+
"run_state",
|
|
12420
|
+
"parent_flow_id",
|
|
12421
|
+
"root_flow_id",
|
|
12422
|
+
"correlation_id"
|
|
12423
|
+
]);
|
|
12424
|
+
var RETIREMENT_PROGRESS_FIELDS = [
|
|
12425
|
+
"phase_counts",
|
|
12426
|
+
"current_phases",
|
|
12427
|
+
"completed_shards",
|
|
12428
|
+
"total_shards",
|
|
12429
|
+
"deleted_entries",
|
|
12430
|
+
"deleted_bytes",
|
|
12431
|
+
"rewritten_reverse_rows"
|
|
12432
|
+
];
|
|
12433
|
+
function validateFlowQueryIndexContract(status, expectedId) {
|
|
12434
|
+
let previousId;
|
|
12435
|
+
let previousVersion;
|
|
12436
|
+
for (const index of status.indexes) {
|
|
12437
|
+
const version = BigInt(index.version);
|
|
12438
|
+
if (previousId != null && (index.id < previousId || index.id === previousId && previousVersion != null && version <= previousVersion)) {
|
|
12439
|
+
fail("indexes must be uniquely sorted by id and version", status.raw);
|
|
12440
|
+
}
|
|
12441
|
+
if (expectedId != null && index.id !== expectedId) {
|
|
12442
|
+
fail("filtered indexes do not match the requested id", status.raw);
|
|
12443
|
+
}
|
|
12444
|
+
previousId = index.id;
|
|
12445
|
+
previousVersion = version;
|
|
12446
|
+
validateIndex(index, status);
|
|
12447
|
+
}
|
|
12448
|
+
if (expectedId != null && status.indexes.length === 0) {
|
|
12449
|
+
fail("filtered indexes do not match the requested id", status.raw);
|
|
12450
|
+
}
|
|
12451
|
+
const hasUnavailableStatistics = status.indexes.some(
|
|
12452
|
+
(index) => index.statistics.status === "unavailable"
|
|
12453
|
+
);
|
|
12454
|
+
if (status.services.statisticsStore === "unavailable") {
|
|
12455
|
+
if (status.indexes.some((index) => index.statistics.status !== "unavailable")) {
|
|
12456
|
+
fail("statistics must be unavailable when the service is unavailable", status.raw);
|
|
12457
|
+
}
|
|
12458
|
+
} else if (hasUnavailableStatistics) {
|
|
12459
|
+
fail("statistics cannot be unavailable while the service is ready", status.raw);
|
|
12460
|
+
}
|
|
12461
|
+
}
|
|
12462
|
+
function validateIndex(index, status) {
|
|
12463
|
+
if (!IDENTIFIER.test(index.id) || index.workloads.some((workload) => !IDENTIFIER.test(workload))) {
|
|
12464
|
+
fail("index identity contains invalid characters", index.raw);
|
|
12465
|
+
}
|
|
12466
|
+
const first = index.fields[0];
|
|
12467
|
+
if (first?.name !== "partition_key" || first.direction !== "asc" || first.encoding !== "hashed") {
|
|
12468
|
+
fail("index must begin with partition_key asc hashed", index.raw);
|
|
12469
|
+
}
|
|
12470
|
+
let attributeFields = 0;
|
|
12471
|
+
for (const indexField of index.fields) {
|
|
12472
|
+
if (indexField.encoding === "hashed" && indexField.direction !== "asc") {
|
|
12473
|
+
fail("hashed index fields must be ascending", index.raw);
|
|
12474
|
+
}
|
|
12475
|
+
const kind = fieldKind(indexField.name);
|
|
12476
|
+
if (kind == null) fail("index contains an unsupported field selector", index.raw);
|
|
12477
|
+
if (indexField.encoding === "ordered" && kind !== "integer") {
|
|
12478
|
+
fail("ordered index fields must be integers", index.raw);
|
|
12479
|
+
}
|
|
12480
|
+
if (kind === "attribute") attributeFields += 1;
|
|
12481
|
+
}
|
|
12482
|
+
if (attributeFields > 1) fail("index may contain at most one attribute field", index.raw);
|
|
12483
|
+
for (const prefix of index.countPrefixes) {
|
|
12484
|
+
if (index.fields.slice(0, prefix).some((field3) => field3.encoding !== "hashed")) {
|
|
12485
|
+
fail("count prefixes may cover only hashed fields", index.raw);
|
|
12486
|
+
}
|
|
12487
|
+
}
|
|
12488
|
+
if (index.coveringFields.length > 0) {
|
|
12489
|
+
if (index.coveringFields.some((field3) => fieldKind(field3) == null)) {
|
|
12490
|
+
fail("index contains an unsupported covering field selector", index.raw);
|
|
12491
|
+
}
|
|
12492
|
+
const required = /* @__PURE__ */ new Set(["run_id", "version", ...index.fields.map((field3) => field3.name)]);
|
|
12493
|
+
if ([...required].some((field3) => !index.coveringFields.includes(field3))) {
|
|
12494
|
+
fail("index covering fields omit an identity or index field", index.raw);
|
|
12495
|
+
}
|
|
12496
|
+
}
|
|
12497
|
+
if (index.countPrefixes.length > 0 !== (index.format.counter != null)) {
|
|
12498
|
+
fail("index counter format is inconsistent with count prefixes", index.raw);
|
|
12499
|
+
}
|
|
12500
|
+
validateProgress(index.build, FLOW_QUERY_BUILD_PHASES, "build");
|
|
12501
|
+
validateProgress(index.validation, FLOW_QUERY_VALIDATION_PHASES, "validation");
|
|
12502
|
+
if (index.retirement.status === "not_applicable") {
|
|
12503
|
+
if (RETIREMENT_PROGRESS_FIELDS.some((name) => hasKey(index.retirement.raw, name))) {
|
|
12504
|
+
fail("not_applicable retirement must not contain progress", index.retirement.raw);
|
|
12505
|
+
}
|
|
12506
|
+
} else {
|
|
12507
|
+
const retirement = index.retirement;
|
|
12508
|
+
if (retirement.phaseCounts == null || retirement.currentPhases == null || retirement.completedShards == null || retirement.totalShards == null) {
|
|
12509
|
+
fail("retirement progress is incomplete", retirement.raw);
|
|
12510
|
+
}
|
|
12511
|
+
validateProgress(
|
|
12512
|
+
{
|
|
12513
|
+
phaseCounts: retirement.phaseCounts,
|
|
12514
|
+
currentPhases: retirement.currentPhases,
|
|
12515
|
+
completedShards: retirement.completedShards,
|
|
12516
|
+
totalShards: retirement.totalShards,
|
|
12517
|
+
raw: retirement.raw
|
|
12518
|
+
},
|
|
12519
|
+
FLOW_QUERY_RETIREMENT_PHASES,
|
|
12520
|
+
"retirement"
|
|
12521
|
+
);
|
|
12522
|
+
}
|
|
12523
|
+
const totals = new Set(
|
|
12524
|
+
[
|
|
12525
|
+
index.coverage.totalShards,
|
|
12526
|
+
index.build.totalShards,
|
|
12527
|
+
index.validation.totalShards,
|
|
12528
|
+
...index.retirement.totalShards == null ? [] : [index.retirement.totalShards]
|
|
12529
|
+
].map(indexInteger)
|
|
12530
|
+
);
|
|
12531
|
+
if (totals.size !== 1) fail("index shard totals are inconsistent", index.raw);
|
|
12532
|
+
if (!sameIndexInteger(index.coverage.completeShards, index.build.completedShards)) {
|
|
12533
|
+
fail("coverage and build completion are inconsistent", index.raw);
|
|
12534
|
+
}
|
|
12535
|
+
if (index.coverage.validation !== index.validation.status) {
|
|
12536
|
+
fail("coverage and validation status are inconsistent", index.raw);
|
|
12537
|
+
}
|
|
12538
|
+
const queryable = index.state === "active" && sameIndexInteger(
|
|
12539
|
+
index.coverage.completeShards,
|
|
12540
|
+
index.coverage.totalShards
|
|
12541
|
+
) && index.coverage.validation === "passed";
|
|
12542
|
+
if (index.queryable !== queryable) fail("index queryable flag is inconsistent", index.raw);
|
|
12543
|
+
validateLifecycle(index);
|
|
12544
|
+
validateValidation(index);
|
|
12545
|
+
validateStatistics(index, status);
|
|
12546
|
+
}
|
|
12547
|
+
function validateProgress(progress, phases, section) {
|
|
12548
|
+
const entries = Object.entries(progress.phaseCounts);
|
|
12549
|
+
if (entries.length === 0 || entries.some(
|
|
12550
|
+
([phase, count]) => !phases.includes(phase) || indexInteger(count) <= 0n
|
|
12551
|
+
) || entries.reduce((sum, [, count]) => sum + indexInteger(count), 0n) !== indexInteger(progress.totalShards)) {
|
|
12552
|
+
fail(`${section} phase_counts are invalid`, progress.raw);
|
|
12553
|
+
}
|
|
12554
|
+
const current = phases.filter((phase) => Object.hasOwn(progress.phaseCounts, phase));
|
|
12555
|
+
if (current.length !== progress.currentPhases.length || current.some((phase, position) => phase !== progress.currentPhases[position])) {
|
|
12556
|
+
fail(`${section} current_phases are inconsistent`, progress.raw);
|
|
12557
|
+
}
|
|
12558
|
+
if (!sameIndexInteger(
|
|
12559
|
+
progress.completedShards,
|
|
12560
|
+
progress.phaseCounts.done ?? 0
|
|
12561
|
+
)) {
|
|
12562
|
+
fail(`${section} completed_shards is inconsistent`, progress.raw);
|
|
12563
|
+
}
|
|
12564
|
+
}
|
|
12565
|
+
function validateLifecycle(index) {
|
|
12566
|
+
const built = sameIndexInteger(
|
|
12567
|
+
index.build.completedShards,
|
|
12568
|
+
index.build.totalShards
|
|
12569
|
+
);
|
|
12570
|
+
const validation = index.validation.status;
|
|
12571
|
+
const retirement = index.retirement.status;
|
|
12572
|
+
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";
|
|
12573
|
+
if (!valid) fail("index lifecycle fields are inconsistent", index.raw);
|
|
12574
|
+
}
|
|
12575
|
+
function validateValidation(index) {
|
|
12576
|
+
const validation = index.validation;
|
|
12577
|
+
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;
|
|
12578
|
+
if (!valid) fail("validation status fields are inconsistent", validation.raw);
|
|
12579
|
+
}
|
|
12580
|
+
function validateStatistics(index, status) {
|
|
12581
|
+
const statistics = index.statistics;
|
|
12582
|
+
const times = [
|
|
12583
|
+
statistics.oldestCollectedAtMs,
|
|
12584
|
+
statistics.newestCollectedAtMs,
|
|
12585
|
+
statistics.oldestAgeMs,
|
|
12586
|
+
statistics.newestAgeMs
|
|
12587
|
+
];
|
|
12588
|
+
if (indexInteger(statistics.samples) === 0n) {
|
|
12589
|
+
if (statistics.status !== "missing" && statistics.status !== "unavailable" || times.some((value) => value != null)) {
|
|
12590
|
+
fail("empty statistics fields are inconsistent", statistics.raw);
|
|
12591
|
+
}
|
|
12592
|
+
return;
|
|
12593
|
+
}
|
|
12594
|
+
if (times.some((value) => value == null)) {
|
|
12595
|
+
fail("sampled statistics require timestamps and ages", statistics.raw);
|
|
12596
|
+
}
|
|
12597
|
+
const [oldest, newest, oldestAge, newestAge] = times;
|
|
12598
|
+
if (indexInteger(oldest) > indexInteger(newest) || indexInteger(oldestAge) !== indexAge(status.observedAtMs, oldest) || indexInteger(newestAge) !== indexAge(status.observedAtMs, newest)) {
|
|
12599
|
+
fail("statistics timestamps or ages are inconsistent", statistics.raw);
|
|
12600
|
+
}
|
|
12601
|
+
const expected = sameIndexInteger(statistics.freshSamples, statistics.samples) ? ["fresh"] : indexInteger(statistics.freshSamples) === 0n ? indexInteger(statistics.futureSamples) > 0n ? ["stale", "future"] : ["stale"] : ["mixed"];
|
|
12602
|
+
if (!expected.includes(statistics.status)) {
|
|
12603
|
+
fail("statistics status does not match sample counters", statistics.raw);
|
|
12604
|
+
}
|
|
12605
|
+
}
|
|
12606
|
+
function fieldKind(name) {
|
|
12607
|
+
if (BUILTIN_FIELDS.has(name)) return INTEGER_FIELDS.has(name) ? "integer" : "keyword";
|
|
12608
|
+
const parts = name.split(".");
|
|
12609
|
+
if (parts.length === 2 && parts[0] === "attribute" && validUnquoted(parts[1] ?? "")) return "attribute";
|
|
12610
|
+
if (parts.length === 3 && parts[0] === "state_meta" && validUnquoted(parts[1] ?? "") && validUnquoted(parts[2] ?? "")) return "state_meta";
|
|
12611
|
+
const attribute = ATTRIBUTE_SELECTOR.exec(name);
|
|
12612
|
+
if (attribute != null) {
|
|
12613
|
+
const metadata = (attribute[1] ?? "").replaceAll("''", "'");
|
|
12614
|
+
if (validMetadata(metadata, true) && name === externalSelector("attribute", metadata)) return "attribute";
|
|
12615
|
+
}
|
|
12616
|
+
const stateMeta = STATE_META_SELECTOR.exec(name);
|
|
12617
|
+
if (stateMeta != null) {
|
|
12618
|
+
const state = (stateMeta[1] ?? "").replaceAll("''", "'");
|
|
12619
|
+
const metadata = (stateMeta[2] ?? "").replaceAll("''", "'");
|
|
12620
|
+
if (validMetadata(state, false) && validMetadata(metadata, true) && name === externalSelector("state_meta", state, metadata)) return "state_meta";
|
|
12621
|
+
}
|
|
12622
|
+
return void 0;
|
|
12623
|
+
}
|
|
12624
|
+
function validUnquoted(value) {
|
|
12625
|
+
return !value.startsWith("__") && UNQUOTED_METADATA.test(value) && import_node_buffer47.Buffer.byteLength(value, "ascii") <= 64;
|
|
12626
|
+
}
|
|
12627
|
+
function validMetadata(value, rejectReserved) {
|
|
12628
|
+
return value.length > 0 && import_node_buffer47.Buffer.byteLength(value, "utf8") <= 64 && (!rejectReserved || !value.startsWith("__"));
|
|
12629
|
+
}
|
|
12630
|
+
function externalSelector(root, ...segments) {
|
|
12631
|
+
return segments.every(validUnquoted) ? [root, ...segments].join(".") : root + segments.map((segment) => `['${segment.replaceAll("'", "''")}']`).join("");
|
|
12632
|
+
}
|
|
12633
|
+
function sameIndexInteger(left, right) {
|
|
12634
|
+
return indexInteger(left) === indexInteger(right);
|
|
12635
|
+
}
|
|
12636
|
+
function indexAge(observedAtMs, collectedAtMs) {
|
|
12637
|
+
const age = indexInteger(observedAtMs) - indexInteger(collectedAtMs);
|
|
12638
|
+
return age < 0n ? 0n : age;
|
|
12639
|
+
}
|
|
12640
|
+
function indexInteger(value) {
|
|
12641
|
+
return BigInt(value);
|
|
12642
|
+
}
|
|
12643
|
+
function fail(message, raw) {
|
|
12644
|
+
throw decodeError(`FLOW.QUERY.INDEXES ${message}`, raw);
|
|
12645
|
+
}
|
|
12646
|
+
|
|
12647
|
+
// src/flow-query-index-decode.ts
|
|
12648
|
+
var MAX_UNSIGNED_64 = (1n << 64n) - 1n;
|
|
12649
|
+
function decodeUniqueTextArray(value, context, maximum, maximumBytes) {
|
|
12650
|
+
if (!Array.isArray(value) || value.length > maximum) {
|
|
12651
|
+
throw decodeError(`${context} must be a bounded array`, value);
|
|
12652
|
+
}
|
|
12653
|
+
const result = new Array(value.length);
|
|
12654
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12655
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12656
|
+
if (!Object.hasOwn(value, index)) {
|
|
12657
|
+
throw decodeError(`${context} must be dense`, value);
|
|
12658
|
+
}
|
|
12659
|
+
const text3 = boundedText(
|
|
12660
|
+
value[index],
|
|
12661
|
+
`${context} entry ${index}`,
|
|
12662
|
+
maximumBytes
|
|
12663
|
+
);
|
|
12664
|
+
if (seen.has(text3)) {
|
|
12665
|
+
throw decodeError(`${context} contains duplicates`, value);
|
|
12666
|
+
}
|
|
12667
|
+
seen.add(text3);
|
|
12668
|
+
result[index] = text3;
|
|
12669
|
+
}
|
|
12670
|
+
return Object.freeze(result);
|
|
12671
|
+
}
|
|
12672
|
+
function requiredChoice(mapping, name, context, choices) {
|
|
12673
|
+
const value = requiredBoundedText2(mapping, name, context, 64);
|
|
12674
|
+
if (!choices.includes(value)) {
|
|
12675
|
+
throw decodeError(`${context} ${name} is unsupported`, mapping);
|
|
12676
|
+
}
|
|
12677
|
+
return value;
|
|
12678
|
+
}
|
|
12679
|
+
function optionalBoundedText(mapping, name, context, maximumBytes) {
|
|
12680
|
+
const value = field(mapping, name);
|
|
12681
|
+
if (value == null) return void 0;
|
|
12682
|
+
return boundedText(value, `${context} ${name}`, maximumBytes);
|
|
12683
|
+
}
|
|
12684
|
+
function optionalIndexInteger(mapping, name, context) {
|
|
12685
|
+
const value = field(mapping, name);
|
|
12686
|
+
return value == null ? void 0 : unsignedIndexInteger(value, `${context} ${name}`);
|
|
12687
|
+
}
|
|
12688
|
+
function indexCounter(mapping, name, section) {
|
|
12689
|
+
return unsignedIndexInteger(
|
|
12690
|
+
field(mapping, name),
|
|
12691
|
+
`FLOW.QUERY.INDEXES index ${section} ${name}`
|
|
12692
|
+
);
|
|
12693
|
+
}
|
|
12694
|
+
function unsignedIndexInteger(value, context) {
|
|
12695
|
+
return boundedInteger(value, MAX_UNSIGNED_64, context);
|
|
12696
|
+
}
|
|
12697
|
+
function positiveIndexInteger(value, context) {
|
|
12698
|
+
return positiveBoundedInteger(value, MAX_UNSIGNED_64, context);
|
|
12699
|
+
}
|
|
12700
|
+
function indexInteger2(value) {
|
|
12701
|
+
return BigInt(value);
|
|
12702
|
+
}
|
|
12703
|
+
|
|
12704
|
+
// src/flow-query-index-lifecycle-response.ts
|
|
12705
|
+
function decodeIndexCoverage(value) {
|
|
12706
|
+
const context = "FLOW.QUERY.INDEXES index coverage";
|
|
12707
|
+
const mapping = requiredMap2(value, context);
|
|
12708
|
+
const completeShards = unsignedIndexInteger(
|
|
12709
|
+
field(mapping, "complete_shards"),
|
|
12710
|
+
`${context} complete_shards`
|
|
12711
|
+
);
|
|
12712
|
+
const totalShards = positiveIndexInteger(
|
|
12713
|
+
field(mapping, "total_shards"),
|
|
12714
|
+
`${context} total_shards`
|
|
12715
|
+
);
|
|
12716
|
+
if (indexInteger2(completeShards) > indexInteger2(totalShards)) {
|
|
12717
|
+
throw decodeError(`${context} complete_shards exceeds total_shards`, value);
|
|
12718
|
+
}
|
|
12719
|
+
return Object.freeze({
|
|
12720
|
+
completeShards,
|
|
12721
|
+
totalShards,
|
|
12722
|
+
validation: requiredChoice(mapping, "validation", context, [
|
|
12723
|
+
"pending",
|
|
12724
|
+
"passed",
|
|
12725
|
+
"failed"
|
|
12726
|
+
]),
|
|
12727
|
+
raw: freezeMap(mapping)
|
|
12728
|
+
});
|
|
12729
|
+
}
|
|
12730
|
+
function decodeIndexBuild(value) {
|
|
12731
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES index build");
|
|
12732
|
+
const progress = decodeIndexProgress(
|
|
12733
|
+
mapping,
|
|
12734
|
+
"build",
|
|
12735
|
+
FLOW_QUERY_BUILD_PHASES
|
|
12736
|
+
);
|
|
12737
|
+
return Object.freeze({
|
|
12738
|
+
...progress,
|
|
12739
|
+
scannedRecords: indexCounter(mapping, "scanned_records", "build"),
|
|
12740
|
+
writtenEntries: indexCounter(mapping, "written_entries", "build"),
|
|
12741
|
+
writtenBytes: indexCounter(mapping, "written_bytes", "build")
|
|
12742
|
+
});
|
|
12743
|
+
}
|
|
12744
|
+
function decodeIndexValidation(value) {
|
|
12745
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES index validation");
|
|
12746
|
+
if (!hasKey(mapping, "failure_reason") || !hasKey(mapping, "validated_at_ms")) {
|
|
12747
|
+
throw decodeError(
|
|
12748
|
+
"FLOW.QUERY.INDEXES index validation is missing nullable fields",
|
|
12749
|
+
value
|
|
12750
|
+
);
|
|
12751
|
+
}
|
|
12752
|
+
const progress = decodeIndexProgress(
|
|
12753
|
+
mapping,
|
|
12754
|
+
"validation",
|
|
12755
|
+
FLOW_QUERY_VALIDATION_PHASES
|
|
12756
|
+
);
|
|
12757
|
+
return Object.freeze({
|
|
12758
|
+
...progress,
|
|
12759
|
+
status: requiredChoice(
|
|
12760
|
+
mapping,
|
|
12761
|
+
"status",
|
|
12762
|
+
"FLOW.QUERY.INDEXES index validation",
|
|
12763
|
+
["pending", "passed", "failed"]
|
|
12764
|
+
),
|
|
12765
|
+
checkedRecords: indexCounter(mapping, "checked_records", "validation"),
|
|
12766
|
+
checkedEntries: indexCounter(mapping, "checked_entries", "validation"),
|
|
12767
|
+
mismatches: indexCounter(mapping, "mismatches", "validation"),
|
|
12768
|
+
failureReason: optionalBoundedText(
|
|
12769
|
+
mapping,
|
|
12770
|
+
"failure_reason",
|
|
12771
|
+
"FLOW.QUERY.INDEXES index validation",
|
|
12772
|
+
128
|
|
12773
|
+
),
|
|
12774
|
+
validatedAtMs: optionalIndexInteger(
|
|
12775
|
+
mapping,
|
|
12776
|
+
"validated_at_ms",
|
|
12777
|
+
"FLOW.QUERY.INDEXES index validation"
|
|
12778
|
+
)
|
|
12779
|
+
});
|
|
12780
|
+
}
|
|
12781
|
+
function decodeIndexRetirement(value) {
|
|
12782
|
+
const context = "FLOW.QUERY.INDEXES index retirement";
|
|
12783
|
+
const mapping = requiredMap2(value, context);
|
|
12784
|
+
const status = requiredChoice(mapping, "status", context, [
|
|
12785
|
+
"not_applicable",
|
|
12786
|
+
"pending",
|
|
12787
|
+
"complete"
|
|
12788
|
+
]);
|
|
12789
|
+
if (status === "not_applicable") {
|
|
12790
|
+
return Object.freeze({ status, raw: freezeMap(mapping) });
|
|
12791
|
+
}
|
|
12792
|
+
const completedShards = unsignedIndexInteger(
|
|
12793
|
+
field(mapping, "completed_shards"),
|
|
12794
|
+
`${context} completed_shards`
|
|
12795
|
+
);
|
|
12796
|
+
const totalShards = positiveIndexInteger(
|
|
12797
|
+
field(mapping, "total_shards"),
|
|
12798
|
+
`${context} total_shards`
|
|
12799
|
+
);
|
|
12800
|
+
if (indexInteger2(completedShards) > indexInteger2(totalShards)) {
|
|
12801
|
+
throw decodeError(
|
|
12802
|
+
`${context} completed_shards exceeds total_shards`,
|
|
12803
|
+
mapping
|
|
12804
|
+
);
|
|
12805
|
+
}
|
|
12806
|
+
return Object.freeze({
|
|
12807
|
+
status,
|
|
12808
|
+
phaseCounts: decodePhaseCounts(
|
|
12809
|
+
field(mapping, "phase_counts"),
|
|
12810
|
+
"retirement"
|
|
12811
|
+
),
|
|
12812
|
+
currentPhases: decodeAllowedPhases(
|
|
12813
|
+
field(mapping, "current_phases"),
|
|
12814
|
+
"retirement",
|
|
12815
|
+
FLOW_QUERY_RETIREMENT_PHASES
|
|
12816
|
+
),
|
|
12817
|
+
completedShards,
|
|
12818
|
+
totalShards,
|
|
12819
|
+
deletedEntries: indexCounter(mapping, "deleted_entries", "retirement"),
|
|
12820
|
+
deletedBytes: indexCounter(mapping, "deleted_bytes", "retirement"),
|
|
12821
|
+
rewrittenReverseRows: indexCounter(
|
|
12822
|
+
mapping,
|
|
12823
|
+
"rewritten_reverse_rows",
|
|
12824
|
+
"retirement"
|
|
12825
|
+
),
|
|
12826
|
+
raw: freezeMap(mapping)
|
|
12827
|
+
});
|
|
12828
|
+
}
|
|
12829
|
+
function decodeIndexStatistics(value) {
|
|
12830
|
+
const context = "FLOW.QUERY.INDEXES index statistics";
|
|
12831
|
+
const mapping = requiredMap2(value, context);
|
|
12832
|
+
for (const name of [
|
|
12833
|
+
"oldest_collected_at_ms",
|
|
12834
|
+
"newest_collected_at_ms",
|
|
12835
|
+
"oldest_age_ms",
|
|
12836
|
+
"newest_age_ms"
|
|
12837
|
+
]) {
|
|
12838
|
+
if (!hasKey(mapping, name)) {
|
|
12839
|
+
throw decodeError(
|
|
12840
|
+
`${context} is missing required nullable fields`,
|
|
12841
|
+
value
|
|
12842
|
+
);
|
|
12843
|
+
}
|
|
12844
|
+
}
|
|
12845
|
+
const samples = indexCounter(mapping, "samples", "statistics");
|
|
12846
|
+
const freshSamples = indexCounter(mapping, "fresh_samples", "statistics");
|
|
12847
|
+
const staleSamples = indexCounter(mapping, "stale_samples", "statistics");
|
|
12848
|
+
const futureSamples = indexCounter(mapping, "future_samples", "statistics");
|
|
12849
|
+
if (indexInteger2(freshSamples) + indexInteger2(staleSamples) !== indexInteger2(samples) || indexInteger2(futureSamples) > indexInteger2(staleSamples)) {
|
|
12850
|
+
throw decodeError(`${context} counters are inconsistent`, value);
|
|
12851
|
+
}
|
|
12852
|
+
return Object.freeze({
|
|
12853
|
+
status: requiredChoice(mapping, "status", context, [
|
|
12854
|
+
"fresh",
|
|
12855
|
+
"stale",
|
|
12856
|
+
"future",
|
|
12857
|
+
"mixed",
|
|
12858
|
+
"missing",
|
|
12859
|
+
"unavailable"
|
|
12860
|
+
]),
|
|
12861
|
+
samples,
|
|
12862
|
+
freshSamples,
|
|
12863
|
+
staleSamples,
|
|
12864
|
+
futureSamples,
|
|
12865
|
+
oldestCollectedAtMs: optionalIndexInteger(
|
|
12866
|
+
mapping,
|
|
12867
|
+
"oldest_collected_at_ms",
|
|
12868
|
+
context
|
|
12869
|
+
),
|
|
12870
|
+
newestCollectedAtMs: optionalIndexInteger(
|
|
12871
|
+
mapping,
|
|
12872
|
+
"newest_collected_at_ms",
|
|
12873
|
+
context
|
|
12874
|
+
),
|
|
12875
|
+
oldestAgeMs: optionalIndexInteger(mapping, "oldest_age_ms", context),
|
|
12876
|
+
newestAgeMs: optionalIndexInteger(mapping, "newest_age_ms", context),
|
|
12877
|
+
raw: freezeMap(mapping)
|
|
12878
|
+
});
|
|
12879
|
+
}
|
|
12880
|
+
function decodeIndexProgress(mapping, section, allowedPhases) {
|
|
12881
|
+
const context = `FLOW.QUERY.INDEXES index ${section}`;
|
|
12882
|
+
const completedShards = unsignedIndexInteger(
|
|
12883
|
+
field(mapping, "completed_shards"),
|
|
12884
|
+
`${context} completed_shards`
|
|
12885
|
+
);
|
|
12886
|
+
const totalShards = positiveIndexInteger(
|
|
12887
|
+
field(mapping, "total_shards"),
|
|
12888
|
+
`${context} total_shards`
|
|
12889
|
+
);
|
|
12890
|
+
if (indexInteger2(completedShards) > indexInteger2(totalShards)) {
|
|
12891
|
+
throw decodeError(
|
|
12892
|
+
`${context} completed_shards exceeds total_shards`,
|
|
12893
|
+
mapping
|
|
12894
|
+
);
|
|
12895
|
+
}
|
|
12896
|
+
return Object.freeze({
|
|
12897
|
+
scope: requiredChoice(mapping, "scope", context, ["catalog_build"]),
|
|
12898
|
+
phaseCounts: decodePhaseCounts(field(mapping, "phase_counts"), section),
|
|
12899
|
+
currentPhases: decodeAllowedPhases(
|
|
12900
|
+
field(mapping, "current_phases"),
|
|
12901
|
+
section,
|
|
12902
|
+
allowedPhases
|
|
12903
|
+
),
|
|
12904
|
+
completedShards,
|
|
12905
|
+
totalShards,
|
|
12906
|
+
raw: freezeMap(mapping)
|
|
12907
|
+
});
|
|
12908
|
+
}
|
|
12909
|
+
function decodePhaseCounts(value, section) {
|
|
12910
|
+
const context = `FLOW.QUERY.INDEXES index ${section} phase_counts`;
|
|
12911
|
+
const mapping = requiredMap2(value, context);
|
|
12912
|
+
const entries = mapping instanceof Map ? [...mapping.entries()] : Object.entries(mapping);
|
|
12913
|
+
if (entries.length > 16) {
|
|
12914
|
+
throw decodeError(`${context} contains too many entries`, value);
|
|
12915
|
+
}
|
|
12916
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
12917
|
+
for (const [rawPhase, rawCount] of entries) {
|
|
12918
|
+
const phase = boundedText(rawPhase, `${context} phase`, 64);
|
|
12919
|
+
if (Object.hasOwn(result, phase)) {
|
|
12920
|
+
throw decodeError(`${context} contains duplicate phases`, value);
|
|
12921
|
+
}
|
|
12922
|
+
result[phase] = unsignedIndexInteger(rawCount, `${context} ${phase}`);
|
|
12923
|
+
}
|
|
12924
|
+
return Object.freeze(result);
|
|
12925
|
+
}
|
|
12926
|
+
function decodeAllowedPhases(value, section, allowed) {
|
|
12927
|
+
const phases = decodeUniqueTextArray(
|
|
12928
|
+
value,
|
|
12929
|
+
`FLOW.QUERY.INDEXES index ${section} current_phases`,
|
|
12930
|
+
allowed.length,
|
|
12931
|
+
64
|
|
12932
|
+
);
|
|
12933
|
+
if (phases.some((phase) => !allowed.includes(phase))) {
|
|
12934
|
+
throw decodeError(
|
|
12935
|
+
`FLOW.QUERY.INDEXES index ${section} current_phases are invalid`,
|
|
12936
|
+
value
|
|
12937
|
+
);
|
|
12938
|
+
}
|
|
12939
|
+
return phases;
|
|
12940
|
+
}
|
|
12941
|
+
|
|
12942
|
+
// src/flow-query-index-response.ts
|
|
12943
|
+
var FLOW_QUERY_INDEXES_CONTRACT = "ferric.flow.query.indexes/v1";
|
|
12944
|
+
function decodeFlowQueryIndexStatus(value, expectedId) {
|
|
12945
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES");
|
|
12946
|
+
requireContract(
|
|
12947
|
+
mapping,
|
|
12948
|
+
"contract_version",
|
|
12949
|
+
FLOW_QUERY_INDEXES_CONTRACT,
|
|
12950
|
+
"FLOW.QUERY.INDEXES"
|
|
12951
|
+
);
|
|
12952
|
+
const registry = requiredMap2(
|
|
12953
|
+
field(mapping, "registry"),
|
|
12954
|
+
"FLOW.QUERY.INDEXES registry"
|
|
12955
|
+
);
|
|
12956
|
+
const services = decodeIndexServices(field(mapping, "services"));
|
|
12302
12957
|
const rawIndexes = field(mapping, "indexes");
|
|
12303
12958
|
if (!Array.isArray(rawIndexes) || rawIndexes.length > 32) {
|
|
12304
|
-
throw decodeError(
|
|
12959
|
+
throw decodeError(
|
|
12960
|
+
"FLOW.QUERY.INDEXES indexes must contain at most 32 entries",
|
|
12961
|
+
value
|
|
12962
|
+
);
|
|
12305
12963
|
}
|
|
12306
12964
|
const indexes = new Array(rawIndexes.length);
|
|
12307
12965
|
for (let index = 0; index < rawIndexes.length; index += 1) {
|
|
12308
12966
|
if (!Object.hasOwn(rawIndexes, index)) {
|
|
12309
|
-
throw decodeError(
|
|
12967
|
+
throw decodeError(
|
|
12968
|
+
"FLOW.QUERY.INDEXES indexes must be a dense array",
|
|
12969
|
+
value
|
|
12970
|
+
);
|
|
12310
12971
|
}
|
|
12311
12972
|
indexes[index] = decodeIndex(rawIndexes[index], index);
|
|
12312
12973
|
}
|
|
12313
|
-
|
|
12974
|
+
const status = Object.freeze({
|
|
12314
12975
|
contractVersion: FLOW_QUERY_INDEXES_CONTRACT,
|
|
12315
|
-
observedAtMs:
|
|
12976
|
+
observedAtMs: unsignedIndexInteger(
|
|
12316
12977
|
field(mapping, "observed_at_ms"),
|
|
12317
12978
|
"FLOW.QUERY.INDEXES observed_at_ms"
|
|
12318
12979
|
),
|
|
12319
|
-
statisticsMaxAgeMs:
|
|
12980
|
+
statisticsMaxAgeMs: unsignedIndexInteger(
|
|
12320
12981
|
field(mapping, "statistics_max_age_ms"),
|
|
12321
12982
|
"FLOW.QUERY.INDEXES statistics_max_age_ms"
|
|
12322
12983
|
),
|
|
12323
12984
|
registry: Object.freeze({
|
|
12324
|
-
epoch:
|
|
12985
|
+
epoch: unsignedIndexInteger(
|
|
12325
12986
|
field(registry, "epoch"),
|
|
12326
|
-
MAX_UNSIGNED_64,
|
|
12327
12987
|
"FLOW.QUERY.INDEXES epoch"
|
|
12328
12988
|
),
|
|
12329
|
-
catalogVersion:
|
|
12989
|
+
catalogVersion: positiveIndexInteger(
|
|
12330
12990
|
field(registry, "catalog_version"),
|
|
12331
|
-
MAX_UNSIGNED_64,
|
|
12332
12991
|
"FLOW.QUERY.INDEXES catalog_version"
|
|
12333
12992
|
)
|
|
12334
12993
|
}),
|
|
@@ -12336,24 +12995,155 @@ function decodeFlowQueryIndexStatus(value) {
|
|
|
12336
12995
|
indexes: Object.freeze(indexes),
|
|
12337
12996
|
raw: freezeMap(mapping)
|
|
12338
12997
|
});
|
|
12998
|
+
validateFlowQueryIndexContract(status, expectedId);
|
|
12999
|
+
return status;
|
|
12339
13000
|
}
|
|
12340
13001
|
function decodeIndex(value, index) {
|
|
12341
13002
|
const mapping = requiredMap2(value, `FLOW.QUERY.INDEXES index ${index}`);
|
|
13003
|
+
const fields = decodeIndexFields(field(mapping, "fields"));
|
|
12342
13004
|
return Object.freeze({
|
|
12343
|
-
id:
|
|
12344
|
-
version:
|
|
13005
|
+
id: requiredBoundedText2(mapping, "id", "FLOW.QUERY.INDEXES index", 64),
|
|
13006
|
+
version: positiveIndexInteger(
|
|
12345
13007
|
field(mapping, "version"),
|
|
12346
|
-
MAX_UNSIGNED_64,
|
|
12347
13008
|
"FLOW.QUERY.INDEXES index version"
|
|
12348
13009
|
),
|
|
12349
|
-
buildId:
|
|
12350
|
-
|
|
12351
|
-
|
|
13010
|
+
buildId: requiredBoundedText2(
|
|
13011
|
+
mapping,
|
|
13012
|
+
"build_id",
|
|
13013
|
+
"FLOW.QUERY.INDEXES index",
|
|
13014
|
+
128
|
|
13015
|
+
),
|
|
13016
|
+
source: requiredChoice(mapping, "source", "FLOW.QUERY.INDEXES index", [
|
|
13017
|
+
"runs"
|
|
13018
|
+
]),
|
|
13019
|
+
state: requiredChoice(mapping, "state", "FLOW.QUERY.INDEXES index", [
|
|
13020
|
+
"building",
|
|
13021
|
+
"validating",
|
|
13022
|
+
"active",
|
|
13023
|
+
"retiring",
|
|
13024
|
+
"failed"
|
|
13025
|
+
]),
|
|
13026
|
+
queryable: requiredBoolean(
|
|
13027
|
+
mapping,
|
|
13028
|
+
"queryable",
|
|
13029
|
+
"FLOW.QUERY.INDEXES index"
|
|
13030
|
+
),
|
|
13031
|
+
fields,
|
|
13032
|
+
workloads: decodeUniqueTextArray(
|
|
13033
|
+
field(mapping, "workloads"),
|
|
13034
|
+
"FLOW.QUERY.INDEXES index workloads",
|
|
13035
|
+
16,
|
|
13036
|
+
64
|
|
13037
|
+
),
|
|
13038
|
+
countPrefixes: decodeCountPrefixes(
|
|
13039
|
+
field(mapping, "count_prefixes"),
|
|
13040
|
+
fields.length
|
|
13041
|
+
),
|
|
12352
13042
|
coveringFields: decodeCoveringFields(mapping),
|
|
12353
13043
|
format: decodeIndexFormat(mapping),
|
|
13044
|
+
coverage: decodeIndexCoverage(field(mapping, "coverage")),
|
|
13045
|
+
build: decodeIndexBuild(field(mapping, "build")),
|
|
13046
|
+
validation: decodeIndexValidation(field(mapping, "validation")),
|
|
13047
|
+
retirement: decodeIndexRetirement(field(mapping, "retirement")),
|
|
13048
|
+
statistics: decodeIndexStatistics(field(mapping, "statistics")),
|
|
12354
13049
|
raw: freezeMap(mapping)
|
|
12355
13050
|
});
|
|
12356
13051
|
}
|
|
13052
|
+
function decodeIndexServices(value) {
|
|
13053
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES services");
|
|
13054
|
+
const choices = ["ready", "unavailable"];
|
|
13055
|
+
return Object.freeze({
|
|
13056
|
+
registry: requiredChoice(
|
|
13057
|
+
mapping,
|
|
13058
|
+
"registry",
|
|
13059
|
+
"FLOW.QUERY.INDEXES services",
|
|
13060
|
+
choices
|
|
13061
|
+
),
|
|
13062
|
+
lifecycleWorker: requiredChoice(
|
|
13063
|
+
mapping,
|
|
13064
|
+
"lifecycle_worker",
|
|
13065
|
+
"FLOW.QUERY.INDEXES services",
|
|
13066
|
+
choices
|
|
13067
|
+
),
|
|
13068
|
+
statisticsStore: requiredChoice(
|
|
13069
|
+
mapping,
|
|
13070
|
+
"statistics_store",
|
|
13071
|
+
"FLOW.QUERY.INDEXES services",
|
|
13072
|
+
choices
|
|
13073
|
+
),
|
|
13074
|
+
statisticsWorker: requiredChoice(
|
|
13075
|
+
mapping,
|
|
13076
|
+
"statistics_worker",
|
|
13077
|
+
"FLOW.QUERY.INDEXES services",
|
|
13078
|
+
choices
|
|
13079
|
+
),
|
|
13080
|
+
raw: freezeMap(mapping)
|
|
13081
|
+
});
|
|
13082
|
+
}
|
|
13083
|
+
function decodeIndexFields(value) {
|
|
13084
|
+
const context = "FLOW.QUERY.INDEXES index fields";
|
|
13085
|
+
if (!Array.isArray(value) || value.length < 2 || value.length > 8) {
|
|
13086
|
+
throw decodeError(`${context} must contain 2 to 8 entries`, value);
|
|
13087
|
+
}
|
|
13088
|
+
const fields = new Array(value.length);
|
|
13089
|
+
const names = /* @__PURE__ */ new Set();
|
|
13090
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13091
|
+
if (!Object.hasOwn(value, index)) {
|
|
13092
|
+
throw decodeError(`${context} must be dense`, value);
|
|
13093
|
+
}
|
|
13094
|
+
const mapping = requiredMap2(
|
|
13095
|
+
value[index],
|
|
13096
|
+
`FLOW.QUERY.INDEXES index field ${index}`
|
|
13097
|
+
);
|
|
13098
|
+
const name = requiredBoundedText2(
|
|
13099
|
+
mapping,
|
|
13100
|
+
"name",
|
|
13101
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13102
|
+
512
|
|
13103
|
+
);
|
|
13104
|
+
if (names.has(name)) {
|
|
13105
|
+
throw decodeError(`${context} contain duplicates`, value);
|
|
13106
|
+
}
|
|
13107
|
+
names.add(name);
|
|
13108
|
+
fields[index] = Object.freeze({
|
|
13109
|
+
name,
|
|
13110
|
+
direction: requiredChoice(
|
|
13111
|
+
mapping,
|
|
13112
|
+
"direction",
|
|
13113
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13114
|
+
["asc", "desc"]
|
|
13115
|
+
),
|
|
13116
|
+
encoding: requiredChoice(
|
|
13117
|
+
mapping,
|
|
13118
|
+
"encoding",
|
|
13119
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13120
|
+
["hashed", "ordered"]
|
|
13121
|
+
),
|
|
13122
|
+
raw: freezeMap(mapping)
|
|
13123
|
+
});
|
|
13124
|
+
}
|
|
13125
|
+
return Object.freeze(fields);
|
|
13126
|
+
}
|
|
13127
|
+
function decodeCountPrefixes(value, fieldCount) {
|
|
13128
|
+
const context = "FLOW.QUERY.INDEXES index count_prefixes";
|
|
13129
|
+
if (!Array.isArray(value) || value.length > fieldCount) {
|
|
13130
|
+
throw decodeError(`${context} are invalid`, value);
|
|
13131
|
+
}
|
|
13132
|
+
const prefixes = new Array(value.length);
|
|
13133
|
+
let previous = 0;
|
|
13134
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13135
|
+
if (!Object.hasOwn(value, index)) {
|
|
13136
|
+
throw decodeError(`${context} must be dense`, value);
|
|
13137
|
+
}
|
|
13138
|
+
const prefix = positiveInteger(value[index], `${context} entry`);
|
|
13139
|
+
if (prefix > fieldCount || prefix <= previous) {
|
|
13140
|
+
throw decodeError(`${context} are invalid`, value);
|
|
13141
|
+
}
|
|
13142
|
+
prefixes[index] = prefix;
|
|
13143
|
+
previous = prefix;
|
|
13144
|
+
}
|
|
13145
|
+
return Object.freeze(prefixes);
|
|
13146
|
+
}
|
|
12357
13147
|
function decodeCoveringFields(mapping) {
|
|
12358
13148
|
const raw = field(mapping, "covering_fields");
|
|
12359
13149
|
if (!Array.isArray(raw) || raw.length > 32) {
|
|
@@ -12366,7 +13156,10 @@ function decodeCoveringFields(mapping) {
|
|
|
12366
13156
|
const seen = /* @__PURE__ */ new Set();
|
|
12367
13157
|
for (let index = 0; index < raw.length; index += 1) {
|
|
12368
13158
|
if (!Object.hasOwn(raw, index)) {
|
|
12369
|
-
throw decodeError(
|
|
13159
|
+
throw decodeError(
|
|
13160
|
+
"FLOW.QUERY.INDEXES index covering_fields must be dense",
|
|
13161
|
+
raw
|
|
13162
|
+
);
|
|
12370
13163
|
}
|
|
12371
13164
|
const value = boundedText(
|
|
12372
13165
|
raw[index],
|
|
@@ -12374,7 +13167,10 @@ function decodeCoveringFields(mapping) {
|
|
|
12374
13167
|
512
|
|
12375
13168
|
);
|
|
12376
13169
|
if (seen.has(value)) {
|
|
12377
|
-
throw decodeError(
|
|
13170
|
+
throw decodeError(
|
|
13171
|
+
"FLOW.QUERY.INDEXES index covering_fields contains duplicates",
|
|
13172
|
+
raw
|
|
13173
|
+
);
|
|
12378
13174
|
}
|
|
12379
13175
|
seen.add(value);
|
|
12380
13176
|
fields[index] = value;
|
|
@@ -12382,30 +13178,341 @@ function decodeCoveringFields(mapping) {
|
|
|
12382
13178
|
return Object.freeze(fields);
|
|
12383
13179
|
}
|
|
12384
13180
|
function decodeIndexFormat(mapping) {
|
|
12385
|
-
const raw = requiredMap2(
|
|
13181
|
+
const raw = requiredMap2(
|
|
13182
|
+
field(mapping, "format"),
|
|
13183
|
+
"FLOW.QUERY.INDEXES index format"
|
|
13184
|
+
);
|
|
12386
13185
|
if (!hasKey(raw, "counter")) {
|
|
12387
|
-
throw decodeError(
|
|
13186
|
+
throw decodeError(
|
|
13187
|
+
"FLOW.QUERY.INDEXES index format counter is missing",
|
|
13188
|
+
raw
|
|
13189
|
+
);
|
|
12388
13190
|
}
|
|
12389
13191
|
const counterValue = field(raw, "counter");
|
|
12390
|
-
const counter = counterValue === null ? void 0 : boundedText(
|
|
13192
|
+
const counter = counterValue === null ? void 0 : boundedText(
|
|
13193
|
+
counterValue,
|
|
13194
|
+
"FLOW.QUERY.INDEXES index format counter",
|
|
13195
|
+
128
|
|
13196
|
+
);
|
|
12391
13197
|
return Object.freeze({
|
|
12392
|
-
queryRow: requiredBoundedText2(
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
|
|
13198
|
+
queryRow: requiredBoundedText2(
|
|
13199
|
+
raw,
|
|
13200
|
+
"query_row",
|
|
13201
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13202
|
+
128
|
|
13203
|
+
),
|
|
13204
|
+
key: requiredBoundedText2(
|
|
13205
|
+
raw,
|
|
13206
|
+
"key",
|
|
13207
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13208
|
+
128
|
|
13209
|
+
),
|
|
13210
|
+
entry: requiredBoundedText2(
|
|
13211
|
+
raw,
|
|
13212
|
+
"entry",
|
|
13213
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13214
|
+
128
|
|
13215
|
+
),
|
|
13216
|
+
reverse: requiredBoundedText2(
|
|
13217
|
+
raw,
|
|
13218
|
+
"reverse",
|
|
13219
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13220
|
+
128
|
|
13221
|
+
),
|
|
12396
13222
|
counter,
|
|
12397
13223
|
raw: freezeMap(raw)
|
|
12398
13224
|
});
|
|
12399
13225
|
}
|
|
13226
|
+
|
|
13227
|
+
// src/flow-query-response.ts
|
|
13228
|
+
var FLOW_QUERY_RESULT_CONTRACT = "ferric.flow.query.result/v1";
|
|
13229
|
+
var FLOW_EXPLAIN_CONTRACT = "ferric.flow.explain/v1";
|
|
13230
|
+
var USAGE_FIELDS2 = [
|
|
13231
|
+
["range_seeks", "rangeSeeks"],
|
|
13232
|
+
["range_pages", "rangePages"],
|
|
13233
|
+
["scanned_entries", "scannedEntries"],
|
|
13234
|
+
["scanned_bytes", "scannedBytes"],
|
|
13235
|
+
["hydrated_records", "hydratedRecords"],
|
|
13236
|
+
["residual_checks", "residualChecks"],
|
|
13237
|
+
["duplicate_entries", "duplicateEntries"],
|
|
13238
|
+
["result_records", "resultRecords"],
|
|
13239
|
+
["response_bytes", "responseBytes"],
|
|
13240
|
+
["memory_high_water_bytes", "memoryHighWaterBytes"],
|
|
13241
|
+
["wall_time_us", "wallTimeUs"]
|
|
13242
|
+
];
|
|
13243
|
+
var MAX_SIGNED_643 = (1n << 63n) - 1n;
|
|
13244
|
+
var QUALITY_VALUES2 = {
|
|
13245
|
+
exactness: ["authoritative", "projected_exact", "exact", "not_applicable"],
|
|
13246
|
+
freshness: ["current", "projection_watermark", "not_applicable"],
|
|
13247
|
+
coverage: ["complete", "unavailable"],
|
|
13248
|
+
pagination: ["none", "complete", "authenticated_seek", "live_seek"]
|
|
13249
|
+
};
|
|
13250
|
+
function decodeFlowQueryResult(value) {
|
|
13251
|
+
const result = decodeFlowQueryResponse(value, (mapping) => freezeMap(mapping));
|
|
13252
|
+
if (result.kind === "records") {
|
|
13253
|
+
return Object.freeze({
|
|
13254
|
+
kind: "records",
|
|
13255
|
+
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
13256
|
+
records: Object.freeze(result.records),
|
|
13257
|
+
page: result.page,
|
|
13258
|
+
quality: result.quality,
|
|
13259
|
+
usage: result.usage,
|
|
13260
|
+
raw: result.raw
|
|
13261
|
+
});
|
|
13262
|
+
}
|
|
13263
|
+
return Object.freeze({
|
|
13264
|
+
kind: "count",
|
|
13265
|
+
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
13266
|
+
count: result.count,
|
|
13267
|
+
quality: result.quality,
|
|
13268
|
+
usage: result.usage,
|
|
13269
|
+
raw: result.raw
|
|
13270
|
+
});
|
|
13271
|
+
}
|
|
13272
|
+
function decodeFlowQueryRecords(value, decodeRecord) {
|
|
13273
|
+
const result = decodeFlowQueryResponse(
|
|
13274
|
+
value,
|
|
13275
|
+
(mapping, index) => decodeRecord(mapping instanceof Map ? freezeMap(mapping) : mapping, index)
|
|
13276
|
+
);
|
|
13277
|
+
if (result.kind === "count") {
|
|
13278
|
+
throw new FerricStoreError("Flow record convenience query returned a count result", {
|
|
13279
|
+
raw: result.raw
|
|
13280
|
+
});
|
|
13281
|
+
}
|
|
13282
|
+
return result.records;
|
|
13283
|
+
}
|
|
13284
|
+
function decodeFlowQueryResponse(value, decodeRecord) {
|
|
13285
|
+
const mapping = requiredMap2(value, "FLOW.QUERY result");
|
|
13286
|
+
requireContract(mapping, "version", FLOW_QUERY_RESULT_CONTRACT, "FLOW.QUERY result");
|
|
13287
|
+
const quality = decodeQuality(field(mapping, "quality"));
|
|
13288
|
+
const usage = decodeUsage(field(mapping, "usage"));
|
|
13289
|
+
const hasRecords = hasKey(mapping, "records");
|
|
13290
|
+
const hasCount = hasKey(mapping, "result");
|
|
13291
|
+
if (hasRecords === hasCount) {
|
|
13292
|
+
throw decodeError("FLOW.QUERY result must contain exactly one records or count shape", value);
|
|
13293
|
+
}
|
|
13294
|
+
const raw = freezeMap(mapping);
|
|
13295
|
+
if (hasRecords) {
|
|
13296
|
+
const rawRecords = field(mapping, "records");
|
|
13297
|
+
if (!Array.isArray(rawRecords) || rawRecords.length > 100) {
|
|
13298
|
+
throw decodeError("FLOW.QUERY records must be an array of at most 100 maps", value);
|
|
13299
|
+
}
|
|
13300
|
+
const records = new Array(rawRecords.length);
|
|
13301
|
+
for (let index = 0; index < rawRecords.length; index += 1) {
|
|
13302
|
+
if (!Object.hasOwn(rawRecords, index)) {
|
|
13303
|
+
throw decodeError("FLOW.QUERY records must be a dense array", value);
|
|
13304
|
+
}
|
|
13305
|
+
records[index] = decodeRecord(
|
|
13306
|
+
requiredMap2(rawRecords[index], `FLOW.QUERY record ${index}`),
|
|
13307
|
+
index
|
|
13308
|
+
);
|
|
13309
|
+
}
|
|
13310
|
+
if (usage.resultRecords !== records.length || usage.resultRecords > usage.scannedEntries) {
|
|
13311
|
+
throw decodeError("FLOW.QUERY usage result_records is inconsistent with records", value);
|
|
13312
|
+
}
|
|
13313
|
+
return {
|
|
13314
|
+
kind: "records",
|
|
13315
|
+
records,
|
|
13316
|
+
page: decodePage(field(mapping, "page")),
|
|
13317
|
+
quality,
|
|
13318
|
+
usage,
|
|
13319
|
+
raw
|
|
13320
|
+
};
|
|
13321
|
+
}
|
|
13322
|
+
if (hasKey(mapping, "page")) {
|
|
13323
|
+
throw decodeError("FLOW.QUERY count result contains an unexpected page", value);
|
|
13324
|
+
}
|
|
13325
|
+
const countResult = requiredMap2(field(mapping, "result"), "FLOW.QUERY count result");
|
|
13326
|
+
if (requiredText2(countResult, "kind", "FLOW.QUERY count result") !== "count") {
|
|
13327
|
+
throw decodeError("FLOW.QUERY count result kind must be count", value);
|
|
13328
|
+
}
|
|
13329
|
+
const count = boundedInteger(
|
|
13330
|
+
field(countResult, "value"),
|
|
13331
|
+
MAX_SIGNED_643,
|
|
13332
|
+
"FLOW.QUERY count value"
|
|
13333
|
+
);
|
|
13334
|
+
if (usage.resultRecords !== 1) {
|
|
13335
|
+
throw decodeError("FLOW.QUERY count usage result_records must be 1", value);
|
|
13336
|
+
}
|
|
13337
|
+
return {
|
|
13338
|
+
kind: "count",
|
|
13339
|
+
count,
|
|
13340
|
+
quality,
|
|
13341
|
+
usage,
|
|
13342
|
+
raw
|
|
13343
|
+
};
|
|
13344
|
+
}
|
|
13345
|
+
function decodeFlowExplainResult(value) {
|
|
13346
|
+
const mapping = requiredMap2(value, "FLOW.QUERY explain");
|
|
13347
|
+
requireContract(mapping, "version", FLOW_EXPLAIN_CONTRACT, "FLOW.QUERY explain");
|
|
13348
|
+
const queryFingerprint = requiredText2(mapping, "query_fingerprint", "FLOW.QUERY explain");
|
|
13349
|
+
if (!/^[0-9a-f]{64}$/iu.test(queryFingerprint)) {
|
|
13350
|
+
throw decodeError("FLOW.QUERY explain query_fingerprint is invalid", value);
|
|
13351
|
+
}
|
|
13352
|
+
const status = requiredText2(mapping, "status", "FLOW.QUERY explain");
|
|
13353
|
+
if (status !== "planned" && status !== "rejected" && status !== "executed") {
|
|
13354
|
+
throw decodeError(`FLOW.QUERY explain status ${JSON.stringify(status)} is unsupported`, value);
|
|
13355
|
+
}
|
|
13356
|
+
const plan = freezeMetadataMap(
|
|
13357
|
+
requiredMap2(field(mapping, "plan"), "FLOW.QUERY explain plan"),
|
|
13358
|
+
"FLOW.QUERY explain plan"
|
|
13359
|
+
);
|
|
13360
|
+
const estimate = freezeMetadataMap(
|
|
13361
|
+
requiredMap2(field(mapping, "estimate"), "FLOW.QUERY explain estimate"),
|
|
13362
|
+
"FLOW.QUERY explain estimate"
|
|
13363
|
+
);
|
|
13364
|
+
const bounds = freezeMetadataMap(
|
|
13365
|
+
requiredMap2(field(mapping, "bounds"), "FLOW.QUERY explain bounds"),
|
|
13366
|
+
"FLOW.QUERY explain bounds"
|
|
13367
|
+
);
|
|
13368
|
+
const capabilities = decodeExplainCapabilities(mapping);
|
|
13369
|
+
const extendedFields = ["stats", "quality", "pressure", "decision", "alternatives"];
|
|
13370
|
+
const extendedPresence = extendedFields.map((name) => hasKey(mapping, name));
|
|
13371
|
+
const specialized = capabilities != null && !extendedPresence.some(Boolean);
|
|
13372
|
+
let stats;
|
|
13373
|
+
let quality;
|
|
13374
|
+
let pressure;
|
|
13375
|
+
let decision;
|
|
13376
|
+
let alternatives;
|
|
13377
|
+
if (specialized) {
|
|
13378
|
+
if (status !== "planned") {
|
|
13379
|
+
throw decodeError("FLOW.QUERY specialized explain must be planned", value);
|
|
13380
|
+
}
|
|
13381
|
+
if (hasKey(mapping, "actual") || hasKey(mapping, "diagnostic")) {
|
|
13382
|
+
throw decodeError("FLOW.QUERY specialized explain has extended status fields", value);
|
|
13383
|
+
}
|
|
13384
|
+
alternatives = Object.freeze([]);
|
|
13385
|
+
} else {
|
|
13386
|
+
if (!extendedPresence.every(Boolean) || !hasKey(mapping, "actual") || !hasKey(mapping, "diagnostic")) {
|
|
13387
|
+
throw decodeError("FLOW.QUERY explain is missing required v1 fields", value);
|
|
13388
|
+
}
|
|
13389
|
+
stats = freezeMetadataMap(
|
|
13390
|
+
requiredMap2(field(mapping, "stats"), "FLOW.QUERY explain stats"),
|
|
13391
|
+
"FLOW.QUERY explain stats"
|
|
13392
|
+
);
|
|
13393
|
+
quality = decodeQuality(field(mapping, "quality"));
|
|
13394
|
+
pressure = freezeMetadataMap(
|
|
13395
|
+
requiredMap2(field(mapping, "pressure"), "FLOW.QUERY explain pressure"),
|
|
13396
|
+
"FLOW.QUERY explain pressure"
|
|
13397
|
+
);
|
|
13398
|
+
decision = freezeMetadataMap(
|
|
13399
|
+
requiredMap2(field(mapping, "decision"), "FLOW.QUERY explain decision"),
|
|
13400
|
+
"FLOW.QUERY explain decision"
|
|
13401
|
+
);
|
|
13402
|
+
alternatives = decodeExplainAlternatives(field(mapping, "alternatives"));
|
|
13403
|
+
}
|
|
13404
|
+
const actualValue = field(mapping, "actual");
|
|
13405
|
+
let actual;
|
|
13406
|
+
if (status === "executed") {
|
|
13407
|
+
if (actualValue == null) {
|
|
13408
|
+
throw decodeError("FLOW.QUERY executed explain is missing actual usage", value);
|
|
13409
|
+
}
|
|
13410
|
+
actual = decodeUsage(actualValue);
|
|
13411
|
+
} else if (actualValue != null) {
|
|
13412
|
+
throw decodeError("FLOW.QUERY non-executed explain contains actual usage", value);
|
|
13413
|
+
}
|
|
13414
|
+
const diagnosticValue = field(mapping, "diagnostic");
|
|
13415
|
+
let diagnostic;
|
|
13416
|
+
if (status === "rejected") {
|
|
13417
|
+
diagnostic = tryDecodeFlowQueryError(diagnosticValue);
|
|
13418
|
+
if (diagnostic == null) {
|
|
13419
|
+
throw decodeError("FLOW.QUERY rejected explain has an invalid diagnostic", value);
|
|
13420
|
+
}
|
|
13421
|
+
} else if (diagnosticValue != null) {
|
|
13422
|
+
throw decodeError("FLOW.QUERY non-rejected explain contains a diagnostic", value);
|
|
13423
|
+
}
|
|
13424
|
+
return Object.freeze({
|
|
13425
|
+
version: FLOW_EXPLAIN_CONTRACT,
|
|
13426
|
+
queryFingerprint,
|
|
13427
|
+
status,
|
|
13428
|
+
plan,
|
|
13429
|
+
estimate,
|
|
13430
|
+
stats,
|
|
13431
|
+
quality,
|
|
13432
|
+
bounds,
|
|
13433
|
+
pressure,
|
|
13434
|
+
decision,
|
|
13435
|
+
alternatives,
|
|
13436
|
+
capabilities,
|
|
13437
|
+
actual,
|
|
13438
|
+
diagnostic,
|
|
13439
|
+
raw: freezeMap(mapping)
|
|
13440
|
+
});
|
|
13441
|
+
}
|
|
13442
|
+
function decodeExplainCapabilities(mapping) {
|
|
13443
|
+
if (!hasKey(mapping, "capabilities")) return void 0;
|
|
13444
|
+
const value = requiredMap2(
|
|
13445
|
+
field(mapping, "capabilities"),
|
|
13446
|
+
"FLOW.QUERY explain capabilities"
|
|
13447
|
+
);
|
|
13448
|
+
return Object.freeze({
|
|
13449
|
+
requested: decodeExplainCapabilityList(field(value, "requested"), "requested"),
|
|
13450
|
+
available: decodeExplainCapabilityList(field(value, "available"), "available"),
|
|
13451
|
+
missing: decodeExplainCapabilityList(field(value, "missing"), "missing"),
|
|
13452
|
+
raw: freezeMetadataMap(value, "FLOW.QUERY explain capabilities")
|
|
13453
|
+
});
|
|
13454
|
+
}
|
|
13455
|
+
function decodeExplainCapabilityList(value, name) {
|
|
13456
|
+
if (!Array.isArray(value) || value.length > 64) {
|
|
13457
|
+
throw decodeError(
|
|
13458
|
+
`FLOW.QUERY explain capabilities ${name} must contain at most 64 entries`,
|
|
13459
|
+
value
|
|
13460
|
+
);
|
|
13461
|
+
}
|
|
13462
|
+
const result = new Array(value.length);
|
|
13463
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13464
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13465
|
+
if (!Object.hasOwn(value, index)) {
|
|
13466
|
+
throw decodeError(`FLOW.QUERY explain capabilities ${name} must be dense`, value);
|
|
13467
|
+
}
|
|
13468
|
+
const capability = boundedText(
|
|
13469
|
+
value[index],
|
|
13470
|
+
`FLOW.QUERY explain capabilities ${name} entry ${index}`,
|
|
13471
|
+
128
|
|
13472
|
+
);
|
|
13473
|
+
if (seen.has(capability)) {
|
|
13474
|
+
throw decodeError(
|
|
13475
|
+
`FLOW.QUERY explain capabilities ${name} contains duplicates`,
|
|
13476
|
+
value
|
|
13477
|
+
);
|
|
13478
|
+
}
|
|
13479
|
+
seen.add(capability);
|
|
13480
|
+
result[index] = capability;
|
|
13481
|
+
}
|
|
13482
|
+
return Object.freeze(result);
|
|
13483
|
+
}
|
|
13484
|
+
function decodeExplainAlternatives(value) {
|
|
13485
|
+
if (!Array.isArray(value) || value.length > 31) {
|
|
13486
|
+
throw decodeError("FLOW.QUERY explain alternatives must be an array of at most 31 maps", value);
|
|
13487
|
+
}
|
|
13488
|
+
const alternatives = new Array(value.length);
|
|
13489
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13490
|
+
if (!Object.hasOwn(value, index)) {
|
|
13491
|
+
throw decodeError("FLOW.QUERY explain alternatives must be dense", value);
|
|
13492
|
+
}
|
|
13493
|
+
alternatives[index] = freezeMetadataMap(
|
|
13494
|
+
requiredMap2(value[index], `FLOW.QUERY explain alternative ${index}`),
|
|
13495
|
+
`FLOW.QUERY explain alternative ${index}`
|
|
13496
|
+
);
|
|
13497
|
+
}
|
|
13498
|
+
return Object.freeze(alternatives);
|
|
13499
|
+
}
|
|
12400
13500
|
function decodeQuality(value) {
|
|
12401
13501
|
const mapping = requiredMap2(value, "FLOW.QUERY quality");
|
|
12402
13502
|
return Object.freeze({
|
|
12403
|
-
exactness:
|
|
12404
|
-
freshness:
|
|
12405
|
-
coverage:
|
|
12406
|
-
pagination:
|
|
13503
|
+
exactness: decodeQualityValue(mapping, "exactness", QUALITY_VALUES2.exactness),
|
|
13504
|
+
freshness: decodeQualityValue(mapping, "freshness", QUALITY_VALUES2.freshness),
|
|
13505
|
+
coverage: decodeQualityValue(mapping, "coverage", QUALITY_VALUES2.coverage),
|
|
13506
|
+
pagination: decodeQualityValue(mapping, "pagination", QUALITY_VALUES2.pagination)
|
|
12407
13507
|
});
|
|
12408
13508
|
}
|
|
13509
|
+
function decodeQualityValue(mapping, name, allowed) {
|
|
13510
|
+
const value = requiredBoundedText2(mapping, name, "FLOW.QUERY quality", 64);
|
|
13511
|
+
if (!allowed.includes(value)) {
|
|
13512
|
+
throw decodeError(`FLOW.QUERY quality ${name} is unsupported`, mapping);
|
|
13513
|
+
}
|
|
13514
|
+
return value;
|
|
13515
|
+
}
|
|
12409
13516
|
function decodeUsage(value) {
|
|
12410
13517
|
const mapping = requiredMap2(value, "FLOW.QUERY usage");
|
|
12411
13518
|
const usage = /* @__PURE__ */ Object.create(null);
|
|
@@ -12415,13 +13522,17 @@ function decodeUsage(value) {
|
|
|
12415
13522
|
`FLOW.QUERY usage ${wireName}`
|
|
12416
13523
|
);
|
|
12417
13524
|
}
|
|
12418
|
-
|
|
13525
|
+
const decoded = usage;
|
|
13526
|
+
if (decoded.hydratedRecords > decoded.scannedEntries || decoded.duplicateEntries > decoded.scannedEntries || decoded.rangePages > decoded.scannedEntries + decoded.rangeSeeks || decoded.residualChecks > decoded.scannedEntries * 12) {
|
|
13527
|
+
throw decodeError("FLOW.QUERY usage counters are inconsistent", value);
|
|
13528
|
+
}
|
|
13529
|
+
return Object.freeze(decoded);
|
|
12419
13530
|
}
|
|
12420
13531
|
function decodePage(value) {
|
|
12421
13532
|
const mapping = requiredMap2(value, "FLOW.QUERY page");
|
|
12422
13533
|
const hasMore = requiredBoolean(mapping, "has_more", "FLOW.QUERY page");
|
|
12423
13534
|
const cursor = optionalText2(mapping, "cursor", "FLOW.QUERY page");
|
|
12424
|
-
if (cursor != null && (!cursor.startsWith("fqc1_") ||
|
|
13535
|
+
if (cursor != null && (!cursor.startsWith("fqc1_") || import_node_buffer48.Buffer.byteLength(cursor) < 16 || import_node_buffer48.Buffer.byteLength(cursor) > 4096)) {
|
|
12425
13536
|
throw decodeError("FLOW.QUERY page cursor is invalid", value);
|
|
12426
13537
|
}
|
|
12427
13538
|
if (hasMore !== (cursor != null)) {
|
|
@@ -12429,26 +13540,14 @@ function decodePage(value) {
|
|
|
12429
13540
|
}
|
|
12430
13541
|
return Object.freeze({ hasMore, ...cursor == null ? {} : { cursor } });
|
|
12431
13542
|
}
|
|
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
13543
|
|
|
12445
13544
|
// src/client-core.ts
|
|
12446
|
-
var
|
|
13545
|
+
var import_node_buffer53 = require("buffer");
|
|
12447
13546
|
|
|
12448
13547
|
// src/client-core-helpers.ts
|
|
12449
|
-
var
|
|
13548
|
+
var import_node_buffer49 = require("buffer");
|
|
12450
13549
|
function bgsaveResponse(response) {
|
|
12451
|
-
if ((typeof response === "string" ||
|
|
13550
|
+
if ((typeof response === "string" || import_node_buffer49.Buffer.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
|
|
12452
13551
|
return true;
|
|
12453
13552
|
}
|
|
12454
13553
|
return okResponse(response);
|
|
@@ -12462,7 +13561,7 @@ function fetchOrComputeCompletionToken(options) {
|
|
|
12462
13561
|
"fetch-or-compute completion requires computeToken"
|
|
12463
13562
|
);
|
|
12464
13563
|
}
|
|
12465
|
-
if (!
|
|
13564
|
+
if (!import_node_buffer49.Buffer.isBuffer(options.computeToken)) {
|
|
12466
13565
|
throw new TypeError("fetch-or-compute computeToken must be a Buffer");
|
|
12467
13566
|
}
|
|
12468
13567
|
return options.computeToken;
|
|
@@ -12485,10 +13584,10 @@ function unsupportedClientCaching() {
|
|
|
12485
13584
|
}
|
|
12486
13585
|
|
|
12487
13586
|
// src/client-base.ts
|
|
12488
|
-
var
|
|
13587
|
+
var import_node_buffer51 = require("buffer");
|
|
12489
13588
|
|
|
12490
13589
|
// src/client-executor.ts
|
|
12491
|
-
var
|
|
13590
|
+
var import_node_buffer50 = require("buffer");
|
|
12492
13591
|
var ErrorMappingExecutor = class {
|
|
12493
13592
|
constructor(executor) {
|
|
12494
13593
|
this.executor = executor;
|
|
@@ -12822,14 +13921,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
|
|
|
12822
13921
|
};
|
|
12823
13922
|
|
|
12824
13923
|
// src/store-utilities.ts
|
|
12825
|
-
var
|
|
13924
|
+
var import_node_buffer52 = require("buffer");
|
|
12826
13925
|
function encode(codec, value) {
|
|
12827
13926
|
return codec.encode(value);
|
|
12828
13927
|
}
|
|
12829
13928
|
function decode(codec, value) {
|
|
12830
13929
|
if (value == null) return null;
|
|
12831
|
-
if (
|
|
12832
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
13930
|
+
if (import_node_buffer52.Buffer.isBuffer(value)) return codec.decode(value);
|
|
13931
|
+
if (value instanceof Uint8Array) return codec.decode(import_node_buffer52.Buffer.from(value));
|
|
12833
13932
|
return value;
|
|
12834
13933
|
}
|
|
12835
13934
|
function number(value) {
|
|
@@ -15064,7 +16163,7 @@ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
|
|
|
15064
16163
|
args.push(indexId);
|
|
15065
16164
|
}
|
|
15066
16165
|
try {
|
|
15067
|
-
return decodeFlowQueryIndexStatus(await this.commandArgs(args));
|
|
16166
|
+
return decodeFlowQueryIndexStatus(await this.commandArgs(args), indexId);
|
|
15068
16167
|
} catch (error) {
|
|
15069
16168
|
this.throwFlowQueryError(error);
|
|
15070
16169
|
}
|
|
@@ -15126,7 +16225,7 @@ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
|
|
|
15126
16225
|
if (hasFlowExplainPrefix(query)) {
|
|
15127
16226
|
throw new TypeError("query already contains an EXPLAIN prefix");
|
|
15128
16227
|
}
|
|
15129
|
-
return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query
|
|
16228
|
+
return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query, params));
|
|
15130
16229
|
}
|
|
15131
16230
|
throwFlowQueryError(error) {
|
|
15132
16231
|
if (error instanceof FerricStoreError) {
|
|
@@ -15159,7 +16258,7 @@ function throwIfClosed(signal) {
|
|
|
15159
16258
|
}
|
|
15160
16259
|
|
|
15161
16260
|
// src/flow-policy.ts
|
|
15162
|
-
var
|
|
16261
|
+
var import_node_buffer54 = require("buffer");
|
|
15163
16262
|
var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
|
|
15164
16263
|
function assertFlowPolicyGeneration(value) {
|
|
15165
16264
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
@@ -15249,7 +16348,7 @@ function requiredRecord(value, context) {
|
|
|
15249
16348
|
}
|
|
15250
16349
|
return result;
|
|
15251
16350
|
}
|
|
15252
|
-
if (typeof value === "object" && value != null && !Array.isArray(value) && !
|
|
16351
|
+
if (typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer54.Buffer.isBuffer(value) && !(value instanceof Uint8Array)) return value;
|
|
15253
16352
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
15254
16353
|
}
|
|
15255
16354
|
function optionalRecord(value, context) {
|
|
@@ -15270,8 +16369,8 @@ function stringArray(value, context) {
|
|
|
15270
16369
|
}
|
|
15271
16370
|
function requiredText3(value, context) {
|
|
15272
16371
|
if (typeof value === "string") return value;
|
|
15273
|
-
if (
|
|
15274
|
-
return
|
|
16372
|
+
if (import_node_buffer54.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
16373
|
+
return import_node_buffer54.Buffer.from(value).toString("utf8");
|
|
15275
16374
|
}
|
|
15276
16375
|
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
15277
16376
|
}
|
|
@@ -15527,7 +16626,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreFlowQueryClient {
|
|
|
15527
16626
|
};
|
|
15528
16627
|
|
|
15529
16628
|
// src/flow-many-snapshot.ts
|
|
15530
|
-
var
|
|
16629
|
+
var import_node_buffer56 = require("buffer");
|
|
15531
16630
|
var encodedOptionFields = ["error", "payload", "reason", "result"];
|
|
15532
16631
|
function snapshotCreateItem(item, codec) {
|
|
15533
16632
|
const snapshot = {
|
|
@@ -15567,7 +16666,7 @@ function snapshotFlowManyOptions(options, codec) {
|
|
|
15567
16666
|
}
|
|
15568
16667
|
function snapshotClaimedItem(item) {
|
|
15569
16668
|
const wire = item[CLAIMED_ITEM_WIRE];
|
|
15570
|
-
const leaseToken =
|
|
16669
|
+
const leaseToken = import_node_buffer56.Buffer.from(wire?.leaseToken ?? item.leaseToken);
|
|
15571
16670
|
const snapshot = {
|
|
15572
16671
|
...item,
|
|
15573
16672
|
fencingToken: wire?.fencingToken ?? item.fencingToken,
|
|
@@ -15584,15 +16683,15 @@ function snapshotClaimedItem(item) {
|
|
|
15584
16683
|
function snapshotFencedItem(item) {
|
|
15585
16684
|
return Object.freeze({
|
|
15586
16685
|
...item,
|
|
15587
|
-
...item.leaseToken == null ? {} : { leaseToken:
|
|
16686
|
+
...item.leaseToken == null ? {} : { leaseToken: import_node_buffer56.Buffer.from(item.leaseToken) }
|
|
15588
16687
|
});
|
|
15589
16688
|
}
|
|
15590
16689
|
function snapshotClaimedItemWire(wire, leaseToken) {
|
|
15591
16690
|
return Object.freeze({
|
|
15592
16691
|
fencingToken: wire.fencingToken,
|
|
15593
|
-
id:
|
|
16692
|
+
id: import_node_buffer56.Buffer.from(wire.id),
|
|
15594
16693
|
leaseToken,
|
|
15595
|
-
partitionKey: wire.partitionKey == null ? wire.partitionKey :
|
|
16694
|
+
partitionKey: wire.partitionKey == null ? wire.partitionKey : import_node_buffer56.Buffer.from(wire.partitionKey)
|
|
15596
16695
|
});
|
|
15597
16696
|
}
|
|
15598
16697
|
function snapshotArray(values) {
|
|
@@ -15603,7 +16702,7 @@ function snapshotArray(values) {
|
|
|
15603
16702
|
return Object.freeze(snapshot);
|
|
15604
16703
|
}
|
|
15605
16704
|
function snapshotStateMeta(stateMeta) {
|
|
15606
|
-
return snapshotRecord(stateMeta, (value) =>
|
|
16705
|
+
return snapshotRecord(stateMeta, (value) => import_node_buffer56.Buffer.isBuffer(value) ? import_node_buffer56.Buffer.from(value) : value);
|
|
15607
16706
|
}
|
|
15608
16707
|
function snapshotCommandRecord(values) {
|
|
15609
16708
|
const seen = /* @__PURE__ */ new WeakMap();
|
|
@@ -15621,7 +16720,7 @@ function snapshotRecord(values, capture) {
|
|
|
15621
16720
|
}
|
|
15622
16721
|
function snapshotCommandArgument(value, seen) {
|
|
15623
16722
|
if (typeof value !== "object" || value == null) return value;
|
|
15624
|
-
if (
|
|
16723
|
+
if (import_node_buffer56.Buffer.isBuffer(value) || value instanceof Uint8Array) return import_node_buffer56.Buffer.from(value);
|
|
15625
16724
|
const objectValue = value;
|
|
15626
16725
|
const existing = seen.get(objectValue);
|
|
15627
16726
|
if (existing != null) return existing;
|
|
@@ -16609,7 +17708,7 @@ function nativeOptionsForBootstrap(options, signal) {
|
|
|
16609
17708
|
}
|
|
16610
17709
|
|
|
16611
17710
|
// src/flow-query-projection.ts
|
|
16612
|
-
var
|
|
17711
|
+
var import_node_buffer57 = require("buffer");
|
|
16613
17712
|
var MAX_PROJECTION_FIELDS = 32;
|
|
16614
17713
|
var MAX_DYNAMIC_NAME_BYTES = 64;
|
|
16615
17714
|
var FIELD_BRAND = /* @__PURE__ */ Symbol("FerricStoreFlowProjectionField");
|
|
@@ -16677,20 +17776,38 @@ function projectFlowQuery(query, shape, ...fields) {
|
|
|
16677
17776
|
if (containsReturnKeyword(query)) {
|
|
16678
17777
|
throw new TypeError("Flow query already contains a RETURN clause");
|
|
16679
17778
|
}
|
|
16680
|
-
const
|
|
16681
|
-
const base = trimmed.endsWith(";") ? trimmed.slice(0, -1).trimEnd() : trimmed;
|
|
17779
|
+
const base = stripOptionalTerminator(query);
|
|
16682
17780
|
const result = `${base} RETURN ${shape.toUpperCase()} (${selectors.join(", ")})`;
|
|
16683
|
-
if (
|
|
17781
|
+
if (import_node_buffer57.Buffer.byteLength(result, "utf8") > FLOW_QUERY_MAX_BYTES) {
|
|
16684
17782
|
throw new TypeError(`FLOW.QUERY query exceeds ${FLOW_QUERY_MAX_BYTES} bytes`);
|
|
16685
17783
|
}
|
|
16686
17784
|
return result;
|
|
16687
17785
|
}
|
|
17786
|
+
function stripOptionalTerminator(query) {
|
|
17787
|
+
const trimmed = trimFlowQueryAsciiWhitespace(query);
|
|
17788
|
+
if (!trimmed.endsWith(";")) return trimmed;
|
|
17789
|
+
const base = trimFlowQueryAsciiWhitespace(trimmed.slice(0, -1));
|
|
17790
|
+
if (base.endsWith(";")) {
|
|
17791
|
+
throw new TypeError("Flow query accepts at most one trailing semicolon");
|
|
17792
|
+
}
|
|
17793
|
+
return base;
|
|
17794
|
+
}
|
|
16688
17795
|
function querySource(query) {
|
|
16689
|
-
const
|
|
16690
|
-
if (
|
|
17796
|
+
const source = trimFlowQueryAsciiWhitespaceStart(query);
|
|
17797
|
+
if (!matchesFlowQueryAsciiKeyword(source, 0, "FROM") || !isFlowQueryAsciiWhitespaceCode(source.charCodeAt(4))) {
|
|
16691
17798
|
throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
|
|
16692
17799
|
}
|
|
16693
|
-
|
|
17800
|
+
let offset = 4;
|
|
17801
|
+
while (isFlowQueryAsciiWhitespaceCode(source.charCodeAt(offset))) offset += 1;
|
|
17802
|
+
for (const candidate of ["runs", "events"]) {
|
|
17803
|
+
if (matchesFlowQueryAsciiKeyword(source, offset, candidate.toUpperCase())) {
|
|
17804
|
+
const boundary = source[offset + candidate.length];
|
|
17805
|
+
if (boundary == null || isFlowQueryAsciiWhitespaceCode(boundary.charCodeAt(0))) {
|
|
17806
|
+
return candidate;
|
|
17807
|
+
}
|
|
17808
|
+
}
|
|
17809
|
+
}
|
|
17810
|
+
throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
|
|
16694
17811
|
}
|
|
16695
17812
|
function containsReturnKeyword(query) {
|
|
16696
17813
|
let quoted = false;
|
|
@@ -16721,7 +17838,7 @@ function quoteName(value, allowPrivate) {
|
|
|
16721
17838
|
throw new TypeError("Flow query projection metadata name must be text");
|
|
16722
17839
|
}
|
|
16723
17840
|
validateUnicodeScalarText2(value);
|
|
16724
|
-
const size =
|
|
17841
|
+
const size = import_node_buffer57.Buffer.byteLength(value, "utf8");
|
|
16725
17842
|
if (size === 0 || size > MAX_DYNAMIC_NAME_BYTES || !allowPrivate && value.startsWith("__")) {
|
|
16726
17843
|
throw new TypeError(
|
|
16727
17844
|
`Flow query projection metadata names must be 1..${MAX_DYNAMIC_NAME_BYTES} UTF-8 bytes`
|
|
@@ -16755,7 +17872,7 @@ function complete(options = {}) {
|
|
|
16755
17872
|
function retry(options = {}) {
|
|
16756
17873
|
return brandOutcome({ ...options, kind: "retry" });
|
|
16757
17874
|
}
|
|
16758
|
-
function
|
|
17875
|
+
function fail2(options = {}) {
|
|
16759
17876
|
return brandOutcome({ ...options, kind: "fail" });
|
|
16760
17877
|
}
|
|
16761
17878
|
function isOutcome(value) {
|
|
@@ -17552,7 +18669,7 @@ async function applyQueueException(queue, options, job, error) {
|
|
|
17552
18669
|
const policy = normalizeExceptionPolicy(options.exceptionPolicy);
|
|
17553
18670
|
if (policy === "raise") throw error;
|
|
17554
18671
|
const payload = workerErrorPayload(error, options, queue.client.codec);
|
|
17555
|
-
await applyQueueOutcome(queue, job, policy === "fail" ?
|
|
18672
|
+
await applyQueueOutcome(queue, job, policy === "fail" ? fail2({ error: payload }) : retry({ error: payload }));
|
|
17556
18673
|
}
|
|
17557
18674
|
|
|
17558
18675
|
// src/queue-pending-completions.ts
|
|
@@ -17799,7 +18916,7 @@ var QueueWorker = class {
|
|
|
17799
18916
|
const policy = normalizeExceptionPolicy(this.options.exceptionPolicy);
|
|
17800
18917
|
if (policy !== "raise") {
|
|
17801
18918
|
const payload = workerErrorPayload(error, this.options, this.queue.client.codec);
|
|
17802
|
-
outcome = policy === "fail" ?
|
|
18919
|
+
outcome = policy === "fail" ? fail2({ error: payload }) : retry({ error: payload });
|
|
17803
18920
|
}
|
|
17804
18921
|
}
|
|
17805
18922
|
const stopped = await stopQueueBatchGuards(guards.map((guard) => guard.job), guards);
|
|
@@ -18712,7 +19829,7 @@ var WorkflowWorker = class {
|
|
|
18712
19829
|
await applyWorkflowOutcome(
|
|
18713
19830
|
this.workflow.client,
|
|
18714
19831
|
ctx,
|
|
18715
|
-
|
|
19832
|
+
fail2({ error: workerErrorPayload(error, this.options, this.workflow.client.codec) }),
|
|
18716
19833
|
registration.returnRecord
|
|
18717
19834
|
);
|
|
18718
19835
|
return;
|
|
@@ -18727,7 +19844,7 @@ var WorkflowWorker = class {
|
|
|
18727
19844
|
};
|
|
18728
19845
|
|
|
18729
19846
|
// src/version.ts
|
|
18730
|
-
var FERRICSTORE_SDK_VERSION = "0.5.
|
|
19847
|
+
var FERRICSTORE_SDK_VERSION = "0.5.2";
|
|
18731
19848
|
var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.0";
|
|
18732
19849
|
var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
|
|
18733
19850
|
// Annotate the CommonJS export names for ESM import in node:
|