@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.js
CHANGED
|
@@ -1140,10 +1140,10 @@ var NativeFlowControl = class {
|
|
|
1140
1140
|
|
|
1141
1141
|
// src/native-heartbeat.ts
|
|
1142
1142
|
var NativeHeartbeat = class {
|
|
1143
|
-
constructor(intervalMs, send,
|
|
1143
|
+
constructor(intervalMs, send, fail3) {
|
|
1144
1144
|
this.intervalMs = intervalMs;
|
|
1145
1145
|
this.send = send;
|
|
1146
|
-
this.fail =
|
|
1146
|
+
this.fail = fail3;
|
|
1147
1147
|
}
|
|
1148
1148
|
intervalMs;
|
|
1149
1149
|
send;
|
|
@@ -1190,9 +1190,11 @@ var FLOW_QUERY_LANGUAGE_VERSION = "FQL1";
|
|
|
1190
1190
|
var FLOW_QUERY_MAX_BYTES = 16 * 1024;
|
|
1191
1191
|
var FLOW_QUERY_MAX_PARAMETERS = 64;
|
|
1192
1192
|
var FLOW_QUERY_MAX_PARAMETER_NAME_BYTES = 128;
|
|
1193
|
+
var FLOW_QUERY_MAX_PARAMETER_VALUE_BYTES = 65535;
|
|
1193
1194
|
var MIN_I64 = -(1n << 63n);
|
|
1194
1195
|
var MAX_I64 = (1n << 63n) - 1n;
|
|
1195
1196
|
var INDEX_ID = /^[A-Za-z0-9_.:-]{1,64}$/u;
|
|
1197
|
+
var PARAMETER_NAME = /^[A-Za-z0-9_.-]+$/u;
|
|
1196
1198
|
function flowQueryArgs(query, params = {}) {
|
|
1197
1199
|
validateFlowQueryText(query);
|
|
1198
1200
|
const entries = flowQueryParameterEntries(params);
|
|
@@ -1246,9 +1248,34 @@ function validateFlowQueryIndexId(indexId) {
|
|
|
1246
1248
|
}
|
|
1247
1249
|
}
|
|
1248
1250
|
function hasFlowExplainPrefix(query) {
|
|
1249
|
-
const source = query
|
|
1250
|
-
|
|
1251
|
-
|
|
1251
|
+
const source = trimFlowQueryAsciiWhitespaceStart(query);
|
|
1252
|
+
return matchesFlowQueryAsciiKeyword(source, 0, "EXPLAIN") && (source.length === 7 || isFlowQueryAsciiWhitespaceCode(source.charCodeAt(7)));
|
|
1253
|
+
}
|
|
1254
|
+
function matchesFlowQueryAsciiKeyword(value, offset, keyword) {
|
|
1255
|
+
if (offset < 0 || offset + keyword.length > value.length) return false;
|
|
1256
|
+
for (let index = 0; index < keyword.length; index += 1) {
|
|
1257
|
+
let actual = value.charCodeAt(offset + index);
|
|
1258
|
+
if (actual >= 97 && actual <= 122) actual -= 32;
|
|
1259
|
+
if (actual !== keyword.charCodeAt(index)) return false;
|
|
1260
|
+
}
|
|
1261
|
+
return true;
|
|
1262
|
+
}
|
|
1263
|
+
function trimFlowQueryAsciiWhitespaceStart(value) {
|
|
1264
|
+
let start = 0;
|
|
1265
|
+
while (start < value.length && isFlowQueryAsciiWhitespaceCode(value.charCodeAt(start))) {
|
|
1266
|
+
start += 1;
|
|
1267
|
+
}
|
|
1268
|
+
return start === 0 ? value : value.slice(start);
|
|
1269
|
+
}
|
|
1270
|
+
function trimFlowQueryAsciiWhitespace(value) {
|
|
1271
|
+
let start = 0;
|
|
1272
|
+
let end = value.length;
|
|
1273
|
+
while (start < end && isFlowQueryAsciiWhitespaceCode(value.charCodeAt(start))) start += 1;
|
|
1274
|
+
while (end > start && isFlowQueryAsciiWhitespaceCode(value.charCodeAt(end - 1))) end -= 1;
|
|
1275
|
+
return start === 0 && end === value.length ? value : value.slice(start, end);
|
|
1276
|
+
}
|
|
1277
|
+
function isFlowQueryAsciiWhitespaceCode(code) {
|
|
1278
|
+
return code === 32 || code === 9 || code === 10 || code === 13;
|
|
1252
1279
|
}
|
|
1253
1280
|
function flowQueryParameterEntries(params) {
|
|
1254
1281
|
if (typeof params !== "object" || params == null || Array.isArray(params)) {
|
|
@@ -1274,19 +1301,26 @@ function flowQueryParameterEntries(params) {
|
|
|
1274
1301
|
function validateFlowQueryParameterName(name) {
|
|
1275
1302
|
validateUnicodeScalarText(name, "FLOW.QUERY parameter name");
|
|
1276
1303
|
const size = Buffer4.byteLength(name, "utf8");
|
|
1277
|
-
if (size === 0 || size > FLOW_QUERY_MAX_PARAMETER_NAME_BYTES) {
|
|
1304
|
+
if (size === 0 || size > FLOW_QUERY_MAX_PARAMETER_NAME_BYTES || !PARAMETER_NAME.test(name)) {
|
|
1278
1305
|
throw new TypeError(
|
|
1279
|
-
`FLOW.QUERY parameter names must be 1..${FLOW_QUERY_MAX_PARAMETER_NAME_BYTES}
|
|
1306
|
+
`FLOW.QUERY parameter names must be 1..${FLOW_QUERY_MAX_PARAMETER_NAME_BYTES} ASCII letters, digits, '_', '.', or '-'`
|
|
1280
1307
|
);
|
|
1281
1308
|
}
|
|
1282
1309
|
}
|
|
1283
1310
|
function normalizeFlowQueryParameter(value, name) {
|
|
1284
1311
|
if (typeof value === "string") {
|
|
1285
1312
|
validateUnicodeScalarText(value, `FLOW.QUERY parameter ${JSON.stringify(name)}`);
|
|
1313
|
+
validateParameterValueSize(Buffer4.byteLength(value, "utf8"), name);
|
|
1314
|
+
return value;
|
|
1315
|
+
}
|
|
1316
|
+
if (Buffer4.isBuffer(value)) {
|
|
1317
|
+
validateParameterValueSize(value.byteLength, name);
|
|
1286
1318
|
return value;
|
|
1287
1319
|
}
|
|
1288
|
-
if (
|
|
1289
|
-
|
|
1320
|
+
if (value instanceof Uint8Array) {
|
|
1321
|
+
validateParameterValueSize(value.byteLength, name);
|
|
1322
|
+
return Buffer4.from(value);
|
|
1323
|
+
}
|
|
1290
1324
|
if (typeof value === "boolean") return value;
|
|
1291
1325
|
if (typeof value === "bigint" && value >= MIN_I64 && value <= MAX_I64) return value;
|
|
1292
1326
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -1296,6 +1330,13 @@ function normalizeFlowQueryParameter(value, name) {
|
|
|
1296
1330
|
`FLOW.QUERY parameter ${JSON.stringify(name)} must be text, bytes, boolean, a finite float, or a signed 64-bit integer`
|
|
1297
1331
|
);
|
|
1298
1332
|
}
|
|
1333
|
+
function validateParameterValueSize(size, name) {
|
|
1334
|
+
if (size > FLOW_QUERY_MAX_PARAMETER_VALUE_BYTES) {
|
|
1335
|
+
throw new TypeError(
|
|
1336
|
+
`FLOW.QUERY parameter ${JSON.stringify(name)} exceeds ${FLOW_QUERY_MAX_PARAMETER_VALUE_BYTES} bytes`
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1299
1340
|
function commandText(value, context) {
|
|
1300
1341
|
if (typeof value === "string") {
|
|
1301
1342
|
validateUnicodeScalarText(value, context);
|
|
@@ -5730,7 +5771,7 @@ function truncate(value) {
|
|
|
5730
5771
|
}
|
|
5731
5772
|
|
|
5732
5773
|
// src/protocol-flow-query-result.ts
|
|
5733
|
-
import { Buffer as Buffer24 } from "buffer";
|
|
5774
|
+
import { Buffer as Buffer24, isUtf8 as isUtf82 } from "buffer";
|
|
5734
5775
|
|
|
5735
5776
|
// src/protocol-binary-detacher.ts
|
|
5736
5777
|
import { Buffer as Buffer23 } from "buffer";
|
|
@@ -5767,7 +5808,10 @@ function isDecodedRecord(value) {
|
|
|
5767
5808
|
// src/protocol-flow-query-result.ts
|
|
5768
5809
|
var CONTRACT = "ferric.flow.query.result/v1";
|
|
5769
5810
|
var MAX_RECORDS = 100;
|
|
5811
|
+
var MIN_CURSOR_BYTES = 16;
|
|
5770
5812
|
var MAX_CURSOR_BYTES = 4096;
|
|
5813
|
+
var CURSOR_PREFIX = Buffer24.from("fqc1_");
|
|
5814
|
+
var MAX_SIGNED_64 = (1n << 63n) - 1n;
|
|
5771
5815
|
var RECORD_FIELDS = [
|
|
5772
5816
|
"id",
|
|
5773
5817
|
"type",
|
|
@@ -5831,9 +5875,13 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5831
5875
|
const usage = {};
|
|
5832
5876
|
for (const field3 of USAGE_FIELDS) {
|
|
5833
5877
|
const read = readU64(data, offset);
|
|
5878
|
+
if (BigInt(read.value) > MAX_SIGNED_64) {
|
|
5879
|
+
throw new FerricStoreError("compact FLOW.QUERY usage exceeds signed 64-bit range");
|
|
5880
|
+
}
|
|
5834
5881
|
usage[field3] = read.value;
|
|
5835
5882
|
offset = read.offset;
|
|
5836
5883
|
}
|
|
5884
|
+
validateCompactUsage(usage);
|
|
5837
5885
|
let result;
|
|
5838
5886
|
if (kind === 0) {
|
|
5839
5887
|
const page = readPage(data, offset);
|
|
@@ -5842,6 +5890,7 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5842
5890
|
const count = data.readUInt32BE(offset);
|
|
5843
5891
|
offset += 4;
|
|
5844
5892
|
if (count > MAX_RECORDS) throw new FerricStoreError("compact FLOW.QUERY page exceeds 100 records");
|
|
5893
|
+
validateCompactRecordUsage(usage, count);
|
|
5845
5894
|
consumeDecodeItems(count, budget);
|
|
5846
5895
|
const records = new Array(count);
|
|
5847
5896
|
for (let index = 0; index < count; index += 1) {
|
|
@@ -5851,7 +5900,13 @@ function decodeCompactFlowQueryResult(data, budget) {
|
|
|
5851
5900
|
}
|
|
5852
5901
|
result = { version: Buffer24.from(CONTRACT), records, page: page.value, quality, usage };
|
|
5853
5902
|
} else if (kind === 1) {
|
|
5903
|
+
if (usageInteger(usage, "result_records") !== 1n) {
|
|
5904
|
+
throw new FerricStoreError("compact FLOW.QUERY count usage is inconsistent");
|
|
5905
|
+
}
|
|
5854
5906
|
const count = readU64(data, offset);
|
|
5907
|
+
if (BigInt(count.value) > MAX_SIGNED_64) {
|
|
5908
|
+
throw new FerricStoreError("compact FLOW.QUERY count exceeds signed 64-bit range");
|
|
5909
|
+
}
|
|
5855
5910
|
offset = count.offset;
|
|
5856
5911
|
result = {
|
|
5857
5912
|
version: Buffer24.from(CONTRACT),
|
|
@@ -5876,18 +5931,37 @@ function readPage(data, offset) {
|
|
|
5876
5931
|
if (hasMoreCode === 0 && size === NULL_U32) {
|
|
5877
5932
|
return { value: { has_more: false, cursor: null }, offset };
|
|
5878
5933
|
}
|
|
5879
|
-
if (hasMoreCode !== 1 || size
|
|
5934
|
+
if (hasMoreCode !== 1 || size < MIN_CURSOR_BYTES || size === NULL_U32 || size > MAX_CURSOR_BYTES) {
|
|
5880
5935
|
throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
|
|
5881
5936
|
}
|
|
5882
5937
|
requireAvailable(data, offset, size);
|
|
5938
|
+
const cursor = data.subarray(offset, offset + size);
|
|
5939
|
+
if (!cursor.subarray(0, CURSOR_PREFIX.byteLength).equals(CURSOR_PREFIX) || !isUtf82(cursor)) {
|
|
5940
|
+
throw new FerricStoreError("invalid compact FLOW.QUERY page cursor");
|
|
5941
|
+
}
|
|
5883
5942
|
return {
|
|
5884
5943
|
value: {
|
|
5885
5944
|
has_more: true,
|
|
5886
|
-
cursor: detachDecodedBinary(
|
|
5945
|
+
cursor: detachDecodedBinary(cursor, data.byteLength)
|
|
5887
5946
|
},
|
|
5888
5947
|
offset: offset + size
|
|
5889
5948
|
};
|
|
5890
5949
|
}
|
|
5950
|
+
function validateCompactUsage(usage) {
|
|
5951
|
+
const scanned = usageInteger(usage, "scanned_entries");
|
|
5952
|
+
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) {
|
|
5953
|
+
throw new FerricStoreError("compact FLOW.QUERY usage counters are inconsistent");
|
|
5954
|
+
}
|
|
5955
|
+
}
|
|
5956
|
+
function validateCompactRecordUsage(usage, count) {
|
|
5957
|
+
const resultRecords = usageInteger(usage, "result_records");
|
|
5958
|
+
if (resultRecords !== BigInt(count) || resultRecords > usageInteger(usage, "scanned_entries")) {
|
|
5959
|
+
throw new FerricStoreError("compact FLOW.QUERY record usage is inconsistent");
|
|
5960
|
+
}
|
|
5961
|
+
}
|
|
5962
|
+
function usageInteger(usage, field3) {
|
|
5963
|
+
return BigInt(usage[field3]);
|
|
5964
|
+
}
|
|
5891
5965
|
function readRecord(data, offset, budget) {
|
|
5892
5966
|
requireAvailable(data, offset, 4);
|
|
5893
5967
|
const bitmap = data.readUInt32BE(offset);
|
|
@@ -7913,6 +7987,63 @@ function nativeStartupPayload(clientName, events) {
|
|
|
7913
7987
|
};
|
|
7914
7988
|
}
|
|
7915
7989
|
|
|
7990
|
+
// src/flow-query-deadline.ts
|
|
7991
|
+
import { Buffer as Buffer31 } from "buffer";
|
|
7992
|
+
function withFlowQueryDeadline(command, timeoutMs, nowMs2) {
|
|
7993
|
+
if (timeoutMs == null) return command;
|
|
7994
|
+
if (command.opcode === OPCODES.pipeline) {
|
|
7995
|
+
return withPipelineQueryDeadlines(command, timeoutMs, nowMs2);
|
|
7996
|
+
}
|
|
7997
|
+
if (command.opcode !== OPCODES.flowQuery) return command;
|
|
7998
|
+
const payload = command.payload;
|
|
7999
|
+
if (payload instanceof Map) {
|
|
8000
|
+
const nextPayload = new Map(payload);
|
|
8001
|
+
nextPayload.set("deadline_ms", flowQueryDeadlineMs(timeoutMs, nowMs2));
|
|
8002
|
+
return { ...command, payload: nextPayload };
|
|
8003
|
+
}
|
|
8004
|
+
if (typeof payload !== "object" || payload == null || Array.isArray(payload) || Buffer31.isBuffer(payload) || payload instanceof Uint8Array) {
|
|
8005
|
+
return command;
|
|
8006
|
+
}
|
|
8007
|
+
return {
|
|
8008
|
+
...command,
|
|
8009
|
+
payload: {
|
|
8010
|
+
...payload,
|
|
8011
|
+
deadline_ms: flowQueryDeadlineMs(timeoutMs, nowMs2)
|
|
8012
|
+
}
|
|
8013
|
+
};
|
|
8014
|
+
}
|
|
8015
|
+
function withPipelineQueryDeadlines(command, timeoutMs, nowMs2) {
|
|
8016
|
+
const payload = plainRecord(command.payload);
|
|
8017
|
+
if (payload == null) return command;
|
|
8018
|
+
const rawCommands = payload.commands;
|
|
8019
|
+
if (!Array.isArray(rawCommands)) return command;
|
|
8020
|
+
let commands;
|
|
8021
|
+
let deadlineMs;
|
|
8022
|
+
for (let index = 0; index < rawCommands.length; index += 1) {
|
|
8023
|
+
const rawItem = rawCommands[index];
|
|
8024
|
+
const item = plainRecord(rawItem);
|
|
8025
|
+
if (item?.opcode !== OPCODES.flowQuery) continue;
|
|
8026
|
+
const body = plainRecord(item.body);
|
|
8027
|
+
if (body == null) continue;
|
|
8028
|
+
commands ??= rawCommands.slice();
|
|
8029
|
+
deadlineMs ??= flowQueryDeadlineMs(timeoutMs, nowMs2);
|
|
8030
|
+
commands[index] = { ...item, body: { ...body, deadline_ms: deadlineMs } };
|
|
8031
|
+
}
|
|
8032
|
+
return commands == null ? command : { ...command, payload: { ...payload, commands } };
|
|
8033
|
+
}
|
|
8034
|
+
function flowQueryDeadlineMs(timeoutMs, nowMs2) {
|
|
8035
|
+
return Math.min(
|
|
8036
|
+
Number.MAX_SAFE_INTEGER,
|
|
8037
|
+
(nowMs2 ?? Date.now()) + Math.max(1, Math.ceil(timeoutMs))
|
|
8038
|
+
);
|
|
8039
|
+
}
|
|
8040
|
+
function plainRecord(value) {
|
|
8041
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || Buffer31.isBuffer(value) || value instanceof Uint8Array) {
|
|
8042
|
+
return void 0;
|
|
8043
|
+
}
|
|
8044
|
+
return value;
|
|
8045
|
+
}
|
|
8046
|
+
|
|
7916
8047
|
// src/native-adapter.ts
|
|
7917
8048
|
var NativeAdapter = class _NativeAdapter {
|
|
7918
8049
|
socket;
|
|
@@ -8118,7 +8249,11 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
8118
8249
|
let frame;
|
|
8119
8250
|
try {
|
|
8120
8251
|
requestId = this.requestScheduler.nextRequestId();
|
|
8121
|
-
frame = encodeRequest(
|
|
8252
|
+
frame = encodeRequest(
|
|
8253
|
+
withFlowQueryDeadline(command, timeoutMs),
|
|
8254
|
+
requestId,
|
|
8255
|
+
this.capabilities.requestFrameBytes
|
|
8256
|
+
);
|
|
8122
8257
|
} catch (error) {
|
|
8123
8258
|
if (hasFlowControlCredit) this.flowControl.release(laneId);
|
|
8124
8259
|
return Promise.reject(error instanceof Error ? error : new FerricStoreError(String(error), { raw: error }));
|
|
@@ -8266,7 +8401,7 @@ function executeCommandArgs(executor, args) {
|
|
|
8266
8401
|
import "buffer";
|
|
8267
8402
|
|
|
8268
8403
|
// src/command-retry-policy.ts
|
|
8269
|
-
import { Buffer as
|
|
8404
|
+
import { Buffer as Buffer33 } from "buffer";
|
|
8270
8405
|
function isCasMutation(args) {
|
|
8271
8406
|
const offset = commandName2(args[0]) === "COMMAND_EXEC" ? 1 : 0;
|
|
8272
8407
|
const name = commandName2(args[offset]);
|
|
@@ -8280,8 +8415,8 @@ function isCasMutation(args) {
|
|
|
8280
8415
|
}
|
|
8281
8416
|
function commandName2(value) {
|
|
8282
8417
|
if (typeof value === "string") return value.toUpperCase();
|
|
8283
|
-
if (
|
|
8284
|
-
return
|
|
8418
|
+
if (Buffer33.isBuffer(value) || value instanceof Uint8Array) {
|
|
8419
|
+
return Buffer33.from(value).toString("utf8").toUpperCase();
|
|
8285
8420
|
}
|
|
8286
8421
|
return void 0;
|
|
8287
8422
|
}
|
|
@@ -8496,12 +8631,12 @@ function normalizeNonNegativeInteger2(value, fallback) {
|
|
|
8496
8631
|
import "buffer";
|
|
8497
8632
|
|
|
8498
8633
|
// src/topology-routing.ts
|
|
8499
|
-
import { Buffer as
|
|
8634
|
+
import { Buffer as Buffer36 } from "buffer";
|
|
8500
8635
|
|
|
8501
8636
|
// src/flow-partition-route-cache.ts
|
|
8502
|
-
import { Buffer as
|
|
8637
|
+
import { Buffer as Buffer35 } from "buffer";
|
|
8503
8638
|
import { createHash } from "crypto";
|
|
8504
|
-
var AUTO_PREFIX =
|
|
8639
|
+
var AUTO_PREFIX = Buffer35.from("__flow_auto__:", "ascii");
|
|
8505
8640
|
var MAX_CACHEABLE_PARTITION_BYTES = 4 * 1024;
|
|
8506
8641
|
var MAX_CACHE_BYTES = 1 * 1024 * 1024;
|
|
8507
8642
|
var MAX_CACHE_ENTRIES = 1024;
|
|
@@ -8511,10 +8646,10 @@ var cacheBytes = 0;
|
|
|
8511
8646
|
var cacheHits = 0;
|
|
8512
8647
|
var cacheMisses = 0;
|
|
8513
8648
|
function flowLogicalPartitionRoutingKey(value) {
|
|
8514
|
-
if (typeof value !== "string" && !
|
|
8649
|
+
if (typeof value !== "string" && !Buffer35.isBuffer(value)) return void 0;
|
|
8515
8650
|
const autoBucket = flowAutoBucket(value);
|
|
8516
8651
|
if (autoBucket != null) return `{fa:${autoBucket}}`;
|
|
8517
|
-
const bytes2 =
|
|
8652
|
+
const bytes2 = Buffer35.isBuffer(value) ? value : Buffer35.from(value);
|
|
8518
8653
|
if (bytes2.byteLength > MAX_CACHEABLE_PARTITION_BYTES) return hashRoute(bytes2);
|
|
8519
8654
|
const cacheKey = bytes2.toString("base64");
|
|
8520
8655
|
const cached = routeCache.get(cacheKey);
|
|
@@ -8588,7 +8723,7 @@ function routingKeyFromProtocolPayload(name, command) {
|
|
|
8588
8723
|
"scope"
|
|
8589
8724
|
]) {
|
|
8590
8725
|
const value = getField(command.payload, field3);
|
|
8591
|
-
if (typeof value === "string" ||
|
|
8726
|
+
if (typeof value === "string" || Buffer36.isBuffer(value)) {
|
|
8592
8727
|
return value;
|
|
8593
8728
|
}
|
|
8594
8729
|
}
|
|
@@ -8636,7 +8771,7 @@ function flowRoutingData(name, args) {
|
|
|
8636
8771
|
if (typeof partition === "string" && partition.toUpperCase() !== "AUTO" && partition.toUpperCase() !== "MIXED") {
|
|
8637
8772
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
8638
8773
|
}
|
|
8639
|
-
if (
|
|
8774
|
+
if (Buffer36.isBuffer(partition)) {
|
|
8640
8775
|
const text3 = partition.toString("utf8").toUpperCase();
|
|
8641
8776
|
if (text3 !== "AUTO" && text3 !== "MIXED") {
|
|
8642
8777
|
return flowRoutingResult(flowLogicalPartitionRoutingKey(partition));
|
|
@@ -8727,17 +8862,17 @@ function flowPartitionRoutingKeyFromCommand(command, claim) {
|
|
|
8727
8862
|
return { handled: false };
|
|
8728
8863
|
}
|
|
8729
8864
|
function isRoutingKey(value) {
|
|
8730
|
-
return typeof value === "string" ||
|
|
8865
|
+
return typeof value === "string" || Buffer36.isBuffer(value);
|
|
8731
8866
|
}
|
|
8732
8867
|
function flowAutoIdRoutingKey(value) {
|
|
8733
|
-
if (typeof value !== "string" && !
|
|
8868
|
+
if (typeof value !== "string" && !Buffer36.isBuffer(value)) {
|
|
8734
8869
|
return void 0;
|
|
8735
8870
|
}
|
|
8736
|
-
const bucket = (
|
|
8871
|
+
const bucket = (Buffer36.isBuffer(value) ? crc32(value) : crc32Utf8(value)) & 255;
|
|
8737
8872
|
return `{fa:${bucket}}`;
|
|
8738
8873
|
}
|
|
8739
8874
|
function flowClaimLogicalPartitionRoutingKey(value) {
|
|
8740
|
-
if (typeof value !== "string" && !
|
|
8875
|
+
if (typeof value !== "string" && !Buffer36.isBuffer(value)) return void 0;
|
|
8741
8876
|
const selector = commandPart(value);
|
|
8742
8877
|
if (selector === "AUTO" || selector === "ANY") return void 0;
|
|
8743
8878
|
if (selector === "GLOBAL") return "{f}";
|
|
@@ -8752,7 +8887,7 @@ function singleShardFlowClaimPartitionKey(values) {
|
|
|
8752
8887
|
return keys.some((key) => key == null) ? void 0 : singleShardKey(keys);
|
|
8753
8888
|
}
|
|
8754
8889
|
function singleShardKey(keys) {
|
|
8755
|
-
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !
|
|
8890
|
+
if (keys.length === 0 || keys.some((key) => typeof key !== "string" && !Buffer36.isBuffer(key))) {
|
|
8756
8891
|
return void 0;
|
|
8757
8892
|
}
|
|
8758
8893
|
const usable = keys;
|
|
@@ -8785,7 +8920,7 @@ function routedKeyGroups(keys, routeKey) {
|
|
|
8785
8920
|
const groups = /* @__PURE__ */ new Map();
|
|
8786
8921
|
for (let index = 0; index < keys.length; index += 1) {
|
|
8787
8922
|
const key = keys[index];
|
|
8788
|
-
if (typeof key !== "string" && !
|
|
8923
|
+
if (typeof key !== "string" && !Buffer36.isBuffer(key)) return void 0;
|
|
8789
8924
|
const route = routeKey(key);
|
|
8790
8925
|
const groupKey = `${route.endpointKey}\0${route.laneId}`;
|
|
8791
8926
|
const group = groups.get(groupKey);
|
|
@@ -9874,7 +10009,7 @@ var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
|
9874
10009
|
};
|
|
9875
10010
|
|
|
9876
10011
|
// src/response-map-preservation.ts
|
|
9877
|
-
import { Buffer as
|
|
10012
|
+
import { Buffer as Buffer38 } from "buffer";
|
|
9878
10013
|
function toStringKeyMapPreservingValues(value) {
|
|
9879
10014
|
if (value == null) return void 0;
|
|
9880
10015
|
const result = {};
|
|
@@ -9884,7 +10019,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
9884
10019
|
}
|
|
9885
10020
|
return result;
|
|
9886
10021
|
}
|
|
9887
|
-
if (typeof value === "object" && !Array.isArray(value) && !
|
|
10022
|
+
if (typeof value === "object" && !Array.isArray(value) && !Buffer38.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
9888
10023
|
for (const [key, item] of Object.entries(value)) {
|
|
9889
10024
|
setOwnValue(result, text(key), normalizeMapStructurePreservingBytes(item));
|
|
9890
10025
|
}
|
|
@@ -9893,7 +10028,7 @@ function toStringKeyMapPreservingValues(value) {
|
|
|
9893
10028
|
return void 0;
|
|
9894
10029
|
}
|
|
9895
10030
|
function normalizeMapStructurePreservingBytes(value) {
|
|
9896
|
-
if (
|
|
10031
|
+
if (Buffer38.isBuffer(value) || value instanceof Uint8Array) return value;
|
|
9897
10032
|
if (value instanceof Map) {
|
|
9898
10033
|
const result = {};
|
|
9899
10034
|
for (const [key, item] of value.entries()) {
|
|
@@ -9915,7 +10050,7 @@ function normalizeMapStructurePreservingBytes(value) {
|
|
|
9915
10050
|
}
|
|
9916
10051
|
|
|
9917
10052
|
// src/native-kv-responses.ts
|
|
9918
|
-
import { Buffer as
|
|
10053
|
+
import { Buffer as Buffer39 } from "buffer";
|
|
9919
10054
|
function rateLimitResultFromResp(value) {
|
|
9920
10055
|
if (!Array.isArray(value) || value.length !== 4) {
|
|
9921
10056
|
throw new TypeError("RATELIMIT.ADD returned an unexpected response");
|
|
@@ -9972,13 +10107,13 @@ function fetchOrComputeResultFromResp(value, codec) {
|
|
|
9972
10107
|
}
|
|
9973
10108
|
function decodePayload(codec, value) {
|
|
9974
10109
|
if (value == null) return null;
|
|
9975
|
-
if (
|
|
9976
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
9977
|
-
if (typeof value === "string") return codec.decode(
|
|
10110
|
+
if (Buffer39.isBuffer(value)) return codec.decode(value);
|
|
10111
|
+
if (value instanceof Uint8Array) return codec.decode(Buffer39.from(value));
|
|
10112
|
+
if (typeof value === "string") return codec.decode(Buffer39.from(value));
|
|
9978
10113
|
return normalizeRefMeta(value);
|
|
9979
10114
|
}
|
|
9980
10115
|
function requiredResponseString(value, context) {
|
|
9981
|
-
if (typeof value !== "string" && !
|
|
10116
|
+
if (typeof value !== "string" && !Buffer39.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
9982
10117
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
9983
10118
|
}
|
|
9984
10119
|
const result = text(value);
|
|
@@ -9995,7 +10130,7 @@ function requiredNonNegativeInteger(value, context) {
|
|
|
9995
10130
|
return result;
|
|
9996
10131
|
}
|
|
9997
10132
|
function responseBytes(value, context) {
|
|
9998
|
-
if (typeof value !== "string" && !
|
|
10133
|
+
if (typeof value !== "string" && !Buffer39.isBuffer(value) && !(value instanceof Uint8Array)) {
|
|
9999
10134
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
10000
10135
|
}
|
|
10001
10136
|
return bytes(value);
|
|
@@ -10678,7 +10813,7 @@ function groupAutoPartitionItems(items) {
|
|
|
10678
10813
|
}
|
|
10679
10814
|
|
|
10680
10815
|
// src/client-values.ts
|
|
10681
|
-
import { Buffer as
|
|
10816
|
+
import { Buffer as Buffer40 } from "buffer";
|
|
10682
10817
|
async function valueMGetEntries(client, refs, options = {}) {
|
|
10683
10818
|
const refCount = refs.length;
|
|
10684
10819
|
if (refCount === 0) {
|
|
@@ -10713,12 +10848,12 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
10713
10848
|
const item = response[index];
|
|
10714
10849
|
if (item == null) {
|
|
10715
10850
|
entries[index] = { found: false };
|
|
10716
|
-
} else if (
|
|
10851
|
+
} else if (Buffer40.isBuffer(item)) {
|
|
10717
10852
|
entries[index] = { found: true, value: client.codec.decode(item) };
|
|
10718
10853
|
} else if (item instanceof Uint8Array) {
|
|
10719
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10854
|
+
entries[index] = { found: true, value: client.codec.decode(Buffer40.from(item)) };
|
|
10720
10855
|
} else if (typeof item === "string") {
|
|
10721
|
-
entries[index] = { found: true, value: client.codec.decode(
|
|
10856
|
+
entries[index] = { found: true, value: client.codec.decode(Buffer40.from(item)) };
|
|
10722
10857
|
} else {
|
|
10723
10858
|
entries[index] = { found: true, value: item };
|
|
10724
10859
|
}
|
|
@@ -10730,7 +10865,7 @@ async function valueMGetEntries(client, refs, options = {}) {
|
|
|
10730
10865
|
import "buffer";
|
|
10731
10866
|
|
|
10732
10867
|
// src/auto-batch-ordering.ts
|
|
10733
|
-
import { Buffer as
|
|
10868
|
+
import { Buffer as Buffer41 } from "buffer";
|
|
10734
10869
|
function autoBatchOrderingPlan(batch) {
|
|
10735
10870
|
const accesses = /* @__PURE__ */ new Map();
|
|
10736
10871
|
const fallbackDependencies = [];
|
|
@@ -10845,13 +10980,13 @@ function flowManyAutoBatchIds(command, name) {
|
|
|
10845
10980
|
return fixedFlowItemIds(
|
|
10846
10981
|
command,
|
|
10847
10982
|
mixed ? 4 : 3,
|
|
10848
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) &&
|
|
10983
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && isFencingToken(command[itemIndex + (mixed ? 2 : 1)]) && Buffer41.isBuffer(command[itemIndex + (mixed ? 3 : 2)])
|
|
10849
10984
|
);
|
|
10850
10985
|
}
|
|
10851
10986
|
return fixedFlowItemIds(
|
|
10852
10987
|
command,
|
|
10853
10988
|
mixed ? 4 : 3,
|
|
10854
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
10989
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer41.isBuffer(command[itemIndex + (mixed ? 2 : 1)]) && isFencingToken(command[itemIndex + (mixed ? 3 : 2)])
|
|
10855
10990
|
);
|
|
10856
10991
|
}
|
|
10857
10992
|
function createManyAutoBatchIds(command) {
|
|
@@ -10864,7 +10999,7 @@ function createManyAutoBatchIds(command) {
|
|
|
10864
10999
|
const ids = fixedFlowItemIds(
|
|
10865
11000
|
command,
|
|
10866
11001
|
width,
|
|
10867
|
-
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) &&
|
|
11002
|
+
(itemIndex) => isAutoBatchResourceValue(command[itemIndex]) && (!mixed || isAutoBatchResourceValue(command[itemIndex + 1])) && Buffer41.isBuffer(command[itemIndex + width - 1]),
|
|
10868
11003
|
markerIndex
|
|
10869
11004
|
);
|
|
10870
11005
|
if (ids != null) return ids;
|
|
@@ -10882,7 +11017,7 @@ function extendedCreateManyAutoBatchIds(command, markerIndex) {
|
|
|
10882
11017
|
let cursor = markerIndex + 2;
|
|
10883
11018
|
for (let itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
|
|
10884
11019
|
const id = command[cursor];
|
|
10885
|
-
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !
|
|
11020
|
+
if (!isAutoBatchResourceValue(id) || !isAutoBatchResourceValue(command[cursor + 1]) || !Buffer41.isBuffer(command[cursor + 2])) return void 0;
|
|
10886
11021
|
ids.push(id);
|
|
10887
11022
|
cursor += 3;
|
|
10888
11023
|
const afterValues = skipExtendedNamedItems(command, cursor, true);
|
|
@@ -10901,7 +11036,7 @@ function skipExtendedNamedItems(command, countIndex, encodedValues) {
|
|
|
10901
11036
|
for (let index = 0; index < count; index += 1) {
|
|
10902
11037
|
const name = command[firstItem + index * 2];
|
|
10903
11038
|
const value = command[firstItem + index * 2 + 1];
|
|
10904
|
-
if (!isAutoBatchResourceValue(name) || (encodedValues ? !
|
|
11039
|
+
if (!isAutoBatchResourceValue(name) || (encodedValues ? !Buffer41.isBuffer(value) : !isAutoBatchResourceValue(value))) return void 0;
|
|
10905
11040
|
}
|
|
10906
11041
|
return firstItem + count * 2;
|
|
10907
11042
|
}
|
|
@@ -10916,7 +11051,7 @@ function runStepsManyAutoBatchIds(command) {
|
|
|
10916
11051
|
ids.push(item);
|
|
10917
11052
|
continue;
|
|
10918
11053
|
}
|
|
10919
|
-
if (typeof item !== "object" || item == null || Array.isArray(item) ||
|
|
11054
|
+
if (typeof item !== "object" || item == null || Array.isArray(item) || Buffer41.isBuffer(item)) return void 0;
|
|
10920
11055
|
const id = item.id;
|
|
10921
11056
|
if (!isAutoBatchResourceValue(id)) return void 0;
|
|
10922
11057
|
ids.push(id);
|
|
@@ -10957,7 +11092,7 @@ function flowValuePutOwner(command, start) {
|
|
|
10957
11092
|
}
|
|
10958
11093
|
var flowValuePutOptionTokens = /* @__PURE__ */ new Set(["NAME", "NOW", "OVERRIDE", "OWNER_FLOW_ID", "PARTITION", "TTL", "TTL_MS"]);
|
|
10959
11094
|
function isAutoBatchResourceValue(value) {
|
|
10960
|
-
return typeof value === "string" ||
|
|
11095
|
+
return typeof value === "string" || Buffer41.isBuffer(value);
|
|
10961
11096
|
}
|
|
10962
11097
|
function isFencingToken(value) {
|
|
10963
11098
|
return typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint";
|
|
@@ -10966,7 +11101,7 @@ function nonNegativeItemCount(value) {
|
|
|
10966
11101
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
10967
11102
|
}
|
|
10968
11103
|
function autoBatchResourceKey(namespace, value) {
|
|
10969
|
-
return `${namespace}:${
|
|
11104
|
+
return `${namespace}:${Buffer41.from(value).toString("base64")}`;
|
|
10970
11105
|
}
|
|
10971
11106
|
function autoBatchCommandName(command) {
|
|
10972
11107
|
return commandView(command).name ?? null;
|
|
@@ -11378,10 +11513,10 @@ function claimFailure(error) {
|
|
|
11378
11513
|
import "buffer";
|
|
11379
11514
|
|
|
11380
11515
|
// src/flow-query-builder.ts
|
|
11381
|
-
import { Buffer as
|
|
11516
|
+
import { Buffer as Buffer44 } from "buffer";
|
|
11382
11517
|
|
|
11383
11518
|
// src/flow-query-metadata.ts
|
|
11384
|
-
import { Buffer as
|
|
11519
|
+
import { Buffer as Buffer43 } from "buffer";
|
|
11385
11520
|
var MAX_FLOW_QUERY_METADATA_KEY_BYTES = 64;
|
|
11386
11521
|
function normalizeStateMeta(value, state) {
|
|
11387
11522
|
if (value == null) return {};
|
|
@@ -11406,7 +11541,7 @@ function normalizeStateMeta(value, state) {
|
|
|
11406
11541
|
function metadataEntries(value, context) {
|
|
11407
11542
|
const entries = objectEntries(value ?? {}, context).map(([rawName, item]) => {
|
|
11408
11543
|
const name = rawName.trim();
|
|
11409
|
-
const size =
|
|
11544
|
+
const size = Buffer43.byteLength(name, "utf8");
|
|
11410
11545
|
if (size === 0 || size > MAX_FLOW_QUERY_METADATA_KEY_BYTES || name.startsWith("__")) {
|
|
11411
11546
|
throw new TypeError(`${context} key is invalid or reserved`);
|
|
11412
11547
|
}
|
|
@@ -11430,7 +11565,7 @@ function objectEntries(value, context) {
|
|
|
11430
11565
|
return keys.map((key) => [key, value[key]]);
|
|
11431
11566
|
}
|
|
11432
11567
|
function isPlainRecord(value) {
|
|
11433
|
-
if (typeof value !== "object" || value == null || Array.isArray(value) ||
|
|
11568
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || Buffer43.isBuffer(value)) {
|
|
11434
11569
|
return false;
|
|
11435
11570
|
}
|
|
11436
11571
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -11500,7 +11635,7 @@ var FlowCollectionQuery = class {
|
|
|
11500
11635
|
const states = /* @__PURE__ */ new Set();
|
|
11501
11636
|
for (const [rawState, metadata] of objectEntries(values, "stateMeta")) {
|
|
11502
11637
|
const state = requiredText(rawState, "stateMeta state").trim();
|
|
11503
|
-
const stateBytes =
|
|
11638
|
+
const stateBytes = Buffer44.byteLength(state, "utf8");
|
|
11504
11639
|
if (stateBytes === 0 || stateBytes > MAX_FLOW_QUERY_STATE_BYTES) {
|
|
11505
11640
|
throw new TypeError(
|
|
11506
11641
|
`stateMeta state names must be 1..${MAX_FLOW_QUERY_STATE_BYTES} bytes`
|
|
@@ -11679,7 +11814,7 @@ function requiredPartition(value) {
|
|
|
11679
11814
|
"FLOW.QUERY convenience methods require a partition key"
|
|
11680
11815
|
);
|
|
11681
11816
|
}
|
|
11682
|
-
const size =
|
|
11817
|
+
const size = Buffer44.byteLength(value, "utf8");
|
|
11683
11818
|
if (size === 0 || size > MAX_FLOW_QUERY_PARTITION_BYTES) {
|
|
11684
11819
|
throw new TypeError(
|
|
11685
11820
|
`FLOW.QUERY partition key must be 1..${MAX_FLOW_QUERY_PARTITION_BYTES} bytes`
|
|
@@ -11727,20 +11862,23 @@ function requiredText(value, context) {
|
|
|
11727
11862
|
return value;
|
|
11728
11863
|
}
|
|
11729
11864
|
function queryParameter(value, context) {
|
|
11730
|
-
if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" ||
|
|
11865
|
+
if (typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" || Buffer44.isBuffer(value)) {
|
|
11731
11866
|
return value;
|
|
11732
11867
|
}
|
|
11733
11868
|
throw new TypeError(`${context} must be a scalar FLOW.QUERY parameter`);
|
|
11734
11869
|
}
|
|
11735
11870
|
|
|
11736
11871
|
// src/flow-query-response.ts
|
|
11737
|
-
import { Buffer as
|
|
11872
|
+
import { Buffer as Buffer48 } from "buffer";
|
|
11873
|
+
|
|
11874
|
+
// src/flow-query-diagnostic-response.ts
|
|
11875
|
+
import { Buffer as Buffer46 } from "buffer";
|
|
11738
11876
|
|
|
11739
11877
|
// src/flow-query-response-validation.ts
|
|
11740
|
-
import { Buffer as
|
|
11878
|
+
import { Buffer as Buffer45 } from "buffer";
|
|
11741
11879
|
function requiredMap2(value, context) {
|
|
11742
11880
|
if (value instanceof Map) return value;
|
|
11743
|
-
if (typeof value !== "object" || value == null || Array.isArray(value) ||
|
|
11881
|
+
if (typeof value !== "object" || value == null || Array.isArray(value) || Buffer45.isBuffer(value) || value instanceof Uint8Array) {
|
|
11744
11882
|
throw decodeError(`${context} must be a map`, value);
|
|
11745
11883
|
}
|
|
11746
11884
|
return value;
|
|
@@ -11797,7 +11935,7 @@ function normalizeMetadataValue(value, context, budget, ancestors, depth) {
|
|
|
11797
11935
|
if (!value.isWellFormed()) throw decodeError(`${context} contains invalid text`, value);
|
|
11798
11936
|
return value;
|
|
11799
11937
|
}
|
|
11800
|
-
if (
|
|
11938
|
+
if (Buffer45.isBuffer(value) || value instanceof Uint8Array) {
|
|
11801
11939
|
const decoded = strictText2(value);
|
|
11802
11940
|
if (decoded == null) throw decodeError(`${context} contains invalid UTF-8`, value);
|
|
11803
11941
|
return decoded;
|
|
@@ -11876,7 +12014,7 @@ function optionalText2(mapping, name, context) {
|
|
|
11876
12014
|
}
|
|
11877
12015
|
function requiredBoundedText2(mapping, name, context, maximumBytes) {
|
|
11878
12016
|
const value = requiredText2(mapping, name, context);
|
|
11879
|
-
if (
|
|
12017
|
+
if (Buffer45.byteLength(value, "utf8") > maximumBytes) {
|
|
11880
12018
|
throw decodeError(
|
|
11881
12019
|
`${context} ${name} exceeds ${maximumBytes} bytes`,
|
|
11882
12020
|
mapping
|
|
@@ -11889,7 +12027,7 @@ function boundedText(value, context, maximumBytes) {
|
|
|
11889
12027
|
if (decoded == null || decoded.length === 0) {
|
|
11890
12028
|
throw decodeError(`${context} must be non-empty text`, value);
|
|
11891
12029
|
}
|
|
11892
|
-
if (
|
|
12030
|
+
if (Buffer45.byteLength(decoded, "utf8") > maximumBytes) {
|
|
11893
12031
|
throw decodeError(`${context} exceeds ${maximumBytes} bytes`, value);
|
|
11894
12032
|
}
|
|
11895
12033
|
return decoded;
|
|
@@ -11943,10 +12081,10 @@ function positiveBoundedInteger(value, maximum, context) {
|
|
|
11943
12081
|
function hasKey(mapping, name) {
|
|
11944
12082
|
if (!(mapping instanceof Map)) return Object.hasOwn(mapping, name);
|
|
11945
12083
|
if (mapping.has(name)) return true;
|
|
11946
|
-
const binaryName =
|
|
12084
|
+
const binaryName = Buffer45.from(name);
|
|
11947
12085
|
for (const key of mapping.keys()) {
|
|
11948
|
-
if (
|
|
11949
|
-
if (key instanceof Uint8Array &&
|
|
12086
|
+
if (Buffer45.isBuffer(key) && key.equals(binaryName)) return true;
|
|
12087
|
+
if (key instanceof Uint8Array && Buffer45.from(key).equals(binaryName))
|
|
11950
12088
|
return true;
|
|
11951
12089
|
}
|
|
11952
12090
|
return false;
|
|
@@ -11957,7 +12095,7 @@ function decodeError(message, raw) {
|
|
|
11957
12095
|
function strictText2(value) {
|
|
11958
12096
|
if (typeof value === "string")
|
|
11959
12097
|
return value.isWellFormed() ? value : void 0;
|
|
11960
|
-
if (
|
|
12098
|
+
if (Buffer45.isBuffer(value) || value instanceof Uint8Array) {
|
|
11961
12099
|
try {
|
|
11962
12100
|
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
11963
12101
|
} catch {
|
|
@@ -11990,189 +12128,35 @@ var FlowQueryError = class extends FerricStoreError {
|
|
|
11990
12128
|
}
|
|
11991
12129
|
};
|
|
11992
12130
|
|
|
11993
|
-
// src/flow-query-response.ts
|
|
11994
|
-
var
|
|
11995
|
-
var
|
|
11996
|
-
var
|
|
11997
|
-
var
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
|
|
12002
|
-
["hydrated_records", "hydratedRecords"],
|
|
12003
|
-
["residual_checks", "residualChecks"],
|
|
12004
|
-
["duplicate_entries", "duplicateEntries"],
|
|
12005
|
-
["result_records", "resultRecords"],
|
|
12006
|
-
["response_bytes", "responseBytes"],
|
|
12007
|
-
["memory_high_water_bytes", "memoryHighWaterBytes"],
|
|
12008
|
-
["wall_time_us", "wallTimeUs"]
|
|
12009
|
-
];
|
|
12010
|
-
var MAX_SIGNED_64 = (1n << 63n) - 1n;
|
|
12011
|
-
var MAX_UNSIGNED_64 = (1n << 64n) - 1n;
|
|
12012
|
-
function decodeFlowQueryResult(value) {
|
|
12013
|
-
const result = decodeFlowQueryResponse(value, (mapping) => freezeMap(mapping));
|
|
12014
|
-
if (result.kind === "records") {
|
|
12015
|
-
return Object.freeze({
|
|
12016
|
-
kind: "records",
|
|
12017
|
-
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
12018
|
-
records: Object.freeze(result.records),
|
|
12019
|
-
page: result.page,
|
|
12020
|
-
quality: result.quality,
|
|
12021
|
-
usage: result.usage,
|
|
12022
|
-
raw: result.raw
|
|
12023
|
-
});
|
|
12024
|
-
}
|
|
12025
|
-
return Object.freeze({
|
|
12026
|
-
kind: "count",
|
|
12027
|
-
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
12028
|
-
count: result.count,
|
|
12029
|
-
quality: result.quality,
|
|
12030
|
-
usage: result.usage,
|
|
12031
|
-
raw: result.raw
|
|
12032
|
-
});
|
|
12033
|
-
}
|
|
12034
|
-
function decodeFlowQueryRecords(value, decodeRecord) {
|
|
12035
|
-
const result = decodeFlowQueryResponse(
|
|
12036
|
-
value,
|
|
12037
|
-
(mapping, index) => decodeRecord(mapping instanceof Map ? freezeMap(mapping) : mapping, index)
|
|
12038
|
-
);
|
|
12039
|
-
if (result.kind === "count") {
|
|
12040
|
-
throw new FerricStoreError("Flow record convenience query returned a count result", {
|
|
12041
|
-
raw: result.raw
|
|
12042
|
-
});
|
|
12043
|
-
}
|
|
12044
|
-
return result.records;
|
|
12045
|
-
}
|
|
12046
|
-
function decodeFlowQueryResponse(value, decodeRecord) {
|
|
12047
|
-
const mapping = requiredMap2(value, "FLOW.QUERY result");
|
|
12048
|
-
requireContract(mapping, "version", FLOW_QUERY_RESULT_CONTRACT, "FLOW.QUERY result");
|
|
12049
|
-
const quality = decodeQuality(field(mapping, "quality"));
|
|
12050
|
-
const usage = decodeUsage(field(mapping, "usage"));
|
|
12051
|
-
const hasRecords = hasKey(mapping, "records");
|
|
12052
|
-
const hasCount = hasKey(mapping, "result");
|
|
12053
|
-
if (hasRecords === hasCount) {
|
|
12054
|
-
throw decodeError("FLOW.QUERY result must contain exactly one records or count shape", value);
|
|
12055
|
-
}
|
|
12056
|
-
const raw = freezeMap(mapping);
|
|
12057
|
-
if (hasRecords) {
|
|
12058
|
-
const rawRecords = field(mapping, "records");
|
|
12059
|
-
if (!Array.isArray(rawRecords) || rawRecords.length > 100) {
|
|
12060
|
-
throw decodeError("FLOW.QUERY records must be an array of at most 100 maps", value);
|
|
12061
|
-
}
|
|
12062
|
-
const records = new Array(rawRecords.length);
|
|
12063
|
-
for (let index = 0; index < rawRecords.length; index += 1) {
|
|
12064
|
-
if (!Object.hasOwn(rawRecords, index)) {
|
|
12065
|
-
throw decodeError("FLOW.QUERY records must be a dense array", value);
|
|
12066
|
-
}
|
|
12067
|
-
records[index] = decodeRecord(
|
|
12068
|
-
requiredMap2(rawRecords[index], `FLOW.QUERY record ${index}`),
|
|
12069
|
-
index
|
|
12070
|
-
);
|
|
12071
|
-
}
|
|
12072
|
-
if (usage.resultRecords !== records.length) {
|
|
12073
|
-
throw decodeError("FLOW.QUERY usage result_records does not match records", value);
|
|
12074
|
-
}
|
|
12075
|
-
return {
|
|
12076
|
-
kind: "records",
|
|
12077
|
-
records,
|
|
12078
|
-
page: decodePage(field(mapping, "page")),
|
|
12079
|
-
quality,
|
|
12080
|
-
usage,
|
|
12081
|
-
raw
|
|
12082
|
-
};
|
|
12083
|
-
}
|
|
12084
|
-
if (hasKey(mapping, "page")) {
|
|
12085
|
-
throw decodeError("FLOW.QUERY count result contains an unexpected page", value);
|
|
12086
|
-
}
|
|
12087
|
-
const countResult = requiredMap2(field(mapping, "result"), "FLOW.QUERY count result");
|
|
12088
|
-
if (requiredText2(countResult, "kind", "FLOW.QUERY count result") !== "count") {
|
|
12089
|
-
throw decodeError("FLOW.QUERY count result kind must be count", value);
|
|
12090
|
-
}
|
|
12091
|
-
const count = boundedInteger(
|
|
12092
|
-
field(countResult, "value"),
|
|
12093
|
-
MAX_SIGNED_64,
|
|
12094
|
-
"FLOW.QUERY count value"
|
|
12095
|
-
);
|
|
12096
|
-
if (usage.resultRecords !== 1) {
|
|
12097
|
-
throw decodeError("FLOW.QUERY count usage result_records must be 1", value);
|
|
12098
|
-
}
|
|
12099
|
-
return {
|
|
12100
|
-
kind: "count",
|
|
12101
|
-
count,
|
|
12102
|
-
quality,
|
|
12103
|
-
usage,
|
|
12104
|
-
raw
|
|
12105
|
-
};
|
|
12106
|
-
}
|
|
12107
|
-
function decodeFlowExplainResult(value) {
|
|
12108
|
-
const mapping = requiredMap2(value, "FLOW.QUERY explain");
|
|
12109
|
-
requireContract(mapping, "version", FLOW_EXPLAIN_CONTRACT, "FLOW.QUERY explain");
|
|
12110
|
-
const queryFingerprint = requiredText2(mapping, "query_fingerprint", "FLOW.QUERY explain");
|
|
12111
|
-
if (!/^[0-9a-f]{64}$/iu.test(queryFingerprint)) {
|
|
12112
|
-
throw decodeError("FLOW.QUERY explain query_fingerprint is invalid", value);
|
|
12113
|
-
}
|
|
12114
|
-
const status = requiredText2(mapping, "status", "FLOW.QUERY explain");
|
|
12115
|
-
if (status !== "planned" && status !== "rejected" && status !== "executed") {
|
|
12116
|
-
throw decodeError(`FLOW.QUERY explain status ${JSON.stringify(status)} is unsupported`, value);
|
|
12117
|
-
}
|
|
12118
|
-
const plan = freezeMetadataMap(
|
|
12119
|
-
requiredMap2(field(mapping, "plan"), "FLOW.QUERY explain plan"),
|
|
12120
|
-
"FLOW.QUERY explain plan"
|
|
12121
|
-
);
|
|
12122
|
-
const estimate = freezeMetadataMap(
|
|
12123
|
-
requiredMap2(field(mapping, "estimate"), "FLOW.QUERY explain estimate"),
|
|
12124
|
-
"FLOW.QUERY explain estimate"
|
|
12125
|
-
);
|
|
12126
|
-
const bounds = freezeMetadataMap(
|
|
12127
|
-
requiredMap2(field(mapping, "bounds"), "FLOW.QUERY explain bounds"),
|
|
12128
|
-
"FLOW.QUERY explain bounds"
|
|
12129
|
-
);
|
|
12130
|
-
const actualValue = field(mapping, "actual");
|
|
12131
|
-
let actual;
|
|
12132
|
-
if (status === "executed") {
|
|
12133
|
-
if (actualValue == null) {
|
|
12134
|
-
throw decodeError("FLOW.QUERY executed explain is missing actual usage", value);
|
|
12135
|
-
}
|
|
12136
|
-
actual = decodeUsage(actualValue);
|
|
12137
|
-
} else if (actualValue != null) {
|
|
12138
|
-
throw decodeError("FLOW.QUERY non-executed explain contains actual usage", value);
|
|
12139
|
-
}
|
|
12140
|
-
const diagnosticValue = field(mapping, "diagnostic");
|
|
12141
|
-
let diagnostic;
|
|
12142
|
-
if (status === "rejected") {
|
|
12143
|
-
diagnostic = tryDecodeFlowQueryError(diagnosticValue);
|
|
12144
|
-
if (diagnostic == null) {
|
|
12145
|
-
throw decodeError("FLOW.QUERY rejected explain has an invalid diagnostic", value);
|
|
12146
|
-
}
|
|
12147
|
-
} else if (diagnosticValue != null) {
|
|
12148
|
-
throw decodeError("FLOW.QUERY non-rejected explain contains a diagnostic", value);
|
|
12149
|
-
}
|
|
12150
|
-
return Object.freeze({
|
|
12151
|
-
version: FLOW_EXPLAIN_CONTRACT,
|
|
12152
|
-
queryFingerprint,
|
|
12153
|
-
status,
|
|
12154
|
-
plan,
|
|
12155
|
-
estimate,
|
|
12156
|
-
bounds,
|
|
12157
|
-
actual,
|
|
12158
|
-
diagnostic,
|
|
12159
|
-
raw: freezeMap(mapping)
|
|
12160
|
-
});
|
|
12161
|
-
}
|
|
12131
|
+
// src/flow-query-diagnostic-response.ts
|
|
12132
|
+
var MIN_SIGNED_64 = -(1n << 63n);
|
|
12133
|
+
var MAX_SIGNED_642 = (1n << 63n) - 1n;
|
|
12134
|
+
var DIAGNOSTIC_TEXT_BYTES = 1024;
|
|
12135
|
+
var DIAGNOSTIC_CONTEXT_ENTRIES = 16;
|
|
12136
|
+
var DIAGNOSTIC_CONTEXT_LIST_ITEMS = 32;
|
|
12137
|
+
var DIAGNOSTIC_CONTEXT_KEY_BYTES = 128;
|
|
12138
|
+
var DIAGNOSTIC_CONTEXT_DEPTH = 6;
|
|
12139
|
+
var DIAGNOSTIC_CONTEXT_NODES = 512;
|
|
12162
12140
|
function tryDecodeFlowQueryError(value, cause) {
|
|
12163
12141
|
try {
|
|
12164
12142
|
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic");
|
|
12165
|
-
const
|
|
12166
|
-
const context = contextValue == null ? void 0 : freezeMetadataMap(
|
|
12167
|
-
requiredMap2(contextValue, "FLOW.QUERY diagnostic context"),
|
|
12168
|
-
"FLOW.QUERY diagnostic context"
|
|
12169
|
-
);
|
|
12143
|
+
const context = decodeDiagnosticContext(field(mapping, "context"));
|
|
12170
12144
|
const position = decodePosition(field(mapping, "position"));
|
|
12171
12145
|
return new FlowQueryError({
|
|
12172
|
-
code:
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12146
|
+
code: requiredBoundedText2(
|
|
12147
|
+
mapping,
|
|
12148
|
+
"code",
|
|
12149
|
+
"FLOW.QUERY diagnostic",
|
|
12150
|
+
DIAGNOSTIC_TEXT_BYTES
|
|
12151
|
+
),
|
|
12152
|
+
message: requiredBoundedText2(
|
|
12153
|
+
mapping,
|
|
12154
|
+
"message",
|
|
12155
|
+
"FLOW.QUERY diagnostic",
|
|
12156
|
+
DIAGNOSTIC_TEXT_BYTES
|
|
12157
|
+
),
|
|
12158
|
+
detail: optionalDiagnosticText(mapping, "detail"),
|
|
12159
|
+
hint: optionalDiagnosticText(mapping, "hint"),
|
|
12176
12160
|
retryable: requiredBoolean(mapping, "retryable", "FLOW.QUERY diagnostic"),
|
|
12177
12161
|
safeToRetry: requiredBoolean(mapping, "safe_to_retry", "FLOW.QUERY diagnostic"),
|
|
12178
12162
|
retryAfterMs: nonNegativeInteger(
|
|
@@ -12189,49 +12173,724 @@ function tryDecodeFlowQueryError(value, cause) {
|
|
|
12189
12173
|
throw error;
|
|
12190
12174
|
}
|
|
12191
12175
|
}
|
|
12192
|
-
function
|
|
12193
|
-
const
|
|
12194
|
-
|
|
12176
|
+
function optionalDiagnosticText(mapping, name) {
|
|
12177
|
+
const value = optionalText2(mapping, name, "FLOW.QUERY diagnostic");
|
|
12178
|
+
if (value != null && Buffer46.byteLength(value, "utf8") > DIAGNOSTIC_TEXT_BYTES) {
|
|
12179
|
+
throw decodeError(
|
|
12180
|
+
`FLOW.QUERY diagnostic ${name} exceeds ${DIAGNOSTIC_TEXT_BYTES} bytes`,
|
|
12181
|
+
mapping
|
|
12182
|
+
);
|
|
12183
|
+
}
|
|
12184
|
+
return value;
|
|
12185
|
+
}
|
|
12186
|
+
function decodeDiagnosticContext(value) {
|
|
12187
|
+
if (value == null) return void 0;
|
|
12188
|
+
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic context");
|
|
12189
|
+
const size = mapping instanceof Map ? mapping.size : Object.keys(mapping).length;
|
|
12190
|
+
if (size > DIAGNOSTIC_CONTEXT_ENTRIES) {
|
|
12191
|
+
throw decodeError("FLOW.QUERY diagnostic context contains too many entries", value);
|
|
12192
|
+
}
|
|
12193
|
+
validateDiagnosticContextValue(
|
|
12195
12194
|
mapping,
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
"FLOW.QUERY.INDEXES"
|
|
12199
|
-
);
|
|
12200
|
-
const registry = requiredMap2(field(mapping, "registry"), "FLOW.QUERY.INDEXES registry");
|
|
12201
|
-
const services = freezeMetadataMap(
|
|
12202
|
-
requiredMap2(field(mapping, "services"), "FLOW.QUERY.INDEXES services"),
|
|
12203
|
-
"FLOW.QUERY.INDEXES services"
|
|
12195
|
+
DIAGNOSTIC_CONTEXT_DEPTH,
|
|
12196
|
+
{ remaining: DIAGNOSTIC_CONTEXT_NODES }
|
|
12204
12197
|
);
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12198
|
+
return freezeMetadataMap(mapping, "FLOW.QUERY diagnostic context");
|
|
12199
|
+
}
|
|
12200
|
+
function validateDiagnosticContextValue(value, depth, budget) {
|
|
12201
|
+
consumeDiagnosticContextNode(value, budget);
|
|
12202
|
+
if (value == null || typeof value === "boolean") return;
|
|
12203
|
+
if (typeof value === "number") {
|
|
12204
|
+
if (Number.isSafeInteger(value)) return;
|
|
12205
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid integer", value);
|
|
12208
12206
|
}
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
throw decodeError("FLOW.QUERY.INDEXES indexes must be a dense array", value);
|
|
12213
|
-
}
|
|
12214
|
-
indexes[index] = decodeIndex(rawIndexes[index], index);
|
|
12207
|
+
if (typeof value === "bigint") {
|
|
12208
|
+
if (value >= MIN_SIGNED_64 && value <= MAX_SIGNED_642) return;
|
|
12209
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid integer", value);
|
|
12215
12210
|
}
|
|
12216
|
-
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
|
|
12211
|
+
const text3 = diagnosticContextText(value);
|
|
12212
|
+
if (text3 != null) {
|
|
12213
|
+
if (Buffer46.byteLength(text3, "utf8") <= DIAGNOSTIC_TEXT_BYTES) return;
|
|
12214
|
+
throw decodeError("FLOW.QUERY diagnostic context contains oversized text", value);
|
|
12215
|
+
}
|
|
12216
|
+
if (depth <= 0) {
|
|
12217
|
+
throw decodeError("FLOW.QUERY diagnostic context exceeds its maximum depth", value);
|
|
12218
|
+
}
|
|
12219
|
+
if (Array.isArray(value)) {
|
|
12220
|
+
if (value.length > DIAGNOSTIC_CONTEXT_LIST_ITEMS) {
|
|
12221
|
+
throw decodeError("FLOW.QUERY diagnostic context list is too large", value);
|
|
12222
|
+
}
|
|
12223
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12224
|
+
if (!Object.hasOwn(value, index)) {
|
|
12225
|
+
throw decodeError("FLOW.QUERY diagnostic context list must be dense", value);
|
|
12226
|
+
}
|
|
12227
|
+
validateDiagnosticContextValue(value[index], depth - 1, budget);
|
|
12228
|
+
}
|
|
12229
|
+
return;
|
|
12230
|
+
}
|
|
12231
|
+
if (value instanceof Map || isDiagnosticContextRecord(value)) {
|
|
12232
|
+
const entries = value instanceof Map ? value.entries() : Object.entries(value);
|
|
12233
|
+
const size = value instanceof Map ? value.size : Object.keys(value).length;
|
|
12234
|
+
if (size > DIAGNOSTIC_CONTEXT_ENTRIES) {
|
|
12235
|
+
throw decodeError("FLOW.QUERY diagnostic context map is too large", value);
|
|
12236
|
+
}
|
|
12237
|
+
for (const [rawKey, item] of entries) {
|
|
12238
|
+
const key = diagnosticContextText(rawKey);
|
|
12239
|
+
if (key == null || key.length === 0 || Buffer46.byteLength(key, "utf8") > DIAGNOSTIC_CONTEXT_KEY_BYTES) {
|
|
12240
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an invalid key", value);
|
|
12241
|
+
}
|
|
12242
|
+
validateDiagnosticContextValue(item, depth - 1, budget);
|
|
12243
|
+
}
|
|
12244
|
+
return;
|
|
12245
|
+
}
|
|
12246
|
+
throw decodeError("FLOW.QUERY diagnostic context contains an unsupported value", value);
|
|
12247
|
+
}
|
|
12248
|
+
function consumeDiagnosticContextNode(value, budget) {
|
|
12249
|
+
if (budget.remaining <= 0) {
|
|
12250
|
+
throw decodeError("FLOW.QUERY diagnostic context exceeds its node limit", value);
|
|
12251
|
+
}
|
|
12252
|
+
budget.remaining -= 1;
|
|
12253
|
+
}
|
|
12254
|
+
function diagnosticContextText(value) {
|
|
12255
|
+
if (typeof value === "string") return value.isWellFormed() ? value : void 0;
|
|
12256
|
+
if (!Buffer46.isBuffer(value) && !(value instanceof Uint8Array)) return void 0;
|
|
12257
|
+
try {
|
|
12258
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
12259
|
+
} catch {
|
|
12260
|
+
return void 0;
|
|
12261
|
+
}
|
|
12262
|
+
}
|
|
12263
|
+
function isDiagnosticContextRecord(value) {
|
|
12264
|
+
if (typeof value !== "object" || value == null) return false;
|
|
12265
|
+
const prototype = Object.getPrototypeOf(value);
|
|
12266
|
+
return prototype === Object.prototype || prototype === null;
|
|
12267
|
+
}
|
|
12268
|
+
function decodePosition(value) {
|
|
12269
|
+
if (value == null) return void 0;
|
|
12270
|
+
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic position");
|
|
12271
|
+
return Object.freeze({
|
|
12272
|
+
byte: positiveInteger(field(mapping, "byte"), "FLOW.QUERY diagnostic position byte"),
|
|
12273
|
+
line: positiveInteger(field(mapping, "line"), "FLOW.QUERY diagnostic position line"),
|
|
12274
|
+
column: positiveInteger(
|
|
12275
|
+
field(mapping, "column"),
|
|
12276
|
+
"FLOW.QUERY diagnostic position column"
|
|
12277
|
+
)
|
|
12278
|
+
});
|
|
12279
|
+
}
|
|
12280
|
+
|
|
12281
|
+
// src/flow-query-index-contract.ts
|
|
12282
|
+
import { Buffer as Buffer47 } from "buffer";
|
|
12283
|
+
var FLOW_QUERY_BUILD_PHASES = ["pending", "snapshot", "backfill", "done"];
|
|
12284
|
+
var FLOW_QUERY_VALIDATION_PHASES = [
|
|
12285
|
+
"pending",
|
|
12286
|
+
"source",
|
|
12287
|
+
"index",
|
|
12288
|
+
"counter",
|
|
12289
|
+
"cleanup",
|
|
12290
|
+
"done"
|
|
12291
|
+
];
|
|
12292
|
+
var FLOW_QUERY_RETIREMENT_PHASES = [
|
|
12293
|
+
"pending",
|
|
12294
|
+
"fence",
|
|
12295
|
+
"index",
|
|
12296
|
+
"counter",
|
|
12297
|
+
"reverse",
|
|
12298
|
+
"cleanup",
|
|
12299
|
+
"done"
|
|
12300
|
+
];
|
|
12301
|
+
var IDENTIFIER = /^[A-Za-z0-9_.:-]+$/u;
|
|
12302
|
+
var UNQUOTED_METADATA = /^[A-Za-z0-9_-]+$/u;
|
|
12303
|
+
var ATTRIBUTE_SELECTOR = /^attribute\['((?:[^']|'')*)'\]$/u;
|
|
12304
|
+
var STATE_META_SELECTOR = /^state_meta\['((?:[^']|'')*)'\]\['((?:[^']|'')*)'\]$/u;
|
|
12305
|
+
var INTEGER_FIELDS = /* @__PURE__ */ new Set([
|
|
12306
|
+
"version",
|
|
12307
|
+
"priority",
|
|
12308
|
+
"created_at_ms",
|
|
12309
|
+
"updated_at_ms",
|
|
12310
|
+
"next_run_at_ms",
|
|
12311
|
+
"lease_deadline_ms",
|
|
12312
|
+
"attempts",
|
|
12313
|
+
"max_active_ms"
|
|
12314
|
+
]);
|
|
12315
|
+
var BUILTIN_FIELDS = /* @__PURE__ */ new Set([
|
|
12316
|
+
...INTEGER_FIELDS,
|
|
12317
|
+
"partition_key",
|
|
12318
|
+
"run_id",
|
|
12319
|
+
"event_id",
|
|
12320
|
+
"type",
|
|
12321
|
+
"state",
|
|
12322
|
+
"run_state",
|
|
12323
|
+
"parent_flow_id",
|
|
12324
|
+
"root_flow_id",
|
|
12325
|
+
"correlation_id"
|
|
12326
|
+
]);
|
|
12327
|
+
var RETIREMENT_PROGRESS_FIELDS = [
|
|
12328
|
+
"phase_counts",
|
|
12329
|
+
"current_phases",
|
|
12330
|
+
"completed_shards",
|
|
12331
|
+
"total_shards",
|
|
12332
|
+
"deleted_entries",
|
|
12333
|
+
"deleted_bytes",
|
|
12334
|
+
"rewritten_reverse_rows"
|
|
12335
|
+
];
|
|
12336
|
+
function validateFlowQueryIndexContract(status, expectedId) {
|
|
12337
|
+
let previousId;
|
|
12338
|
+
let previousVersion;
|
|
12339
|
+
for (const index of status.indexes) {
|
|
12340
|
+
const version = BigInt(index.version);
|
|
12341
|
+
if (previousId != null && (index.id < previousId || index.id === previousId && previousVersion != null && version <= previousVersion)) {
|
|
12342
|
+
fail("indexes must be uniquely sorted by id and version", status.raw);
|
|
12343
|
+
}
|
|
12344
|
+
if (expectedId != null && index.id !== expectedId) {
|
|
12345
|
+
fail("filtered indexes do not match the requested id", status.raw);
|
|
12346
|
+
}
|
|
12347
|
+
previousId = index.id;
|
|
12348
|
+
previousVersion = version;
|
|
12349
|
+
validateIndex(index, status);
|
|
12350
|
+
}
|
|
12351
|
+
if (expectedId != null && status.indexes.length === 0) {
|
|
12352
|
+
fail("filtered indexes do not match the requested id", status.raw);
|
|
12353
|
+
}
|
|
12354
|
+
const hasUnavailableStatistics = status.indexes.some(
|
|
12355
|
+
(index) => index.statistics.status === "unavailable"
|
|
12356
|
+
);
|
|
12357
|
+
if (status.services.statisticsStore === "unavailable") {
|
|
12358
|
+
if (status.indexes.some((index) => index.statistics.status !== "unavailable")) {
|
|
12359
|
+
fail("statistics must be unavailable when the service is unavailable", status.raw);
|
|
12360
|
+
}
|
|
12361
|
+
} else if (hasUnavailableStatistics) {
|
|
12362
|
+
fail("statistics cannot be unavailable while the service is ready", status.raw);
|
|
12363
|
+
}
|
|
12364
|
+
}
|
|
12365
|
+
function validateIndex(index, status) {
|
|
12366
|
+
if (!IDENTIFIER.test(index.id) || index.workloads.some((workload) => !IDENTIFIER.test(workload))) {
|
|
12367
|
+
fail("index identity contains invalid characters", index.raw);
|
|
12368
|
+
}
|
|
12369
|
+
const first = index.fields[0];
|
|
12370
|
+
if (first?.name !== "partition_key" || first.direction !== "asc" || first.encoding !== "hashed") {
|
|
12371
|
+
fail("index must begin with partition_key asc hashed", index.raw);
|
|
12372
|
+
}
|
|
12373
|
+
let attributeFields = 0;
|
|
12374
|
+
for (const indexField of index.fields) {
|
|
12375
|
+
if (indexField.encoding === "hashed" && indexField.direction !== "asc") {
|
|
12376
|
+
fail("hashed index fields must be ascending", index.raw);
|
|
12377
|
+
}
|
|
12378
|
+
const kind = fieldKind(indexField.name);
|
|
12379
|
+
if (kind == null) fail("index contains an unsupported field selector", index.raw);
|
|
12380
|
+
if (indexField.encoding === "ordered" && kind !== "integer") {
|
|
12381
|
+
fail("ordered index fields must be integers", index.raw);
|
|
12382
|
+
}
|
|
12383
|
+
if (kind === "attribute") attributeFields += 1;
|
|
12384
|
+
}
|
|
12385
|
+
if (attributeFields > 1) fail("index may contain at most one attribute field", index.raw);
|
|
12386
|
+
for (const prefix of index.countPrefixes) {
|
|
12387
|
+
if (index.fields.slice(0, prefix).some((field3) => field3.encoding !== "hashed")) {
|
|
12388
|
+
fail("count prefixes may cover only hashed fields", index.raw);
|
|
12389
|
+
}
|
|
12390
|
+
}
|
|
12391
|
+
if (index.coveringFields.length > 0) {
|
|
12392
|
+
if (index.coveringFields.some((field3) => fieldKind(field3) == null)) {
|
|
12393
|
+
fail("index contains an unsupported covering field selector", index.raw);
|
|
12394
|
+
}
|
|
12395
|
+
const required = /* @__PURE__ */ new Set(["run_id", "version", ...index.fields.map((field3) => field3.name)]);
|
|
12396
|
+
if ([...required].some((field3) => !index.coveringFields.includes(field3))) {
|
|
12397
|
+
fail("index covering fields omit an identity or index field", index.raw);
|
|
12398
|
+
}
|
|
12399
|
+
}
|
|
12400
|
+
if (index.countPrefixes.length > 0 !== (index.format.counter != null)) {
|
|
12401
|
+
fail("index counter format is inconsistent with count prefixes", index.raw);
|
|
12402
|
+
}
|
|
12403
|
+
validateProgress(index.build, FLOW_QUERY_BUILD_PHASES, "build");
|
|
12404
|
+
validateProgress(index.validation, FLOW_QUERY_VALIDATION_PHASES, "validation");
|
|
12405
|
+
if (index.retirement.status === "not_applicable") {
|
|
12406
|
+
if (RETIREMENT_PROGRESS_FIELDS.some((name) => hasKey(index.retirement.raw, name))) {
|
|
12407
|
+
fail("not_applicable retirement must not contain progress", index.retirement.raw);
|
|
12408
|
+
}
|
|
12409
|
+
} else {
|
|
12410
|
+
const retirement = index.retirement;
|
|
12411
|
+
if (retirement.phaseCounts == null || retirement.currentPhases == null || retirement.completedShards == null || retirement.totalShards == null) {
|
|
12412
|
+
fail("retirement progress is incomplete", retirement.raw);
|
|
12413
|
+
}
|
|
12414
|
+
validateProgress(
|
|
12415
|
+
{
|
|
12416
|
+
phaseCounts: retirement.phaseCounts,
|
|
12417
|
+
currentPhases: retirement.currentPhases,
|
|
12418
|
+
completedShards: retirement.completedShards,
|
|
12419
|
+
totalShards: retirement.totalShards,
|
|
12420
|
+
raw: retirement.raw
|
|
12421
|
+
},
|
|
12422
|
+
FLOW_QUERY_RETIREMENT_PHASES,
|
|
12423
|
+
"retirement"
|
|
12424
|
+
);
|
|
12425
|
+
}
|
|
12426
|
+
const totals = new Set(
|
|
12427
|
+
[
|
|
12428
|
+
index.coverage.totalShards,
|
|
12429
|
+
index.build.totalShards,
|
|
12430
|
+
index.validation.totalShards,
|
|
12431
|
+
...index.retirement.totalShards == null ? [] : [index.retirement.totalShards]
|
|
12432
|
+
].map(indexInteger)
|
|
12433
|
+
);
|
|
12434
|
+
if (totals.size !== 1) fail("index shard totals are inconsistent", index.raw);
|
|
12435
|
+
if (!sameIndexInteger(index.coverage.completeShards, index.build.completedShards)) {
|
|
12436
|
+
fail("coverage and build completion are inconsistent", index.raw);
|
|
12437
|
+
}
|
|
12438
|
+
if (index.coverage.validation !== index.validation.status) {
|
|
12439
|
+
fail("coverage and validation status are inconsistent", index.raw);
|
|
12440
|
+
}
|
|
12441
|
+
const queryable = index.state === "active" && sameIndexInteger(
|
|
12442
|
+
index.coverage.completeShards,
|
|
12443
|
+
index.coverage.totalShards
|
|
12444
|
+
) && index.coverage.validation === "passed";
|
|
12445
|
+
if (index.queryable !== queryable) fail("index queryable flag is inconsistent", index.raw);
|
|
12446
|
+
validateLifecycle(index);
|
|
12447
|
+
validateValidation(index);
|
|
12448
|
+
validateStatistics(index, status);
|
|
12449
|
+
}
|
|
12450
|
+
function validateProgress(progress, phases, section) {
|
|
12451
|
+
const entries = Object.entries(progress.phaseCounts);
|
|
12452
|
+
if (entries.length === 0 || entries.some(
|
|
12453
|
+
([phase, count]) => !phases.includes(phase) || indexInteger(count) <= 0n
|
|
12454
|
+
) || entries.reduce((sum, [, count]) => sum + indexInteger(count), 0n) !== indexInteger(progress.totalShards)) {
|
|
12455
|
+
fail(`${section} phase_counts are invalid`, progress.raw);
|
|
12456
|
+
}
|
|
12457
|
+
const current = phases.filter((phase) => Object.hasOwn(progress.phaseCounts, phase));
|
|
12458
|
+
if (current.length !== progress.currentPhases.length || current.some((phase, position) => phase !== progress.currentPhases[position])) {
|
|
12459
|
+
fail(`${section} current_phases are inconsistent`, progress.raw);
|
|
12460
|
+
}
|
|
12461
|
+
if (!sameIndexInteger(
|
|
12462
|
+
progress.completedShards,
|
|
12463
|
+
progress.phaseCounts.done ?? 0
|
|
12464
|
+
)) {
|
|
12465
|
+
fail(`${section} completed_shards is inconsistent`, progress.raw);
|
|
12466
|
+
}
|
|
12467
|
+
}
|
|
12468
|
+
function validateLifecycle(index) {
|
|
12469
|
+
const built = sameIndexInteger(
|
|
12470
|
+
index.build.completedShards,
|
|
12471
|
+
index.build.totalShards
|
|
12472
|
+
);
|
|
12473
|
+
const validation = index.validation.status;
|
|
12474
|
+
const retirement = index.retirement.status;
|
|
12475
|
+
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";
|
|
12476
|
+
if (!valid) fail("index lifecycle fields are inconsistent", index.raw);
|
|
12477
|
+
}
|
|
12478
|
+
function validateValidation(index) {
|
|
12479
|
+
const validation = index.validation;
|
|
12480
|
+
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;
|
|
12481
|
+
if (!valid) fail("validation status fields are inconsistent", validation.raw);
|
|
12482
|
+
}
|
|
12483
|
+
function validateStatistics(index, status) {
|
|
12484
|
+
const statistics = index.statistics;
|
|
12485
|
+
const times = [
|
|
12486
|
+
statistics.oldestCollectedAtMs,
|
|
12487
|
+
statistics.newestCollectedAtMs,
|
|
12488
|
+
statistics.oldestAgeMs,
|
|
12489
|
+
statistics.newestAgeMs
|
|
12490
|
+
];
|
|
12491
|
+
if (indexInteger(statistics.samples) === 0n) {
|
|
12492
|
+
if (statistics.status !== "missing" && statistics.status !== "unavailable" || times.some((value) => value != null)) {
|
|
12493
|
+
fail("empty statistics fields are inconsistent", statistics.raw);
|
|
12494
|
+
}
|
|
12495
|
+
return;
|
|
12496
|
+
}
|
|
12497
|
+
if (times.some((value) => value == null)) {
|
|
12498
|
+
fail("sampled statistics require timestamps and ages", statistics.raw);
|
|
12499
|
+
}
|
|
12500
|
+
const [oldest, newest, oldestAge, newestAge] = times;
|
|
12501
|
+
if (indexInteger(oldest) > indexInteger(newest) || indexInteger(oldestAge) !== indexAge(status.observedAtMs, oldest) || indexInteger(newestAge) !== indexAge(status.observedAtMs, newest)) {
|
|
12502
|
+
fail("statistics timestamps or ages are inconsistent", statistics.raw);
|
|
12503
|
+
}
|
|
12504
|
+
const expected = sameIndexInteger(statistics.freshSamples, statistics.samples) ? ["fresh"] : indexInteger(statistics.freshSamples) === 0n ? indexInteger(statistics.futureSamples) > 0n ? ["stale", "future"] : ["stale"] : ["mixed"];
|
|
12505
|
+
if (!expected.includes(statistics.status)) {
|
|
12506
|
+
fail("statistics status does not match sample counters", statistics.raw);
|
|
12507
|
+
}
|
|
12508
|
+
}
|
|
12509
|
+
function fieldKind(name) {
|
|
12510
|
+
if (BUILTIN_FIELDS.has(name)) return INTEGER_FIELDS.has(name) ? "integer" : "keyword";
|
|
12511
|
+
const parts = name.split(".");
|
|
12512
|
+
if (parts.length === 2 && parts[0] === "attribute" && validUnquoted(parts[1] ?? "")) return "attribute";
|
|
12513
|
+
if (parts.length === 3 && parts[0] === "state_meta" && validUnquoted(parts[1] ?? "") && validUnquoted(parts[2] ?? "")) return "state_meta";
|
|
12514
|
+
const attribute = ATTRIBUTE_SELECTOR.exec(name);
|
|
12515
|
+
if (attribute != null) {
|
|
12516
|
+
const metadata = (attribute[1] ?? "").replaceAll("''", "'");
|
|
12517
|
+
if (validMetadata(metadata, true) && name === externalSelector("attribute", metadata)) return "attribute";
|
|
12518
|
+
}
|
|
12519
|
+
const stateMeta = STATE_META_SELECTOR.exec(name);
|
|
12520
|
+
if (stateMeta != null) {
|
|
12521
|
+
const state = (stateMeta[1] ?? "").replaceAll("''", "'");
|
|
12522
|
+
const metadata = (stateMeta[2] ?? "").replaceAll("''", "'");
|
|
12523
|
+
if (validMetadata(state, false) && validMetadata(metadata, true) && name === externalSelector("state_meta", state, metadata)) return "state_meta";
|
|
12524
|
+
}
|
|
12525
|
+
return void 0;
|
|
12526
|
+
}
|
|
12527
|
+
function validUnquoted(value) {
|
|
12528
|
+
return !value.startsWith("__") && UNQUOTED_METADATA.test(value) && Buffer47.byteLength(value, "ascii") <= 64;
|
|
12529
|
+
}
|
|
12530
|
+
function validMetadata(value, rejectReserved) {
|
|
12531
|
+
return value.length > 0 && Buffer47.byteLength(value, "utf8") <= 64 && (!rejectReserved || !value.startsWith("__"));
|
|
12532
|
+
}
|
|
12533
|
+
function externalSelector(root, ...segments) {
|
|
12534
|
+
return segments.every(validUnquoted) ? [root, ...segments].join(".") : root + segments.map((segment) => `['${segment.replaceAll("'", "''")}']`).join("");
|
|
12535
|
+
}
|
|
12536
|
+
function sameIndexInteger(left, right) {
|
|
12537
|
+
return indexInteger(left) === indexInteger(right);
|
|
12538
|
+
}
|
|
12539
|
+
function indexAge(observedAtMs, collectedAtMs) {
|
|
12540
|
+
const age = indexInteger(observedAtMs) - indexInteger(collectedAtMs);
|
|
12541
|
+
return age < 0n ? 0n : age;
|
|
12542
|
+
}
|
|
12543
|
+
function indexInteger(value) {
|
|
12544
|
+
return BigInt(value);
|
|
12545
|
+
}
|
|
12546
|
+
function fail(message, raw) {
|
|
12547
|
+
throw decodeError(`FLOW.QUERY.INDEXES ${message}`, raw);
|
|
12548
|
+
}
|
|
12549
|
+
|
|
12550
|
+
// src/flow-query-index-decode.ts
|
|
12551
|
+
var MAX_UNSIGNED_64 = (1n << 64n) - 1n;
|
|
12552
|
+
function decodeUniqueTextArray(value, context, maximum, maximumBytes) {
|
|
12553
|
+
if (!Array.isArray(value) || value.length > maximum) {
|
|
12554
|
+
throw decodeError(`${context} must be a bounded array`, value);
|
|
12555
|
+
}
|
|
12556
|
+
const result = new Array(value.length);
|
|
12557
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12558
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12559
|
+
if (!Object.hasOwn(value, index)) {
|
|
12560
|
+
throw decodeError(`${context} must be dense`, value);
|
|
12561
|
+
}
|
|
12562
|
+
const text3 = boundedText(
|
|
12563
|
+
value[index],
|
|
12564
|
+
`${context} entry ${index}`,
|
|
12565
|
+
maximumBytes
|
|
12566
|
+
);
|
|
12567
|
+
if (seen.has(text3)) {
|
|
12568
|
+
throw decodeError(`${context} contains duplicates`, value);
|
|
12569
|
+
}
|
|
12570
|
+
seen.add(text3);
|
|
12571
|
+
result[index] = text3;
|
|
12572
|
+
}
|
|
12573
|
+
return Object.freeze(result);
|
|
12574
|
+
}
|
|
12575
|
+
function requiredChoice(mapping, name, context, choices) {
|
|
12576
|
+
const value = requiredBoundedText2(mapping, name, context, 64);
|
|
12577
|
+
if (!choices.includes(value)) {
|
|
12578
|
+
throw decodeError(`${context} ${name} is unsupported`, mapping);
|
|
12579
|
+
}
|
|
12580
|
+
return value;
|
|
12581
|
+
}
|
|
12582
|
+
function optionalBoundedText(mapping, name, context, maximumBytes) {
|
|
12583
|
+
const value = field(mapping, name);
|
|
12584
|
+
if (value == null) return void 0;
|
|
12585
|
+
return boundedText(value, `${context} ${name}`, maximumBytes);
|
|
12586
|
+
}
|
|
12587
|
+
function optionalIndexInteger(mapping, name, context) {
|
|
12588
|
+
const value = field(mapping, name);
|
|
12589
|
+
return value == null ? void 0 : unsignedIndexInteger(value, `${context} ${name}`);
|
|
12590
|
+
}
|
|
12591
|
+
function indexCounter(mapping, name, section) {
|
|
12592
|
+
return unsignedIndexInteger(
|
|
12593
|
+
field(mapping, name),
|
|
12594
|
+
`FLOW.QUERY.INDEXES index ${section} ${name}`
|
|
12595
|
+
);
|
|
12596
|
+
}
|
|
12597
|
+
function unsignedIndexInteger(value, context) {
|
|
12598
|
+
return boundedInteger(value, MAX_UNSIGNED_64, context);
|
|
12599
|
+
}
|
|
12600
|
+
function positiveIndexInteger(value, context) {
|
|
12601
|
+
return positiveBoundedInteger(value, MAX_UNSIGNED_64, context);
|
|
12602
|
+
}
|
|
12603
|
+
function indexInteger2(value) {
|
|
12604
|
+
return BigInt(value);
|
|
12605
|
+
}
|
|
12606
|
+
|
|
12607
|
+
// src/flow-query-index-lifecycle-response.ts
|
|
12608
|
+
function decodeIndexCoverage(value) {
|
|
12609
|
+
const context = "FLOW.QUERY.INDEXES index coverage";
|
|
12610
|
+
const mapping = requiredMap2(value, context);
|
|
12611
|
+
const completeShards = unsignedIndexInteger(
|
|
12612
|
+
field(mapping, "complete_shards"),
|
|
12613
|
+
`${context} complete_shards`
|
|
12614
|
+
);
|
|
12615
|
+
const totalShards = positiveIndexInteger(
|
|
12616
|
+
field(mapping, "total_shards"),
|
|
12617
|
+
`${context} total_shards`
|
|
12618
|
+
);
|
|
12619
|
+
if (indexInteger2(completeShards) > indexInteger2(totalShards)) {
|
|
12620
|
+
throw decodeError(`${context} complete_shards exceeds total_shards`, value);
|
|
12621
|
+
}
|
|
12622
|
+
return Object.freeze({
|
|
12623
|
+
completeShards,
|
|
12624
|
+
totalShards,
|
|
12625
|
+
validation: requiredChoice(mapping, "validation", context, [
|
|
12626
|
+
"pending",
|
|
12627
|
+
"passed",
|
|
12628
|
+
"failed"
|
|
12629
|
+
]),
|
|
12630
|
+
raw: freezeMap(mapping)
|
|
12631
|
+
});
|
|
12632
|
+
}
|
|
12633
|
+
function decodeIndexBuild(value) {
|
|
12634
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES index build");
|
|
12635
|
+
const progress = decodeIndexProgress(
|
|
12636
|
+
mapping,
|
|
12637
|
+
"build",
|
|
12638
|
+
FLOW_QUERY_BUILD_PHASES
|
|
12639
|
+
);
|
|
12640
|
+
return Object.freeze({
|
|
12641
|
+
...progress,
|
|
12642
|
+
scannedRecords: indexCounter(mapping, "scanned_records", "build"),
|
|
12643
|
+
writtenEntries: indexCounter(mapping, "written_entries", "build"),
|
|
12644
|
+
writtenBytes: indexCounter(mapping, "written_bytes", "build")
|
|
12645
|
+
});
|
|
12646
|
+
}
|
|
12647
|
+
function decodeIndexValidation(value) {
|
|
12648
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES index validation");
|
|
12649
|
+
if (!hasKey(mapping, "failure_reason") || !hasKey(mapping, "validated_at_ms")) {
|
|
12650
|
+
throw decodeError(
|
|
12651
|
+
"FLOW.QUERY.INDEXES index validation is missing nullable fields",
|
|
12652
|
+
value
|
|
12653
|
+
);
|
|
12654
|
+
}
|
|
12655
|
+
const progress = decodeIndexProgress(
|
|
12656
|
+
mapping,
|
|
12657
|
+
"validation",
|
|
12658
|
+
FLOW_QUERY_VALIDATION_PHASES
|
|
12659
|
+
);
|
|
12660
|
+
return Object.freeze({
|
|
12661
|
+
...progress,
|
|
12662
|
+
status: requiredChoice(
|
|
12663
|
+
mapping,
|
|
12664
|
+
"status",
|
|
12665
|
+
"FLOW.QUERY.INDEXES index validation",
|
|
12666
|
+
["pending", "passed", "failed"]
|
|
12667
|
+
),
|
|
12668
|
+
checkedRecords: indexCounter(mapping, "checked_records", "validation"),
|
|
12669
|
+
checkedEntries: indexCounter(mapping, "checked_entries", "validation"),
|
|
12670
|
+
mismatches: indexCounter(mapping, "mismatches", "validation"),
|
|
12671
|
+
failureReason: optionalBoundedText(
|
|
12672
|
+
mapping,
|
|
12673
|
+
"failure_reason",
|
|
12674
|
+
"FLOW.QUERY.INDEXES index validation",
|
|
12675
|
+
128
|
|
12676
|
+
),
|
|
12677
|
+
validatedAtMs: optionalIndexInteger(
|
|
12678
|
+
mapping,
|
|
12679
|
+
"validated_at_ms",
|
|
12680
|
+
"FLOW.QUERY.INDEXES index validation"
|
|
12681
|
+
)
|
|
12682
|
+
});
|
|
12683
|
+
}
|
|
12684
|
+
function decodeIndexRetirement(value) {
|
|
12685
|
+
const context = "FLOW.QUERY.INDEXES index retirement";
|
|
12686
|
+
const mapping = requiredMap2(value, context);
|
|
12687
|
+
const status = requiredChoice(mapping, "status", context, [
|
|
12688
|
+
"not_applicable",
|
|
12689
|
+
"pending",
|
|
12690
|
+
"complete"
|
|
12691
|
+
]);
|
|
12692
|
+
if (status === "not_applicable") {
|
|
12693
|
+
return Object.freeze({ status, raw: freezeMap(mapping) });
|
|
12694
|
+
}
|
|
12695
|
+
const completedShards = unsignedIndexInteger(
|
|
12696
|
+
field(mapping, "completed_shards"),
|
|
12697
|
+
`${context} completed_shards`
|
|
12698
|
+
);
|
|
12699
|
+
const totalShards = positiveIndexInteger(
|
|
12700
|
+
field(mapping, "total_shards"),
|
|
12701
|
+
`${context} total_shards`
|
|
12702
|
+
);
|
|
12703
|
+
if (indexInteger2(completedShards) > indexInteger2(totalShards)) {
|
|
12704
|
+
throw decodeError(
|
|
12705
|
+
`${context} completed_shards exceeds total_shards`,
|
|
12706
|
+
mapping
|
|
12707
|
+
);
|
|
12708
|
+
}
|
|
12709
|
+
return Object.freeze({
|
|
12710
|
+
status,
|
|
12711
|
+
phaseCounts: decodePhaseCounts(
|
|
12712
|
+
field(mapping, "phase_counts"),
|
|
12713
|
+
"retirement"
|
|
12714
|
+
),
|
|
12715
|
+
currentPhases: decodeAllowedPhases(
|
|
12716
|
+
field(mapping, "current_phases"),
|
|
12717
|
+
"retirement",
|
|
12718
|
+
FLOW_QUERY_RETIREMENT_PHASES
|
|
12719
|
+
),
|
|
12720
|
+
completedShards,
|
|
12721
|
+
totalShards,
|
|
12722
|
+
deletedEntries: indexCounter(mapping, "deleted_entries", "retirement"),
|
|
12723
|
+
deletedBytes: indexCounter(mapping, "deleted_bytes", "retirement"),
|
|
12724
|
+
rewrittenReverseRows: indexCounter(
|
|
12725
|
+
mapping,
|
|
12726
|
+
"rewritten_reverse_rows",
|
|
12727
|
+
"retirement"
|
|
12728
|
+
),
|
|
12729
|
+
raw: freezeMap(mapping)
|
|
12730
|
+
});
|
|
12731
|
+
}
|
|
12732
|
+
function decodeIndexStatistics(value) {
|
|
12733
|
+
const context = "FLOW.QUERY.INDEXES index statistics";
|
|
12734
|
+
const mapping = requiredMap2(value, context);
|
|
12735
|
+
for (const name of [
|
|
12736
|
+
"oldest_collected_at_ms",
|
|
12737
|
+
"newest_collected_at_ms",
|
|
12738
|
+
"oldest_age_ms",
|
|
12739
|
+
"newest_age_ms"
|
|
12740
|
+
]) {
|
|
12741
|
+
if (!hasKey(mapping, name)) {
|
|
12742
|
+
throw decodeError(
|
|
12743
|
+
`${context} is missing required nullable fields`,
|
|
12744
|
+
value
|
|
12745
|
+
);
|
|
12746
|
+
}
|
|
12747
|
+
}
|
|
12748
|
+
const samples = indexCounter(mapping, "samples", "statistics");
|
|
12749
|
+
const freshSamples = indexCounter(mapping, "fresh_samples", "statistics");
|
|
12750
|
+
const staleSamples = indexCounter(mapping, "stale_samples", "statistics");
|
|
12751
|
+
const futureSamples = indexCounter(mapping, "future_samples", "statistics");
|
|
12752
|
+
if (indexInteger2(freshSamples) + indexInteger2(staleSamples) !== indexInteger2(samples) || indexInteger2(futureSamples) > indexInteger2(staleSamples)) {
|
|
12753
|
+
throw decodeError(`${context} counters are inconsistent`, value);
|
|
12754
|
+
}
|
|
12755
|
+
return Object.freeze({
|
|
12756
|
+
status: requiredChoice(mapping, "status", context, [
|
|
12757
|
+
"fresh",
|
|
12758
|
+
"stale",
|
|
12759
|
+
"future",
|
|
12760
|
+
"mixed",
|
|
12761
|
+
"missing",
|
|
12762
|
+
"unavailable"
|
|
12763
|
+
]),
|
|
12764
|
+
samples,
|
|
12765
|
+
freshSamples,
|
|
12766
|
+
staleSamples,
|
|
12767
|
+
futureSamples,
|
|
12768
|
+
oldestCollectedAtMs: optionalIndexInteger(
|
|
12769
|
+
mapping,
|
|
12770
|
+
"oldest_collected_at_ms",
|
|
12771
|
+
context
|
|
12772
|
+
),
|
|
12773
|
+
newestCollectedAtMs: optionalIndexInteger(
|
|
12774
|
+
mapping,
|
|
12775
|
+
"newest_collected_at_ms",
|
|
12776
|
+
context
|
|
12777
|
+
),
|
|
12778
|
+
oldestAgeMs: optionalIndexInteger(mapping, "oldest_age_ms", context),
|
|
12779
|
+
newestAgeMs: optionalIndexInteger(mapping, "newest_age_ms", context),
|
|
12780
|
+
raw: freezeMap(mapping)
|
|
12781
|
+
});
|
|
12782
|
+
}
|
|
12783
|
+
function decodeIndexProgress(mapping, section, allowedPhases) {
|
|
12784
|
+
const context = `FLOW.QUERY.INDEXES index ${section}`;
|
|
12785
|
+
const completedShards = unsignedIndexInteger(
|
|
12786
|
+
field(mapping, "completed_shards"),
|
|
12787
|
+
`${context} completed_shards`
|
|
12788
|
+
);
|
|
12789
|
+
const totalShards = positiveIndexInteger(
|
|
12790
|
+
field(mapping, "total_shards"),
|
|
12791
|
+
`${context} total_shards`
|
|
12792
|
+
);
|
|
12793
|
+
if (indexInteger2(completedShards) > indexInteger2(totalShards)) {
|
|
12794
|
+
throw decodeError(
|
|
12795
|
+
`${context} completed_shards exceeds total_shards`,
|
|
12796
|
+
mapping
|
|
12797
|
+
);
|
|
12798
|
+
}
|
|
12799
|
+
return Object.freeze({
|
|
12800
|
+
scope: requiredChoice(mapping, "scope", context, ["catalog_build"]),
|
|
12801
|
+
phaseCounts: decodePhaseCounts(field(mapping, "phase_counts"), section),
|
|
12802
|
+
currentPhases: decodeAllowedPhases(
|
|
12803
|
+
field(mapping, "current_phases"),
|
|
12804
|
+
section,
|
|
12805
|
+
allowedPhases
|
|
12806
|
+
),
|
|
12807
|
+
completedShards,
|
|
12808
|
+
totalShards,
|
|
12809
|
+
raw: freezeMap(mapping)
|
|
12810
|
+
});
|
|
12811
|
+
}
|
|
12812
|
+
function decodePhaseCounts(value, section) {
|
|
12813
|
+
const context = `FLOW.QUERY.INDEXES index ${section} phase_counts`;
|
|
12814
|
+
const mapping = requiredMap2(value, context);
|
|
12815
|
+
const entries = mapping instanceof Map ? [...mapping.entries()] : Object.entries(mapping);
|
|
12816
|
+
if (entries.length > 16) {
|
|
12817
|
+
throw decodeError(`${context} contains too many entries`, value);
|
|
12818
|
+
}
|
|
12819
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
12820
|
+
for (const [rawPhase, rawCount] of entries) {
|
|
12821
|
+
const phase = boundedText(rawPhase, `${context} phase`, 64);
|
|
12822
|
+
if (Object.hasOwn(result, phase)) {
|
|
12823
|
+
throw decodeError(`${context} contains duplicate phases`, value);
|
|
12824
|
+
}
|
|
12825
|
+
result[phase] = unsignedIndexInteger(rawCount, `${context} ${phase}`);
|
|
12826
|
+
}
|
|
12827
|
+
return Object.freeze(result);
|
|
12828
|
+
}
|
|
12829
|
+
function decodeAllowedPhases(value, section, allowed) {
|
|
12830
|
+
const phases = decodeUniqueTextArray(
|
|
12831
|
+
value,
|
|
12832
|
+
`FLOW.QUERY.INDEXES index ${section} current_phases`,
|
|
12833
|
+
allowed.length,
|
|
12834
|
+
64
|
|
12835
|
+
);
|
|
12836
|
+
if (phases.some((phase) => !allowed.includes(phase))) {
|
|
12837
|
+
throw decodeError(
|
|
12838
|
+
`FLOW.QUERY.INDEXES index ${section} current_phases are invalid`,
|
|
12839
|
+
value
|
|
12840
|
+
);
|
|
12841
|
+
}
|
|
12842
|
+
return phases;
|
|
12843
|
+
}
|
|
12844
|
+
|
|
12845
|
+
// src/flow-query-index-response.ts
|
|
12846
|
+
var FLOW_QUERY_INDEXES_CONTRACT = "ferric.flow.query.indexes/v1";
|
|
12847
|
+
function decodeFlowQueryIndexStatus(value, expectedId) {
|
|
12848
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES");
|
|
12849
|
+
requireContract(
|
|
12850
|
+
mapping,
|
|
12851
|
+
"contract_version",
|
|
12852
|
+
FLOW_QUERY_INDEXES_CONTRACT,
|
|
12853
|
+
"FLOW.QUERY.INDEXES"
|
|
12854
|
+
);
|
|
12855
|
+
const registry = requiredMap2(
|
|
12856
|
+
field(mapping, "registry"),
|
|
12857
|
+
"FLOW.QUERY.INDEXES registry"
|
|
12858
|
+
);
|
|
12859
|
+
const services = decodeIndexServices(field(mapping, "services"));
|
|
12860
|
+
const rawIndexes = field(mapping, "indexes");
|
|
12861
|
+
if (!Array.isArray(rawIndexes) || rawIndexes.length > 32) {
|
|
12862
|
+
throw decodeError(
|
|
12863
|
+
"FLOW.QUERY.INDEXES indexes must contain at most 32 entries",
|
|
12864
|
+
value
|
|
12865
|
+
);
|
|
12866
|
+
}
|
|
12867
|
+
const indexes = new Array(rawIndexes.length);
|
|
12868
|
+
for (let index = 0; index < rawIndexes.length; index += 1) {
|
|
12869
|
+
if (!Object.hasOwn(rawIndexes, index)) {
|
|
12870
|
+
throw decodeError(
|
|
12871
|
+
"FLOW.QUERY.INDEXES indexes must be a dense array",
|
|
12872
|
+
value
|
|
12873
|
+
);
|
|
12874
|
+
}
|
|
12875
|
+
indexes[index] = decodeIndex(rawIndexes[index], index);
|
|
12876
|
+
}
|
|
12877
|
+
const status = Object.freeze({
|
|
12878
|
+
contractVersion: FLOW_QUERY_INDEXES_CONTRACT,
|
|
12879
|
+
observedAtMs: unsignedIndexInteger(
|
|
12880
|
+
field(mapping, "observed_at_ms"),
|
|
12881
|
+
"FLOW.QUERY.INDEXES observed_at_ms"
|
|
12221
12882
|
),
|
|
12222
|
-
statisticsMaxAgeMs:
|
|
12883
|
+
statisticsMaxAgeMs: unsignedIndexInteger(
|
|
12223
12884
|
field(mapping, "statistics_max_age_ms"),
|
|
12224
12885
|
"FLOW.QUERY.INDEXES statistics_max_age_ms"
|
|
12225
12886
|
),
|
|
12226
12887
|
registry: Object.freeze({
|
|
12227
|
-
epoch:
|
|
12888
|
+
epoch: unsignedIndexInteger(
|
|
12228
12889
|
field(registry, "epoch"),
|
|
12229
|
-
MAX_UNSIGNED_64,
|
|
12230
12890
|
"FLOW.QUERY.INDEXES epoch"
|
|
12231
12891
|
),
|
|
12232
|
-
catalogVersion:
|
|
12892
|
+
catalogVersion: positiveIndexInteger(
|
|
12233
12893
|
field(registry, "catalog_version"),
|
|
12234
|
-
MAX_UNSIGNED_64,
|
|
12235
12894
|
"FLOW.QUERY.INDEXES catalog_version"
|
|
12236
12895
|
)
|
|
12237
12896
|
}),
|
|
@@ -12239,24 +12898,155 @@ function decodeFlowQueryIndexStatus(value) {
|
|
|
12239
12898
|
indexes: Object.freeze(indexes),
|
|
12240
12899
|
raw: freezeMap(mapping)
|
|
12241
12900
|
});
|
|
12901
|
+
validateFlowQueryIndexContract(status, expectedId);
|
|
12902
|
+
return status;
|
|
12242
12903
|
}
|
|
12243
12904
|
function decodeIndex(value, index) {
|
|
12244
12905
|
const mapping = requiredMap2(value, `FLOW.QUERY.INDEXES index ${index}`);
|
|
12906
|
+
const fields = decodeIndexFields(field(mapping, "fields"));
|
|
12245
12907
|
return Object.freeze({
|
|
12246
|
-
id:
|
|
12247
|
-
version:
|
|
12908
|
+
id: requiredBoundedText2(mapping, "id", "FLOW.QUERY.INDEXES index", 64),
|
|
12909
|
+
version: positiveIndexInteger(
|
|
12248
12910
|
field(mapping, "version"),
|
|
12249
|
-
MAX_UNSIGNED_64,
|
|
12250
12911
|
"FLOW.QUERY.INDEXES index version"
|
|
12251
12912
|
),
|
|
12252
|
-
buildId:
|
|
12253
|
-
|
|
12254
|
-
|
|
12913
|
+
buildId: requiredBoundedText2(
|
|
12914
|
+
mapping,
|
|
12915
|
+
"build_id",
|
|
12916
|
+
"FLOW.QUERY.INDEXES index",
|
|
12917
|
+
128
|
|
12918
|
+
),
|
|
12919
|
+
source: requiredChoice(mapping, "source", "FLOW.QUERY.INDEXES index", [
|
|
12920
|
+
"runs"
|
|
12921
|
+
]),
|
|
12922
|
+
state: requiredChoice(mapping, "state", "FLOW.QUERY.INDEXES index", [
|
|
12923
|
+
"building",
|
|
12924
|
+
"validating",
|
|
12925
|
+
"active",
|
|
12926
|
+
"retiring",
|
|
12927
|
+
"failed"
|
|
12928
|
+
]),
|
|
12929
|
+
queryable: requiredBoolean(
|
|
12930
|
+
mapping,
|
|
12931
|
+
"queryable",
|
|
12932
|
+
"FLOW.QUERY.INDEXES index"
|
|
12933
|
+
),
|
|
12934
|
+
fields,
|
|
12935
|
+
workloads: decodeUniqueTextArray(
|
|
12936
|
+
field(mapping, "workloads"),
|
|
12937
|
+
"FLOW.QUERY.INDEXES index workloads",
|
|
12938
|
+
16,
|
|
12939
|
+
64
|
|
12940
|
+
),
|
|
12941
|
+
countPrefixes: decodeCountPrefixes(
|
|
12942
|
+
field(mapping, "count_prefixes"),
|
|
12943
|
+
fields.length
|
|
12944
|
+
),
|
|
12255
12945
|
coveringFields: decodeCoveringFields(mapping),
|
|
12256
12946
|
format: decodeIndexFormat(mapping),
|
|
12947
|
+
coverage: decodeIndexCoverage(field(mapping, "coverage")),
|
|
12948
|
+
build: decodeIndexBuild(field(mapping, "build")),
|
|
12949
|
+
validation: decodeIndexValidation(field(mapping, "validation")),
|
|
12950
|
+
retirement: decodeIndexRetirement(field(mapping, "retirement")),
|
|
12951
|
+
statistics: decodeIndexStatistics(field(mapping, "statistics")),
|
|
12952
|
+
raw: freezeMap(mapping)
|
|
12953
|
+
});
|
|
12954
|
+
}
|
|
12955
|
+
function decodeIndexServices(value) {
|
|
12956
|
+
const mapping = requiredMap2(value, "FLOW.QUERY.INDEXES services");
|
|
12957
|
+
const choices = ["ready", "unavailable"];
|
|
12958
|
+
return Object.freeze({
|
|
12959
|
+
registry: requiredChoice(
|
|
12960
|
+
mapping,
|
|
12961
|
+
"registry",
|
|
12962
|
+
"FLOW.QUERY.INDEXES services",
|
|
12963
|
+
choices
|
|
12964
|
+
),
|
|
12965
|
+
lifecycleWorker: requiredChoice(
|
|
12966
|
+
mapping,
|
|
12967
|
+
"lifecycle_worker",
|
|
12968
|
+
"FLOW.QUERY.INDEXES services",
|
|
12969
|
+
choices
|
|
12970
|
+
),
|
|
12971
|
+
statisticsStore: requiredChoice(
|
|
12972
|
+
mapping,
|
|
12973
|
+
"statistics_store",
|
|
12974
|
+
"FLOW.QUERY.INDEXES services",
|
|
12975
|
+
choices
|
|
12976
|
+
),
|
|
12977
|
+
statisticsWorker: requiredChoice(
|
|
12978
|
+
mapping,
|
|
12979
|
+
"statistics_worker",
|
|
12980
|
+
"FLOW.QUERY.INDEXES services",
|
|
12981
|
+
choices
|
|
12982
|
+
),
|
|
12257
12983
|
raw: freezeMap(mapping)
|
|
12258
12984
|
});
|
|
12259
12985
|
}
|
|
12986
|
+
function decodeIndexFields(value) {
|
|
12987
|
+
const context = "FLOW.QUERY.INDEXES index fields";
|
|
12988
|
+
if (!Array.isArray(value) || value.length < 2 || value.length > 8) {
|
|
12989
|
+
throw decodeError(`${context} must contain 2 to 8 entries`, value);
|
|
12990
|
+
}
|
|
12991
|
+
const fields = new Array(value.length);
|
|
12992
|
+
const names = /* @__PURE__ */ new Set();
|
|
12993
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
12994
|
+
if (!Object.hasOwn(value, index)) {
|
|
12995
|
+
throw decodeError(`${context} must be dense`, value);
|
|
12996
|
+
}
|
|
12997
|
+
const mapping = requiredMap2(
|
|
12998
|
+
value[index],
|
|
12999
|
+
`FLOW.QUERY.INDEXES index field ${index}`
|
|
13000
|
+
);
|
|
13001
|
+
const name = requiredBoundedText2(
|
|
13002
|
+
mapping,
|
|
13003
|
+
"name",
|
|
13004
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13005
|
+
512
|
|
13006
|
+
);
|
|
13007
|
+
if (names.has(name)) {
|
|
13008
|
+
throw decodeError(`${context} contain duplicates`, value);
|
|
13009
|
+
}
|
|
13010
|
+
names.add(name);
|
|
13011
|
+
fields[index] = Object.freeze({
|
|
13012
|
+
name,
|
|
13013
|
+
direction: requiredChoice(
|
|
13014
|
+
mapping,
|
|
13015
|
+
"direction",
|
|
13016
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13017
|
+
["asc", "desc"]
|
|
13018
|
+
),
|
|
13019
|
+
encoding: requiredChoice(
|
|
13020
|
+
mapping,
|
|
13021
|
+
"encoding",
|
|
13022
|
+
"FLOW.QUERY.INDEXES index field",
|
|
13023
|
+
["hashed", "ordered"]
|
|
13024
|
+
),
|
|
13025
|
+
raw: freezeMap(mapping)
|
|
13026
|
+
});
|
|
13027
|
+
}
|
|
13028
|
+
return Object.freeze(fields);
|
|
13029
|
+
}
|
|
13030
|
+
function decodeCountPrefixes(value, fieldCount) {
|
|
13031
|
+
const context = "FLOW.QUERY.INDEXES index count_prefixes";
|
|
13032
|
+
if (!Array.isArray(value) || value.length > fieldCount) {
|
|
13033
|
+
throw decodeError(`${context} are invalid`, value);
|
|
13034
|
+
}
|
|
13035
|
+
const prefixes = new Array(value.length);
|
|
13036
|
+
let previous = 0;
|
|
13037
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13038
|
+
if (!Object.hasOwn(value, index)) {
|
|
13039
|
+
throw decodeError(`${context} must be dense`, value);
|
|
13040
|
+
}
|
|
13041
|
+
const prefix = positiveInteger(value[index], `${context} entry`);
|
|
13042
|
+
if (prefix > fieldCount || prefix <= previous) {
|
|
13043
|
+
throw decodeError(`${context} are invalid`, value);
|
|
13044
|
+
}
|
|
13045
|
+
prefixes[index] = prefix;
|
|
13046
|
+
previous = prefix;
|
|
13047
|
+
}
|
|
13048
|
+
return Object.freeze(prefixes);
|
|
13049
|
+
}
|
|
12260
13050
|
function decodeCoveringFields(mapping) {
|
|
12261
13051
|
const raw = field(mapping, "covering_fields");
|
|
12262
13052
|
if (!Array.isArray(raw) || raw.length > 32) {
|
|
@@ -12269,7 +13059,10 @@ function decodeCoveringFields(mapping) {
|
|
|
12269
13059
|
const seen = /* @__PURE__ */ new Set();
|
|
12270
13060
|
for (let index = 0; index < raw.length; index += 1) {
|
|
12271
13061
|
if (!Object.hasOwn(raw, index)) {
|
|
12272
|
-
throw decodeError(
|
|
13062
|
+
throw decodeError(
|
|
13063
|
+
"FLOW.QUERY.INDEXES index covering_fields must be dense",
|
|
13064
|
+
raw
|
|
13065
|
+
);
|
|
12273
13066
|
}
|
|
12274
13067
|
const value = boundedText(
|
|
12275
13068
|
raw[index],
|
|
@@ -12277,7 +13070,10 @@ function decodeCoveringFields(mapping) {
|
|
|
12277
13070
|
512
|
|
12278
13071
|
);
|
|
12279
13072
|
if (seen.has(value)) {
|
|
12280
|
-
throw decodeError(
|
|
13073
|
+
throw decodeError(
|
|
13074
|
+
"FLOW.QUERY.INDEXES index covering_fields contains duplicates",
|
|
13075
|
+
raw
|
|
13076
|
+
);
|
|
12281
13077
|
}
|
|
12282
13078
|
seen.add(value);
|
|
12283
13079
|
fields[index] = value;
|
|
@@ -12285,30 +13081,341 @@ function decodeCoveringFields(mapping) {
|
|
|
12285
13081
|
return Object.freeze(fields);
|
|
12286
13082
|
}
|
|
12287
13083
|
function decodeIndexFormat(mapping) {
|
|
12288
|
-
const raw = requiredMap2(
|
|
13084
|
+
const raw = requiredMap2(
|
|
13085
|
+
field(mapping, "format"),
|
|
13086
|
+
"FLOW.QUERY.INDEXES index format"
|
|
13087
|
+
);
|
|
12289
13088
|
if (!hasKey(raw, "counter")) {
|
|
12290
|
-
throw decodeError(
|
|
13089
|
+
throw decodeError(
|
|
13090
|
+
"FLOW.QUERY.INDEXES index format counter is missing",
|
|
13091
|
+
raw
|
|
13092
|
+
);
|
|
12291
13093
|
}
|
|
12292
13094
|
const counterValue = field(raw, "counter");
|
|
12293
|
-
const counter = counterValue === null ? void 0 : boundedText(
|
|
13095
|
+
const counter = counterValue === null ? void 0 : boundedText(
|
|
13096
|
+
counterValue,
|
|
13097
|
+
"FLOW.QUERY.INDEXES index format counter",
|
|
13098
|
+
128
|
|
13099
|
+
);
|
|
12294
13100
|
return Object.freeze({
|
|
12295
|
-
queryRow: requiredBoundedText2(
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
13101
|
+
queryRow: requiredBoundedText2(
|
|
13102
|
+
raw,
|
|
13103
|
+
"query_row",
|
|
13104
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13105
|
+
128
|
|
13106
|
+
),
|
|
13107
|
+
key: requiredBoundedText2(
|
|
13108
|
+
raw,
|
|
13109
|
+
"key",
|
|
13110
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13111
|
+
128
|
|
13112
|
+
),
|
|
13113
|
+
entry: requiredBoundedText2(
|
|
13114
|
+
raw,
|
|
13115
|
+
"entry",
|
|
13116
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13117
|
+
128
|
|
13118
|
+
),
|
|
13119
|
+
reverse: requiredBoundedText2(
|
|
13120
|
+
raw,
|
|
13121
|
+
"reverse",
|
|
13122
|
+
"FLOW.QUERY.INDEXES index format",
|
|
13123
|
+
128
|
|
13124
|
+
),
|
|
12299
13125
|
counter,
|
|
12300
13126
|
raw: freezeMap(raw)
|
|
12301
13127
|
});
|
|
12302
13128
|
}
|
|
13129
|
+
|
|
13130
|
+
// src/flow-query-response.ts
|
|
13131
|
+
var FLOW_QUERY_RESULT_CONTRACT = "ferric.flow.query.result/v1";
|
|
13132
|
+
var FLOW_EXPLAIN_CONTRACT = "ferric.flow.explain/v1";
|
|
13133
|
+
var USAGE_FIELDS2 = [
|
|
13134
|
+
["range_seeks", "rangeSeeks"],
|
|
13135
|
+
["range_pages", "rangePages"],
|
|
13136
|
+
["scanned_entries", "scannedEntries"],
|
|
13137
|
+
["scanned_bytes", "scannedBytes"],
|
|
13138
|
+
["hydrated_records", "hydratedRecords"],
|
|
13139
|
+
["residual_checks", "residualChecks"],
|
|
13140
|
+
["duplicate_entries", "duplicateEntries"],
|
|
13141
|
+
["result_records", "resultRecords"],
|
|
13142
|
+
["response_bytes", "responseBytes"],
|
|
13143
|
+
["memory_high_water_bytes", "memoryHighWaterBytes"],
|
|
13144
|
+
["wall_time_us", "wallTimeUs"]
|
|
13145
|
+
];
|
|
13146
|
+
var MAX_SIGNED_643 = (1n << 63n) - 1n;
|
|
13147
|
+
var QUALITY_VALUES2 = {
|
|
13148
|
+
exactness: ["authoritative", "projected_exact", "exact", "not_applicable"],
|
|
13149
|
+
freshness: ["current", "projection_watermark", "not_applicable"],
|
|
13150
|
+
coverage: ["complete", "unavailable"],
|
|
13151
|
+
pagination: ["none", "complete", "authenticated_seek", "live_seek"]
|
|
13152
|
+
};
|
|
13153
|
+
function decodeFlowQueryResult(value) {
|
|
13154
|
+
const result = decodeFlowQueryResponse(value, (mapping) => freezeMap(mapping));
|
|
13155
|
+
if (result.kind === "records") {
|
|
13156
|
+
return Object.freeze({
|
|
13157
|
+
kind: "records",
|
|
13158
|
+
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
13159
|
+
records: Object.freeze(result.records),
|
|
13160
|
+
page: result.page,
|
|
13161
|
+
quality: result.quality,
|
|
13162
|
+
usage: result.usage,
|
|
13163
|
+
raw: result.raw
|
|
13164
|
+
});
|
|
13165
|
+
}
|
|
13166
|
+
return Object.freeze({
|
|
13167
|
+
kind: "count",
|
|
13168
|
+
version: FLOW_QUERY_RESULT_CONTRACT,
|
|
13169
|
+
count: result.count,
|
|
13170
|
+
quality: result.quality,
|
|
13171
|
+
usage: result.usage,
|
|
13172
|
+
raw: result.raw
|
|
13173
|
+
});
|
|
13174
|
+
}
|
|
13175
|
+
function decodeFlowQueryRecords(value, decodeRecord) {
|
|
13176
|
+
const result = decodeFlowQueryResponse(
|
|
13177
|
+
value,
|
|
13178
|
+
(mapping, index) => decodeRecord(mapping instanceof Map ? freezeMap(mapping) : mapping, index)
|
|
13179
|
+
);
|
|
13180
|
+
if (result.kind === "count") {
|
|
13181
|
+
throw new FerricStoreError("Flow record convenience query returned a count result", {
|
|
13182
|
+
raw: result.raw
|
|
13183
|
+
});
|
|
13184
|
+
}
|
|
13185
|
+
return result.records;
|
|
13186
|
+
}
|
|
13187
|
+
function decodeFlowQueryResponse(value, decodeRecord) {
|
|
13188
|
+
const mapping = requiredMap2(value, "FLOW.QUERY result");
|
|
13189
|
+
requireContract(mapping, "version", FLOW_QUERY_RESULT_CONTRACT, "FLOW.QUERY result");
|
|
13190
|
+
const quality = decodeQuality(field(mapping, "quality"));
|
|
13191
|
+
const usage = decodeUsage(field(mapping, "usage"));
|
|
13192
|
+
const hasRecords = hasKey(mapping, "records");
|
|
13193
|
+
const hasCount = hasKey(mapping, "result");
|
|
13194
|
+
if (hasRecords === hasCount) {
|
|
13195
|
+
throw decodeError("FLOW.QUERY result must contain exactly one records or count shape", value);
|
|
13196
|
+
}
|
|
13197
|
+
const raw = freezeMap(mapping);
|
|
13198
|
+
if (hasRecords) {
|
|
13199
|
+
const rawRecords = field(mapping, "records");
|
|
13200
|
+
if (!Array.isArray(rawRecords) || rawRecords.length > 100) {
|
|
13201
|
+
throw decodeError("FLOW.QUERY records must be an array of at most 100 maps", value);
|
|
13202
|
+
}
|
|
13203
|
+
const records = new Array(rawRecords.length);
|
|
13204
|
+
for (let index = 0; index < rawRecords.length; index += 1) {
|
|
13205
|
+
if (!Object.hasOwn(rawRecords, index)) {
|
|
13206
|
+
throw decodeError("FLOW.QUERY records must be a dense array", value);
|
|
13207
|
+
}
|
|
13208
|
+
records[index] = decodeRecord(
|
|
13209
|
+
requiredMap2(rawRecords[index], `FLOW.QUERY record ${index}`),
|
|
13210
|
+
index
|
|
13211
|
+
);
|
|
13212
|
+
}
|
|
13213
|
+
if (usage.resultRecords !== records.length || usage.resultRecords > usage.scannedEntries) {
|
|
13214
|
+
throw decodeError("FLOW.QUERY usage result_records is inconsistent with records", value);
|
|
13215
|
+
}
|
|
13216
|
+
return {
|
|
13217
|
+
kind: "records",
|
|
13218
|
+
records,
|
|
13219
|
+
page: decodePage(field(mapping, "page")),
|
|
13220
|
+
quality,
|
|
13221
|
+
usage,
|
|
13222
|
+
raw
|
|
13223
|
+
};
|
|
13224
|
+
}
|
|
13225
|
+
if (hasKey(mapping, "page")) {
|
|
13226
|
+
throw decodeError("FLOW.QUERY count result contains an unexpected page", value);
|
|
13227
|
+
}
|
|
13228
|
+
const countResult = requiredMap2(field(mapping, "result"), "FLOW.QUERY count result");
|
|
13229
|
+
if (requiredText2(countResult, "kind", "FLOW.QUERY count result") !== "count") {
|
|
13230
|
+
throw decodeError("FLOW.QUERY count result kind must be count", value);
|
|
13231
|
+
}
|
|
13232
|
+
const count = boundedInteger(
|
|
13233
|
+
field(countResult, "value"),
|
|
13234
|
+
MAX_SIGNED_643,
|
|
13235
|
+
"FLOW.QUERY count value"
|
|
13236
|
+
);
|
|
13237
|
+
if (usage.resultRecords !== 1) {
|
|
13238
|
+
throw decodeError("FLOW.QUERY count usage result_records must be 1", value);
|
|
13239
|
+
}
|
|
13240
|
+
return {
|
|
13241
|
+
kind: "count",
|
|
13242
|
+
count,
|
|
13243
|
+
quality,
|
|
13244
|
+
usage,
|
|
13245
|
+
raw
|
|
13246
|
+
};
|
|
13247
|
+
}
|
|
13248
|
+
function decodeFlowExplainResult(value) {
|
|
13249
|
+
const mapping = requiredMap2(value, "FLOW.QUERY explain");
|
|
13250
|
+
requireContract(mapping, "version", FLOW_EXPLAIN_CONTRACT, "FLOW.QUERY explain");
|
|
13251
|
+
const queryFingerprint = requiredText2(mapping, "query_fingerprint", "FLOW.QUERY explain");
|
|
13252
|
+
if (!/^[0-9a-f]{64}$/iu.test(queryFingerprint)) {
|
|
13253
|
+
throw decodeError("FLOW.QUERY explain query_fingerprint is invalid", value);
|
|
13254
|
+
}
|
|
13255
|
+
const status = requiredText2(mapping, "status", "FLOW.QUERY explain");
|
|
13256
|
+
if (status !== "planned" && status !== "rejected" && status !== "executed") {
|
|
13257
|
+
throw decodeError(`FLOW.QUERY explain status ${JSON.stringify(status)} is unsupported`, value);
|
|
13258
|
+
}
|
|
13259
|
+
const plan = freezeMetadataMap(
|
|
13260
|
+
requiredMap2(field(mapping, "plan"), "FLOW.QUERY explain plan"),
|
|
13261
|
+
"FLOW.QUERY explain plan"
|
|
13262
|
+
);
|
|
13263
|
+
const estimate = freezeMetadataMap(
|
|
13264
|
+
requiredMap2(field(mapping, "estimate"), "FLOW.QUERY explain estimate"),
|
|
13265
|
+
"FLOW.QUERY explain estimate"
|
|
13266
|
+
);
|
|
13267
|
+
const bounds = freezeMetadataMap(
|
|
13268
|
+
requiredMap2(field(mapping, "bounds"), "FLOW.QUERY explain bounds"),
|
|
13269
|
+
"FLOW.QUERY explain bounds"
|
|
13270
|
+
);
|
|
13271
|
+
const capabilities = decodeExplainCapabilities(mapping);
|
|
13272
|
+
const extendedFields = ["stats", "quality", "pressure", "decision", "alternatives"];
|
|
13273
|
+
const extendedPresence = extendedFields.map((name) => hasKey(mapping, name));
|
|
13274
|
+
const specialized = capabilities != null && !extendedPresence.some(Boolean);
|
|
13275
|
+
let stats;
|
|
13276
|
+
let quality;
|
|
13277
|
+
let pressure;
|
|
13278
|
+
let decision;
|
|
13279
|
+
let alternatives;
|
|
13280
|
+
if (specialized) {
|
|
13281
|
+
if (status !== "planned") {
|
|
13282
|
+
throw decodeError("FLOW.QUERY specialized explain must be planned", value);
|
|
13283
|
+
}
|
|
13284
|
+
if (hasKey(mapping, "actual") || hasKey(mapping, "diagnostic")) {
|
|
13285
|
+
throw decodeError("FLOW.QUERY specialized explain has extended status fields", value);
|
|
13286
|
+
}
|
|
13287
|
+
alternatives = Object.freeze([]);
|
|
13288
|
+
} else {
|
|
13289
|
+
if (!extendedPresence.every(Boolean) || !hasKey(mapping, "actual") || !hasKey(mapping, "diagnostic")) {
|
|
13290
|
+
throw decodeError("FLOW.QUERY explain is missing required v1 fields", value);
|
|
13291
|
+
}
|
|
13292
|
+
stats = freezeMetadataMap(
|
|
13293
|
+
requiredMap2(field(mapping, "stats"), "FLOW.QUERY explain stats"),
|
|
13294
|
+
"FLOW.QUERY explain stats"
|
|
13295
|
+
);
|
|
13296
|
+
quality = decodeQuality(field(mapping, "quality"));
|
|
13297
|
+
pressure = freezeMetadataMap(
|
|
13298
|
+
requiredMap2(field(mapping, "pressure"), "FLOW.QUERY explain pressure"),
|
|
13299
|
+
"FLOW.QUERY explain pressure"
|
|
13300
|
+
);
|
|
13301
|
+
decision = freezeMetadataMap(
|
|
13302
|
+
requiredMap2(field(mapping, "decision"), "FLOW.QUERY explain decision"),
|
|
13303
|
+
"FLOW.QUERY explain decision"
|
|
13304
|
+
);
|
|
13305
|
+
alternatives = decodeExplainAlternatives(field(mapping, "alternatives"));
|
|
13306
|
+
}
|
|
13307
|
+
const actualValue = field(mapping, "actual");
|
|
13308
|
+
let actual;
|
|
13309
|
+
if (status === "executed") {
|
|
13310
|
+
if (actualValue == null) {
|
|
13311
|
+
throw decodeError("FLOW.QUERY executed explain is missing actual usage", value);
|
|
13312
|
+
}
|
|
13313
|
+
actual = decodeUsage(actualValue);
|
|
13314
|
+
} else if (actualValue != null) {
|
|
13315
|
+
throw decodeError("FLOW.QUERY non-executed explain contains actual usage", value);
|
|
13316
|
+
}
|
|
13317
|
+
const diagnosticValue = field(mapping, "diagnostic");
|
|
13318
|
+
let diagnostic;
|
|
13319
|
+
if (status === "rejected") {
|
|
13320
|
+
diagnostic = tryDecodeFlowQueryError(diagnosticValue);
|
|
13321
|
+
if (diagnostic == null) {
|
|
13322
|
+
throw decodeError("FLOW.QUERY rejected explain has an invalid diagnostic", value);
|
|
13323
|
+
}
|
|
13324
|
+
} else if (diagnosticValue != null) {
|
|
13325
|
+
throw decodeError("FLOW.QUERY non-rejected explain contains a diagnostic", value);
|
|
13326
|
+
}
|
|
13327
|
+
return Object.freeze({
|
|
13328
|
+
version: FLOW_EXPLAIN_CONTRACT,
|
|
13329
|
+
queryFingerprint,
|
|
13330
|
+
status,
|
|
13331
|
+
plan,
|
|
13332
|
+
estimate,
|
|
13333
|
+
stats,
|
|
13334
|
+
quality,
|
|
13335
|
+
bounds,
|
|
13336
|
+
pressure,
|
|
13337
|
+
decision,
|
|
13338
|
+
alternatives,
|
|
13339
|
+
capabilities,
|
|
13340
|
+
actual,
|
|
13341
|
+
diagnostic,
|
|
13342
|
+
raw: freezeMap(mapping)
|
|
13343
|
+
});
|
|
13344
|
+
}
|
|
13345
|
+
function decodeExplainCapabilities(mapping) {
|
|
13346
|
+
if (!hasKey(mapping, "capabilities")) return void 0;
|
|
13347
|
+
const value = requiredMap2(
|
|
13348
|
+
field(mapping, "capabilities"),
|
|
13349
|
+
"FLOW.QUERY explain capabilities"
|
|
13350
|
+
);
|
|
13351
|
+
return Object.freeze({
|
|
13352
|
+
requested: decodeExplainCapabilityList(field(value, "requested"), "requested"),
|
|
13353
|
+
available: decodeExplainCapabilityList(field(value, "available"), "available"),
|
|
13354
|
+
missing: decodeExplainCapabilityList(field(value, "missing"), "missing"),
|
|
13355
|
+
raw: freezeMetadataMap(value, "FLOW.QUERY explain capabilities")
|
|
13356
|
+
});
|
|
13357
|
+
}
|
|
13358
|
+
function decodeExplainCapabilityList(value, name) {
|
|
13359
|
+
if (!Array.isArray(value) || value.length > 64) {
|
|
13360
|
+
throw decodeError(
|
|
13361
|
+
`FLOW.QUERY explain capabilities ${name} must contain at most 64 entries`,
|
|
13362
|
+
value
|
|
13363
|
+
);
|
|
13364
|
+
}
|
|
13365
|
+
const result = new Array(value.length);
|
|
13366
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13367
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13368
|
+
if (!Object.hasOwn(value, index)) {
|
|
13369
|
+
throw decodeError(`FLOW.QUERY explain capabilities ${name} must be dense`, value);
|
|
13370
|
+
}
|
|
13371
|
+
const capability = boundedText(
|
|
13372
|
+
value[index],
|
|
13373
|
+
`FLOW.QUERY explain capabilities ${name} entry ${index}`,
|
|
13374
|
+
128
|
|
13375
|
+
);
|
|
13376
|
+
if (seen.has(capability)) {
|
|
13377
|
+
throw decodeError(
|
|
13378
|
+
`FLOW.QUERY explain capabilities ${name} contains duplicates`,
|
|
13379
|
+
value
|
|
13380
|
+
);
|
|
13381
|
+
}
|
|
13382
|
+
seen.add(capability);
|
|
13383
|
+
result[index] = capability;
|
|
13384
|
+
}
|
|
13385
|
+
return Object.freeze(result);
|
|
13386
|
+
}
|
|
13387
|
+
function decodeExplainAlternatives(value) {
|
|
13388
|
+
if (!Array.isArray(value) || value.length > 31) {
|
|
13389
|
+
throw decodeError("FLOW.QUERY explain alternatives must be an array of at most 31 maps", value);
|
|
13390
|
+
}
|
|
13391
|
+
const alternatives = new Array(value.length);
|
|
13392
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13393
|
+
if (!Object.hasOwn(value, index)) {
|
|
13394
|
+
throw decodeError("FLOW.QUERY explain alternatives must be dense", value);
|
|
13395
|
+
}
|
|
13396
|
+
alternatives[index] = freezeMetadataMap(
|
|
13397
|
+
requiredMap2(value[index], `FLOW.QUERY explain alternative ${index}`),
|
|
13398
|
+
`FLOW.QUERY explain alternative ${index}`
|
|
13399
|
+
);
|
|
13400
|
+
}
|
|
13401
|
+
return Object.freeze(alternatives);
|
|
13402
|
+
}
|
|
12303
13403
|
function decodeQuality(value) {
|
|
12304
13404
|
const mapping = requiredMap2(value, "FLOW.QUERY quality");
|
|
12305
13405
|
return Object.freeze({
|
|
12306
|
-
exactness:
|
|
12307
|
-
freshness:
|
|
12308
|
-
coverage:
|
|
12309
|
-
pagination:
|
|
13406
|
+
exactness: decodeQualityValue(mapping, "exactness", QUALITY_VALUES2.exactness),
|
|
13407
|
+
freshness: decodeQualityValue(mapping, "freshness", QUALITY_VALUES2.freshness),
|
|
13408
|
+
coverage: decodeQualityValue(mapping, "coverage", QUALITY_VALUES2.coverage),
|
|
13409
|
+
pagination: decodeQualityValue(mapping, "pagination", QUALITY_VALUES2.pagination)
|
|
12310
13410
|
});
|
|
12311
13411
|
}
|
|
13412
|
+
function decodeQualityValue(mapping, name, allowed) {
|
|
13413
|
+
const value = requiredBoundedText2(mapping, name, "FLOW.QUERY quality", 64);
|
|
13414
|
+
if (!allowed.includes(value)) {
|
|
13415
|
+
throw decodeError(`FLOW.QUERY quality ${name} is unsupported`, mapping);
|
|
13416
|
+
}
|
|
13417
|
+
return value;
|
|
13418
|
+
}
|
|
12312
13419
|
function decodeUsage(value) {
|
|
12313
13420
|
const mapping = requiredMap2(value, "FLOW.QUERY usage");
|
|
12314
13421
|
const usage = /* @__PURE__ */ Object.create(null);
|
|
@@ -12318,13 +13425,17 @@ function decodeUsage(value) {
|
|
|
12318
13425
|
`FLOW.QUERY usage ${wireName}`
|
|
12319
13426
|
);
|
|
12320
13427
|
}
|
|
12321
|
-
|
|
13428
|
+
const decoded = usage;
|
|
13429
|
+
if (decoded.hydratedRecords > decoded.scannedEntries || decoded.duplicateEntries > decoded.scannedEntries || decoded.rangePages > decoded.scannedEntries + decoded.rangeSeeks || decoded.residualChecks > decoded.scannedEntries * 12) {
|
|
13430
|
+
throw decodeError("FLOW.QUERY usage counters are inconsistent", value);
|
|
13431
|
+
}
|
|
13432
|
+
return Object.freeze(decoded);
|
|
12322
13433
|
}
|
|
12323
13434
|
function decodePage(value) {
|
|
12324
13435
|
const mapping = requiredMap2(value, "FLOW.QUERY page");
|
|
12325
13436
|
const hasMore = requiredBoolean(mapping, "has_more", "FLOW.QUERY page");
|
|
12326
13437
|
const cursor = optionalText2(mapping, "cursor", "FLOW.QUERY page");
|
|
12327
|
-
if (cursor != null && (!cursor.startsWith("fqc1_") ||
|
|
13438
|
+
if (cursor != null && (!cursor.startsWith("fqc1_") || Buffer48.byteLength(cursor) < 16 || Buffer48.byteLength(cursor) > 4096)) {
|
|
12328
13439
|
throw decodeError("FLOW.QUERY page cursor is invalid", value);
|
|
12329
13440
|
}
|
|
12330
13441
|
if (hasMore !== (cursor != null)) {
|
|
@@ -12332,26 +13443,14 @@ function decodePage(value) {
|
|
|
12332
13443
|
}
|
|
12333
13444
|
return Object.freeze({ hasMore, ...cursor == null ? {} : { cursor } });
|
|
12334
13445
|
}
|
|
12335
|
-
function decodePosition(value) {
|
|
12336
|
-
if (value == null) return void 0;
|
|
12337
|
-
const mapping = requiredMap2(value, "FLOW.QUERY diagnostic position");
|
|
12338
|
-
return Object.freeze({
|
|
12339
|
-
byte: positiveInteger(field(mapping, "byte"), "FLOW.QUERY diagnostic position byte"),
|
|
12340
|
-
line: positiveInteger(field(mapping, "line"), "FLOW.QUERY diagnostic position line"),
|
|
12341
|
-
column: positiveInteger(
|
|
12342
|
-
field(mapping, "column"),
|
|
12343
|
-
"FLOW.QUERY diagnostic position column"
|
|
12344
|
-
)
|
|
12345
|
-
});
|
|
12346
|
-
}
|
|
12347
13446
|
|
|
12348
13447
|
// src/client-core.ts
|
|
12349
13448
|
import "buffer";
|
|
12350
13449
|
|
|
12351
13450
|
// src/client-core-helpers.ts
|
|
12352
|
-
import { Buffer as
|
|
13451
|
+
import { Buffer as Buffer49 } from "buffer";
|
|
12353
13452
|
function bgsaveResponse(response) {
|
|
12354
|
-
if ((typeof response === "string" ||
|
|
13453
|
+
if ((typeof response === "string" || Buffer49.isBuffer(response) || response instanceof Uint8Array) && text(response) === "Background saving started") {
|
|
12355
13454
|
return true;
|
|
12356
13455
|
}
|
|
12357
13456
|
return okResponse(response);
|
|
@@ -12365,7 +13464,7 @@ function fetchOrComputeCompletionToken(options) {
|
|
|
12365
13464
|
"fetch-or-compute completion requires computeToken"
|
|
12366
13465
|
);
|
|
12367
13466
|
}
|
|
12368
|
-
if (!
|
|
13467
|
+
if (!Buffer49.isBuffer(options.computeToken)) {
|
|
12369
13468
|
throw new TypeError("fetch-or-compute computeToken must be a Buffer");
|
|
12370
13469
|
}
|
|
12371
13470
|
return options.computeToken;
|
|
@@ -12725,14 +13824,14 @@ var FerricStoreAdministrationClient = class extends FerricStoreClientBase {
|
|
|
12725
13824
|
};
|
|
12726
13825
|
|
|
12727
13826
|
// src/store-utilities.ts
|
|
12728
|
-
import { Buffer as
|
|
13827
|
+
import { Buffer as Buffer52 } from "buffer";
|
|
12729
13828
|
function encode(codec, value) {
|
|
12730
13829
|
return codec.encode(value);
|
|
12731
13830
|
}
|
|
12732
13831
|
function decode(codec, value) {
|
|
12733
13832
|
if (value == null) return null;
|
|
12734
|
-
if (
|
|
12735
|
-
if (value instanceof Uint8Array) return codec.decode(
|
|
13833
|
+
if (Buffer52.isBuffer(value)) return codec.decode(value);
|
|
13834
|
+
if (value instanceof Uint8Array) return codec.decode(Buffer52.from(value));
|
|
12736
13835
|
return value;
|
|
12737
13836
|
}
|
|
12738
13837
|
function number(value) {
|
|
@@ -14967,7 +16066,7 @@ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
|
|
|
14967
16066
|
args.push(indexId);
|
|
14968
16067
|
}
|
|
14969
16068
|
try {
|
|
14970
|
-
return decodeFlowQueryIndexStatus(await this.commandArgs(args));
|
|
16069
|
+
return decodeFlowQueryIndexStatus(await this.commandArgs(args), indexId);
|
|
14971
16070
|
} catch (error) {
|
|
14972
16071
|
this.throwFlowQueryError(error);
|
|
14973
16072
|
}
|
|
@@ -15029,7 +16128,7 @@ var FerricStoreFlowQueryClient = class extends FerricStoreManagementClient {
|
|
|
15029
16128
|
if (hasFlowExplainPrefix(query)) {
|
|
15030
16129
|
throw new TypeError("query already contains an EXPLAIN prefix");
|
|
15031
16130
|
}
|
|
15032
|
-
return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query
|
|
16131
|
+
return decodeFlowExplainResult(await this.executeFlowQuery(prefix + query, params));
|
|
15033
16132
|
}
|
|
15034
16133
|
throwFlowQueryError(error) {
|
|
15035
16134
|
if (error instanceof FerricStoreError) {
|
|
@@ -15062,7 +16161,7 @@ function throwIfClosed(signal) {
|
|
|
15062
16161
|
}
|
|
15063
16162
|
|
|
15064
16163
|
// src/flow-policy.ts
|
|
15065
|
-
import { Buffer as
|
|
16164
|
+
import { Buffer as Buffer54 } from "buffer";
|
|
15066
16165
|
var MAX_FLOW_POLICY_GENERATION = Number.MAX_SAFE_INTEGER;
|
|
15067
16166
|
function assertFlowPolicyGeneration(value) {
|
|
15068
16167
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
@@ -15152,7 +16251,7 @@ function requiredRecord(value, context) {
|
|
|
15152
16251
|
}
|
|
15153
16252
|
return result;
|
|
15154
16253
|
}
|
|
15155
|
-
if (typeof value === "object" && value != null && !Array.isArray(value) && !
|
|
16254
|
+
if (typeof value === "object" && value != null && !Array.isArray(value) && !Buffer54.isBuffer(value) && !(value instanceof Uint8Array)) return value;
|
|
15156
16255
|
throw new TypeError(`${context} returned an unexpected response`);
|
|
15157
16256
|
}
|
|
15158
16257
|
function optionalRecord(value, context) {
|
|
@@ -15173,8 +16272,8 @@ function stringArray(value, context) {
|
|
|
15173
16272
|
}
|
|
15174
16273
|
function requiredText3(value, context) {
|
|
15175
16274
|
if (typeof value === "string") return value;
|
|
15176
|
-
if (
|
|
15177
|
-
return
|
|
16275
|
+
if (Buffer54.isBuffer(value) || value instanceof Uint8Array) {
|
|
16276
|
+
return Buffer54.from(value).toString("utf8");
|
|
15178
16277
|
}
|
|
15179
16278
|
throw new TypeError(`FLOW policy ${context} returned an unexpected response`);
|
|
15180
16279
|
}
|
|
@@ -15430,7 +16529,7 @@ var FerricStoreFlowSupportClient = class extends FerricStoreFlowQueryClient {
|
|
|
15430
16529
|
};
|
|
15431
16530
|
|
|
15432
16531
|
// src/flow-many-snapshot.ts
|
|
15433
|
-
import { Buffer as
|
|
16532
|
+
import { Buffer as Buffer56 } from "buffer";
|
|
15434
16533
|
var encodedOptionFields = ["error", "payload", "reason", "result"];
|
|
15435
16534
|
function snapshotCreateItem(item, codec) {
|
|
15436
16535
|
const snapshot = {
|
|
@@ -15470,7 +16569,7 @@ function snapshotFlowManyOptions(options, codec) {
|
|
|
15470
16569
|
}
|
|
15471
16570
|
function snapshotClaimedItem(item) {
|
|
15472
16571
|
const wire = item[CLAIMED_ITEM_WIRE];
|
|
15473
|
-
const leaseToken =
|
|
16572
|
+
const leaseToken = Buffer56.from(wire?.leaseToken ?? item.leaseToken);
|
|
15474
16573
|
const snapshot = {
|
|
15475
16574
|
...item,
|
|
15476
16575
|
fencingToken: wire?.fencingToken ?? item.fencingToken,
|
|
@@ -15487,15 +16586,15 @@ function snapshotClaimedItem(item) {
|
|
|
15487
16586
|
function snapshotFencedItem(item) {
|
|
15488
16587
|
return Object.freeze({
|
|
15489
16588
|
...item,
|
|
15490
|
-
...item.leaseToken == null ? {} : { leaseToken:
|
|
16589
|
+
...item.leaseToken == null ? {} : { leaseToken: Buffer56.from(item.leaseToken) }
|
|
15491
16590
|
});
|
|
15492
16591
|
}
|
|
15493
16592
|
function snapshotClaimedItemWire(wire, leaseToken) {
|
|
15494
16593
|
return Object.freeze({
|
|
15495
16594
|
fencingToken: wire.fencingToken,
|
|
15496
|
-
id:
|
|
16595
|
+
id: Buffer56.from(wire.id),
|
|
15497
16596
|
leaseToken,
|
|
15498
|
-
partitionKey: wire.partitionKey == null ? wire.partitionKey :
|
|
16597
|
+
partitionKey: wire.partitionKey == null ? wire.partitionKey : Buffer56.from(wire.partitionKey)
|
|
15499
16598
|
});
|
|
15500
16599
|
}
|
|
15501
16600
|
function snapshotArray(values) {
|
|
@@ -15506,7 +16605,7 @@ function snapshotArray(values) {
|
|
|
15506
16605
|
return Object.freeze(snapshot);
|
|
15507
16606
|
}
|
|
15508
16607
|
function snapshotStateMeta(stateMeta) {
|
|
15509
|
-
return snapshotRecord(stateMeta, (value) =>
|
|
16608
|
+
return snapshotRecord(stateMeta, (value) => Buffer56.isBuffer(value) ? Buffer56.from(value) : value);
|
|
15510
16609
|
}
|
|
15511
16610
|
function snapshotCommandRecord(values) {
|
|
15512
16611
|
const seen = /* @__PURE__ */ new WeakMap();
|
|
@@ -15524,7 +16623,7 @@ function snapshotRecord(values, capture) {
|
|
|
15524
16623
|
}
|
|
15525
16624
|
function snapshotCommandArgument(value, seen) {
|
|
15526
16625
|
if (typeof value !== "object" || value == null) return value;
|
|
15527
|
-
if (
|
|
16626
|
+
if (Buffer56.isBuffer(value) || value instanceof Uint8Array) return Buffer56.from(value);
|
|
15528
16627
|
const objectValue = value;
|
|
15529
16628
|
const existing = seen.get(objectValue);
|
|
15530
16629
|
if (existing != null) return existing;
|
|
@@ -16512,7 +17611,7 @@ function nativeOptionsForBootstrap(options, signal) {
|
|
|
16512
17611
|
}
|
|
16513
17612
|
|
|
16514
17613
|
// src/flow-query-projection.ts
|
|
16515
|
-
import { Buffer as
|
|
17614
|
+
import { Buffer as Buffer57 } from "buffer";
|
|
16516
17615
|
var MAX_PROJECTION_FIELDS = 32;
|
|
16517
17616
|
var MAX_DYNAMIC_NAME_BYTES = 64;
|
|
16518
17617
|
var FIELD_BRAND = /* @__PURE__ */ Symbol("FerricStoreFlowProjectionField");
|
|
@@ -16580,20 +17679,38 @@ function projectFlowQuery(query, shape, ...fields) {
|
|
|
16580
17679
|
if (containsReturnKeyword(query)) {
|
|
16581
17680
|
throw new TypeError("Flow query already contains a RETURN clause");
|
|
16582
17681
|
}
|
|
16583
|
-
const
|
|
16584
|
-
const base = trimmed.endsWith(";") ? trimmed.slice(0, -1).trimEnd() : trimmed;
|
|
17682
|
+
const base = stripOptionalTerminator(query);
|
|
16585
17683
|
const result = `${base} RETURN ${shape.toUpperCase()} (${selectors.join(", ")})`;
|
|
16586
|
-
if (
|
|
17684
|
+
if (Buffer57.byteLength(result, "utf8") > FLOW_QUERY_MAX_BYTES) {
|
|
16587
17685
|
throw new TypeError(`FLOW.QUERY query exceeds ${FLOW_QUERY_MAX_BYTES} bytes`);
|
|
16588
17686
|
}
|
|
16589
17687
|
return result;
|
|
16590
17688
|
}
|
|
17689
|
+
function stripOptionalTerminator(query) {
|
|
17690
|
+
const trimmed = trimFlowQueryAsciiWhitespace(query);
|
|
17691
|
+
if (!trimmed.endsWith(";")) return trimmed;
|
|
17692
|
+
const base = trimFlowQueryAsciiWhitespace(trimmed.slice(0, -1));
|
|
17693
|
+
if (base.endsWith(";")) {
|
|
17694
|
+
throw new TypeError("Flow query accepts at most one trailing semicolon");
|
|
17695
|
+
}
|
|
17696
|
+
return base;
|
|
17697
|
+
}
|
|
16591
17698
|
function querySource(query) {
|
|
16592
|
-
const
|
|
16593
|
-
if (
|
|
17699
|
+
const source = trimFlowQueryAsciiWhitespaceStart(query);
|
|
17700
|
+
if (!matchesFlowQueryAsciiKeyword(source, 0, "FROM") || !isFlowQueryAsciiWhitespaceCode(source.charCodeAt(4))) {
|
|
16594
17701
|
throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
|
|
16595
17702
|
}
|
|
16596
|
-
|
|
17703
|
+
let offset = 4;
|
|
17704
|
+
while (isFlowQueryAsciiWhitespaceCode(source.charCodeAt(offset))) offset += 1;
|
|
17705
|
+
for (const candidate of ["runs", "events"]) {
|
|
17706
|
+
if (matchesFlowQueryAsciiKeyword(source, offset, candidate.toUpperCase())) {
|
|
17707
|
+
const boundary = source[offset + candidate.length];
|
|
17708
|
+
if (boundary == null || isFlowQueryAsciiWhitespaceCode(boundary.charCodeAt(0))) {
|
|
17709
|
+
return candidate;
|
|
17710
|
+
}
|
|
17711
|
+
}
|
|
17712
|
+
}
|
|
17713
|
+
throw new TypeError("Projected Flow query must start with FROM runs or FROM events");
|
|
16597
17714
|
}
|
|
16598
17715
|
function containsReturnKeyword(query) {
|
|
16599
17716
|
let quoted = false;
|
|
@@ -16624,7 +17741,7 @@ function quoteName(value, allowPrivate) {
|
|
|
16624
17741
|
throw new TypeError("Flow query projection metadata name must be text");
|
|
16625
17742
|
}
|
|
16626
17743
|
validateUnicodeScalarText2(value);
|
|
16627
|
-
const size =
|
|
17744
|
+
const size = Buffer57.byteLength(value, "utf8");
|
|
16628
17745
|
if (size === 0 || size > MAX_DYNAMIC_NAME_BYTES || !allowPrivate && value.startsWith("__")) {
|
|
16629
17746
|
throw new TypeError(
|
|
16630
17747
|
`Flow query projection metadata names must be 1..${MAX_DYNAMIC_NAME_BYTES} UTF-8 bytes`
|
|
@@ -16658,7 +17775,7 @@ function complete(options = {}) {
|
|
|
16658
17775
|
function retry(options = {}) {
|
|
16659
17776
|
return brandOutcome({ ...options, kind: "retry" });
|
|
16660
17777
|
}
|
|
16661
|
-
function
|
|
17778
|
+
function fail2(options = {}) {
|
|
16662
17779
|
return brandOutcome({ ...options, kind: "fail" });
|
|
16663
17780
|
}
|
|
16664
17781
|
function isOutcome(value) {
|
|
@@ -17455,7 +18572,7 @@ async function applyQueueException(queue, options, job, error) {
|
|
|
17455
18572
|
const policy = normalizeExceptionPolicy(options.exceptionPolicy);
|
|
17456
18573
|
if (policy === "raise") throw error;
|
|
17457
18574
|
const payload = workerErrorPayload(error, options, queue.client.codec);
|
|
17458
|
-
await applyQueueOutcome(queue, job, policy === "fail" ?
|
|
18575
|
+
await applyQueueOutcome(queue, job, policy === "fail" ? fail2({ error: payload }) : retry({ error: payload }));
|
|
17459
18576
|
}
|
|
17460
18577
|
|
|
17461
18578
|
// src/queue-pending-completions.ts
|
|
@@ -17702,7 +18819,7 @@ var QueueWorker = class {
|
|
|
17702
18819
|
const policy = normalizeExceptionPolicy(this.options.exceptionPolicy);
|
|
17703
18820
|
if (policy !== "raise") {
|
|
17704
18821
|
const payload = workerErrorPayload(error, this.options, this.queue.client.codec);
|
|
17705
|
-
outcome = policy === "fail" ?
|
|
18822
|
+
outcome = policy === "fail" ? fail2({ error: payload }) : retry({ error: payload });
|
|
17706
18823
|
}
|
|
17707
18824
|
}
|
|
17708
18825
|
const stopped = await stopQueueBatchGuards(guards.map((guard) => guard.job), guards);
|
|
@@ -18615,7 +19732,7 @@ var WorkflowWorker = class {
|
|
|
18615
19732
|
await applyWorkflowOutcome(
|
|
18616
19733
|
this.workflow.client,
|
|
18617
19734
|
ctx,
|
|
18618
|
-
|
|
19735
|
+
fail2({ error: workerErrorPayload(error, this.options, this.workflow.client.codec) }),
|
|
18619
19736
|
registration.returnRecord
|
|
18620
19737
|
);
|
|
18621
19738
|
return;
|
|
@@ -18630,7 +19747,7 @@ var WorkflowWorker = class {
|
|
|
18630
19747
|
};
|
|
18631
19748
|
|
|
18632
19749
|
// src/version.ts
|
|
18633
|
-
var FERRICSTORE_SDK_VERSION = "0.5.
|
|
19750
|
+
var FERRICSTORE_SDK_VERSION = "0.5.2";
|
|
18634
19751
|
var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.0";
|
|
18635
19752
|
var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
|
|
18636
19753
|
export {
|
|
@@ -18689,7 +19806,7 @@ export {
|
|
|
18689
19806
|
WorkflowWorker,
|
|
18690
19807
|
classifyServerError,
|
|
18691
19808
|
complete,
|
|
18692
|
-
fail,
|
|
19809
|
+
fail2 as fail,
|
|
18693
19810
|
isOutcome,
|
|
18694
19811
|
isReconnectableClosedConnectionError,
|
|
18695
19812
|
mapException,
|