@oddington/sdk 0.1.23 → 0.1.24
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/dist/browser.js
CHANGED
|
@@ -405,44 +405,44 @@ var FileOperationError = class extends Error {
|
|
|
405
405
|
retryable;
|
|
406
406
|
}, FILE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/, FILE_ORIGINAL_MAX_BYTES = 5 * 1024 ** 3;
|
|
407
407
|
function parseFileDescriptor(value) {
|
|
408
|
-
let
|
|
408
|
+
let invalid8 = () => {
|
|
409
409
|
throw new FileOperationError("unavailable", 503, !0);
|
|
410
410
|
};
|
|
411
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
411
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
412
412
|
let f = value;
|
|
413
|
-
if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return
|
|
413
|
+
if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return invalid8();
|
|
414
414
|
let d = f.details;
|
|
415
415
|
if (d.kind === "other") {
|
|
416
|
-
if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return
|
|
416
|
+
if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid8();
|
|
417
417
|
} else if (d.kind === "csv") {
|
|
418
|
-
if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return
|
|
418
|
+
if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return invalid8();
|
|
419
419
|
} else if (d.kind === "pdf") {
|
|
420
|
-
if (f.mediaType !== "application/pdf" || Object.keys(d).some((key) => !["kind", "pages"].includes(key)) || "pages" in d && (!Number.isSafeInteger(d.pages) || d.pages < 1)) return
|
|
421
|
-
} else return
|
|
420
|
+
if (f.mediaType !== "application/pdf" || Object.keys(d).some((key) => !["kind", "pages"].includes(key)) || "pages" in d && (!Number.isSafeInteger(d.pages) || d.pages < 1)) return invalid8();
|
|
421
|
+
} else return invalid8();
|
|
422
422
|
for (let [name, descriptor] of Object.entries(f.enrichments)) {
|
|
423
|
-
if (!safeEnrichmentName(name)) return
|
|
423
|
+
if (!safeEnrichmentName(name)) return invalid8();
|
|
424
424
|
parseEnrichmentDescriptor(descriptor);
|
|
425
425
|
}
|
|
426
|
-
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ?
|
|
426
|
+
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid8() : f;
|
|
427
427
|
}
|
|
428
428
|
function parseEnrichmentDescriptor(value) {
|
|
429
|
-
let
|
|
429
|
+
let invalid8 = () => {
|
|
430
430
|
throw new FileOperationError("unavailable", 503, !0);
|
|
431
431
|
};
|
|
432
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
432
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
433
433
|
let d = value;
|
|
434
|
-
return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ?
|
|
434
|
+
return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ? invalid8() : d;
|
|
435
435
|
}
|
|
436
436
|
function safeEnrichmentName(value) {
|
|
437
437
|
return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
|
|
438
438
|
}
|
|
439
439
|
function parseFileEnrichMetadata(value, maxBytes) {
|
|
440
|
-
let
|
|
440
|
+
let invalid8 = () => {
|
|
441
441
|
throw new FileOperationError("invalid_input", 400);
|
|
442
442
|
};
|
|
443
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
443
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
444
444
|
let d = value;
|
|
445
|
-
if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return
|
|
445
|
+
if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid8();
|
|
446
446
|
if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
447
447
|
return d;
|
|
448
448
|
}
|
|
@@ -453,23 +453,23 @@ function safeFilePath(value) {
|
|
|
453
453
|
return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
|
|
454
454
|
}
|
|
455
455
|
function parseFileCreateMetadata(value, maxBytes) {
|
|
456
|
-
let
|
|
456
|
+
let invalid8 = () => {
|
|
457
457
|
throw new FileOperationError("invalid_input", 400);
|
|
458
458
|
};
|
|
459
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
459
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
460
460
|
let input = value;
|
|
461
|
-
if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return
|
|
461
|
+
if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return invalid8();
|
|
462
462
|
let path = input.path === void 0 ? "Files" : input.path;
|
|
463
|
-
if (!safeFileName(input.name) || !safeFilePath(path) || path.split("/")[0].toLowerCase() === ".os" || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || input.inputMediaType !== void 0 && input.inputMediaType !== "application/pdf" || !Number.isSafeInteger(input.size) || input.size < 0) return
|
|
463
|
+
if (!safeFileName(input.name) || !safeFilePath(path) || path.split("/")[0].toLowerCase() === ".os" || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || input.inputMediaType !== void 0 && input.inputMediaType !== "application/pdf" || !Number.isSafeInteger(input.size) || input.size < 0) return invalid8();
|
|
464
464
|
if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
465
|
-
if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return
|
|
465
|
+
if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return invalid8();
|
|
466
466
|
let csv;
|
|
467
467
|
if (input.csv !== void 0) {
|
|
468
|
-
if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return
|
|
468
|
+
if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid8();
|
|
469
469
|
let hints = input.csv;
|
|
470
|
-
if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return
|
|
470
|
+
if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid8();
|
|
471
471
|
let encoding = hints.encoding === void 0 ? "utf-8" : hints.encoding, delimiter = hints.delimiter === void 0 ? "," : hints.delimiter, headerRow = hints.headerRow === void 0 ? 1 : hints.headerRow;
|
|
472
|
-
if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return
|
|
472
|
+
if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid8();
|
|
473
473
|
csv = { encoding, delimiter, headerRow };
|
|
474
474
|
}
|
|
475
475
|
return {
|
|
@@ -957,6 +957,15 @@ function captureRecordsSearchInput(query, options) {
|
|
|
957
957
|
return { query, options: captured };
|
|
958
958
|
}
|
|
959
959
|
|
|
960
|
+
function captureRecordsReadRefs(value) {
|
|
961
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > 100)
|
|
962
|
+
throw new DataOperationError("invalid_query");
|
|
963
|
+
let refs = historyArray(value);
|
|
964
|
+
if (!refs.every((ref) => validRecordRef(ref) && !/[\r\n]/.test(ref)) || new Set(refs).size !== refs.length)
|
|
965
|
+
throw new DataOperationError("invalid_query");
|
|
966
|
+
return refs;
|
|
967
|
+
}
|
|
968
|
+
|
|
960
969
|
var DATA_REQUEST_LIMIT = 256 * 1024, invalidChange = () => {
|
|
961
970
|
throw new DataOperationError("invalid_change", !1, "unapplied");
|
|
962
971
|
};
|
|
@@ -1109,14 +1118,102 @@ async function resolveFilesContext() {
|
|
|
1109
1118
|
}
|
|
1110
1119
|
function filesContext(workspace, endpoint, headers) {
|
|
1111
1120
|
if (!workspace || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(workspace) || workspace.length > 63 || ["auth", "www", "api", "os"].includes(workspace) || endpoint !== `https://${workspace}.oddington.ai`) throw new Error();
|
|
1112
|
-
return { url: `${endpoint}/api/files`, headers: { ...headers, "x-
|
|
1121
|
+
return { url: `${endpoint}/api/files`, headers: { ...headers, "x-os-workspace": workspace }, isCurrent: () => !0 };
|
|
1113
1122
|
}
|
|
1114
1123
|
function checked(workspace, endpoint, headers) {
|
|
1115
1124
|
if (!workspace || !/^[a-z0-9][a-z0-9-]{0,127}$/.test(workspace)) throw new Error();
|
|
1116
1125
|
let origin = new URL(endpoint);
|
|
1117
1126
|
if (origin.protocol !== "https:" || origin.username || origin.password || origin.search || origin.hash || origin.pathname !== "/")
|
|
1118
1127
|
throw new Error();
|
|
1119
|
-
return { url: `${origin.origin}/api/data`, headers: { ...headers, "x-
|
|
1128
|
+
return { url: `${origin.origin}/api/data`, headers: { ...headers, "x-os-workspace": workspace } };
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
var invalid6 = () => {
|
|
1132
|
+
throw new DataOperationError("invalid_query");
|
|
1133
|
+
}, unavailable = () => {
|
|
1134
|
+
throw new DataOperationError("unavailable");
|
|
1135
|
+
}, text2 = (value) => typeof value == "string" && value.length > 0;
|
|
1136
|
+
function capture2(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
|
|
1137
|
+
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return value;
|
|
1138
|
+
if (!value || typeof value != "object" || ancestors.has(value) || depth > 32) return invalid6();
|
|
1139
|
+
ancestors.add(value);
|
|
1140
|
+
try {
|
|
1141
|
+
return Array.isArray(value) ? historyArray(value).map((item) => capture2(item, ancestors, depth + 1)) : Object.fromEntries(Object.entries(historyProperties(value)).map(([key, descriptor]) => [key, capture2(descriptor.value, ancestors, depth + 1)]));
|
|
1142
|
+
} finally {
|
|
1143
|
+
ancestors.delete(value);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
function recordPagination(select) {
|
|
1147
|
+
function pages(query) {
|
|
1148
|
+
let captured = capture2(query), names = Object.keys(historyProperties(captured));
|
|
1149
|
+
for (let name of names) {
|
|
1150
|
+
let selection2 = historyProperties(captured[name]);
|
|
1151
|
+
if (Object.hasOwn(selection2, "$")) {
|
|
1152
|
+
let options = historyProperties(selection2.$.value);
|
|
1153
|
+
if (Object.hasOwn(options, "after")) return invalid6();
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return iterate();
|
|
1157
|
+
async function* iterate() {
|
|
1158
|
+
let state = new Map(names.map((name) => [name, {
|
|
1159
|
+
seen: /* @__PURE__ */ new Set(),
|
|
1160
|
+
total: 0,
|
|
1161
|
+
count: void 0,
|
|
1162
|
+
next: void 0
|
|
1163
|
+
}])), active2 = names, version;
|
|
1164
|
+
do {
|
|
1165
|
+
let request2 = Object.fromEntries(active2.map((name) => {
|
|
1166
|
+
let selection2 = captured[name], next = state.get(name).next;
|
|
1167
|
+
return [name, next === void 0 ? selection2 : { ...selection2, $: { ...selection2.$, after: next } }];
|
|
1168
|
+
})), response2 = await select(request2), page;
|
|
1169
|
+
try {
|
|
1170
|
+
page = capture2(response2);
|
|
1171
|
+
let keys4 = Object.keys(historyProperties(page));
|
|
1172
|
+
(keys4.length !== active2.length + 1 || keys4.some((key) => key !== "$meta" && !active2.includes(key))) && unavailable();
|
|
1173
|
+
let meta = page.$meta;
|
|
1174
|
+
(Object.keys(historyProperties(meta)).sort().join(",") !== "collections,version" || !text2(meta.version) || version !== void 0 && version !== meta.version) && unavailable(), version = meta.version, Object.keys(historyProperties(meta.collections)).some((key) => !active2.includes(key)) && unavailable();
|
|
1175
|
+
for (let name of active2) {
|
|
1176
|
+
let records = historyArray(page[name]), metadata = Object.hasOwn(meta.collections, name) ? meta.collections[name] : {};
|
|
1177
|
+
(Object.keys(historyProperties(metadata)).some((key) => key !== "count" && key !== "next") || Object.hasOwn(metadata, "next") && !text2(metadata.next)) && unavailable();
|
|
1178
|
+
for (let record3 of records) {
|
|
1179
|
+
historyProperties(record3);
|
|
1180
|
+
let row = record3;
|
|
1181
|
+
(!validRecordRef(row.$ref) || !text2(row.$version)) && unavailable();
|
|
1182
|
+
}
|
|
1183
|
+
let current2 = state.get(name);
|
|
1184
|
+
captured[name].$?.count === !0 ? ((!Number.isSafeInteger(metadata.count) || metadata.count < 0 || current2.count !== void 0 && current2.count !== metadata.count) && unavailable(), current2.count = metadata.count) : Object.hasOwn(metadata, "count") && unavailable(), current2.total += records.length, (!Number.isSafeInteger(current2.total) || current2.count !== void 0 && (current2.total > current2.count || metadata.next === void 0 && current2.total !== current2.count)) && unavailable(), metadata.next !== void 0 && (current2.seen.has(metadata.next) && unavailable(), current2.seen.add(metadata.next)), current2.next = metadata.next;
|
|
1185
|
+
}
|
|
1186
|
+
} catch {
|
|
1187
|
+
return unavailable();
|
|
1188
|
+
}
|
|
1189
|
+
let collections = Object.fromEntries(names.map((name) => {
|
|
1190
|
+
let current2 = state.get(name);
|
|
1191
|
+
return [name, {
|
|
1192
|
+
...current2.count === void 0 ? {} : { count: current2.count },
|
|
1193
|
+
...current2.next === void 0 ? {} : { next: current2.next }
|
|
1194
|
+
}];
|
|
1195
|
+
})), output = Object.fromEntries(names.map((name) => [name, active2.includes(name) ? page[name] : []]));
|
|
1196
|
+
active2 = active2.filter((name) => state.get(name).next !== void 0), yield { ...output, $meta: { version, collections } };
|
|
1197
|
+
} while (active2.length);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
async function all(query, options) {
|
|
1201
|
+
let properties = historyProperties(options), maxRecords = properties.maxRecords?.value;
|
|
1202
|
+
(Object.keys(properties).join(",") !== "maxRecords" || !Number.isSafeInteger(maxRecords) || maxRecords < 1) && invalid6();
|
|
1203
|
+
let result2, total = 0;
|
|
1204
|
+
for await (let page of pages(query)) {
|
|
1205
|
+
let names = Object.keys(page.$meta.collections), size = names.reduce((sum, name) => sum + page[name].length, 0);
|
|
1206
|
+
if (size > maxRecords - total) throw new DataOperationError("capacity");
|
|
1207
|
+
total += size, result2 ??= { ...Object.fromEntries(names.map((name) => [name, []])), $meta: page.$meta };
|
|
1208
|
+
for (let name of names) {
|
|
1209
|
+
let target = result2[name];
|
|
1210
|
+
for (let record3 of page[name]) target.push(record3);
|
|
1211
|
+
}
|
|
1212
|
+
result2.$meta = page.$meta;
|
|
1213
|
+
}
|
|
1214
|
+
return result2;
|
|
1215
|
+
}
|
|
1216
|
+
return { pages, all };
|
|
1120
1217
|
}
|
|
1121
1218
|
|
|
1122
1219
|
var data = {
|
|
@@ -1139,13 +1236,20 @@ var data = {
|
|
|
1139
1236
|
throw error instanceof DataOperationError ? error : new DataOperationError("unavailable", !0);
|
|
1140
1237
|
}
|
|
1141
1238
|
}
|
|
1239
|
+
async function read2(input) {
|
|
1240
|
+
let refs = captureRecordsReadRefs(typeof input == "string" ? [input] : input), result2 = await send3({ operation: "records.read", refs });
|
|
1241
|
+
return typeof input == "string" ? result2.records[0] : result2;
|
|
1242
|
+
}
|
|
1243
|
+
let select = (query) => send3({ operation: "records.select", query });
|
|
1142
1244
|
return {
|
|
1143
1245
|
collections: {
|
|
1144
1246
|
list: () => send3({ operation: "collections.list" }),
|
|
1145
1247
|
schema: (name) => send3({ operation: "collections.schema", name })
|
|
1146
1248
|
},
|
|
1147
1249
|
records: {
|
|
1148
|
-
|
|
1250
|
+
read: read2,
|
|
1251
|
+
select,
|
|
1252
|
+
...recordPagination(select),
|
|
1149
1253
|
search: async (query, options) => send3({ operation: "records.search", ...captureRecordsSearchInput(query, options) })
|
|
1150
1254
|
},
|
|
1151
1255
|
history: {
|
|
@@ -1270,7 +1374,7 @@ async function hostedContent(url, init2, parent, upstream = fetch, check = async
|
|
|
1270
1374
|
}
|
|
1271
1375
|
}
|
|
1272
1376
|
|
|
1273
|
-
var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0,
|
|
1377
|
+
var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0, invalid7 = () => new FileOperationError("invalid_input", 400), unavailable2 = () => new FileOperationError("unavailable", 503, !0), failures = {
|
|
1274
1378
|
400: ["invalid_input", "unsupported_context"],
|
|
1275
1379
|
401: ["unauthenticated"],
|
|
1276
1380
|
403: ["access_denied"],
|
|
@@ -1290,9 +1394,9 @@ async function boundedBytes(stream, limit, signal) {
|
|
|
1290
1394
|
try {
|
|
1291
1395
|
for (; ; ) {
|
|
1292
1396
|
let { done, value } = await reader.read();
|
|
1293
|
-
if (signal?.aborted) throw
|
|
1397
|
+
if (signal?.aborted) throw unavailable2();
|
|
1294
1398
|
if (done) break;
|
|
1295
|
-
if (!(value instanceof Uint8Array)) throw
|
|
1399
|
+
if (!(value instanceof Uint8Array)) throw invalid7();
|
|
1296
1400
|
if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
|
|
1297
1401
|
bytes.set(value, size - value.byteLength);
|
|
1298
1402
|
}
|
|
@@ -1306,7 +1410,7 @@ async function boundedBytes(stream, limit, signal) {
|
|
|
1306
1410
|
async function timed(work, parent, timeout = TIMEOUT_MS) {
|
|
1307
1411
|
let controller = new AbortController(), timer, abort, expiry = new Promise((_, reject) => {
|
|
1308
1412
|
abort = () => {
|
|
1309
|
-
controller.abort(), reject(
|
|
1413
|
+
controller.abort(), reject(unavailable2());
|
|
1310
1414
|
}, timer = setTimeout(abort, timeout), parent?.addEventListener("abort", abort, { once: !0 }), parent?.aborted && abort();
|
|
1311
1415
|
});
|
|
1312
1416
|
try {
|
|
@@ -1320,12 +1424,12 @@ async function result(response2, maximum = RESULT_BYTES) {
|
|
|
1320
1424
|
let bytes = await boundedBytes(response2.body, maximum);
|
|
1321
1425
|
return JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes));
|
|
1322
1426
|
} catch {
|
|
1323
|
-
throw
|
|
1427
|
+
throw unavailable2();
|
|
1324
1428
|
}
|
|
1325
1429
|
}
|
|
1326
1430
|
async function send(suffix, init2, descriptor, initial, parent) {
|
|
1327
1431
|
let original = initial, checkCurrent = (context2 = original) => {
|
|
1328
|
-
if (parent?.aborted) throw
|
|
1432
|
+
if (parent?.aborted) throw unavailable2();
|
|
1329
1433
|
if (!original.isCurrent() || context2.url !== original.url) throw new FileOperationError("unsupported_context", 400);
|
|
1330
1434
|
};
|
|
1331
1435
|
for (let attempt = 0; attempt < ATTEMPTS; attempt++) {
|
|
@@ -1345,11 +1449,11 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1345
1449
|
})();
|
|
1346
1450
|
if (!response2.ok) {
|
|
1347
1451
|
let value2 = await result(response2), error = value2 && typeof value2 == "object" && "error" in value2 ? value2.error : void 0, received = error && typeof error == "object" && "code" in error ? error.code : void 0, code = failures[response2.status]?.find((code2) => code2 === received);
|
|
1348
|
-
throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") :
|
|
1452
|
+
throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") : unavailable2();
|
|
1349
1453
|
}
|
|
1350
1454
|
if (response2.status !== (descriptor === 204 ? 204 : 200) || descriptor === 204 && response2.body !== null)
|
|
1351
1455
|
throw response2.body?.cancel().catch(() => {
|
|
1352
|
-
}),
|
|
1456
|
+
}), unavailable2();
|
|
1353
1457
|
try {
|
|
1354
1458
|
checkCurrent();
|
|
1355
1459
|
} catch (error) {
|
|
@@ -1363,21 +1467,21 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1363
1467
|
return checkCurrent(), value;
|
|
1364
1468
|
let parsed;
|
|
1365
1469
|
if (descriptor === "enrichment") {
|
|
1366
|
-
if (!value || typeof value != "object" || Array.isArray(value)) throw
|
|
1470
|
+
if (!value || typeof value != "object" || Array.isArray(value)) throw unavailable2();
|
|
1367
1471
|
let { name, ...metadata } = value;
|
|
1368
|
-
if (!safeEnrichmentName(name)) throw
|
|
1472
|
+
if (!safeEnrichmentName(name)) throw unavailable2();
|
|
1369
1473
|
parsed = { name, ...parseEnrichmentDescriptor(metadata) };
|
|
1370
1474
|
} else parsed = parseFileDescriptor(value);
|
|
1371
1475
|
return checkCurrent(), parsed;
|
|
1372
1476
|
} catch (error) {
|
|
1373
|
-
let failure = error instanceof FileOperationError ? error :
|
|
1477
|
+
let failure = error instanceof FileOperationError ? error : unavailable2();
|
|
1374
1478
|
if (init2.body instanceof ReadableStream || !failure.retryable || attempt + 1 === ATTEMPTS) throw failure;
|
|
1375
1479
|
}
|
|
1376
1480
|
}
|
|
1377
|
-
throw
|
|
1481
|
+
throw unavailable2();
|
|
1378
1482
|
}
|
|
1379
1483
|
function idPath(id3) {
|
|
1380
|
-
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw
|
|
1484
|
+
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid7();
|
|
1381
1485
|
return `/${id3}`;
|
|
1382
1486
|
}
|
|
1383
1487
|
async function multipartCreate(input, metadata, exchange, release = () => {
|
|
@@ -1388,18 +1492,18 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1388
1492
|
return pending.add(task), task.then(() => pending.delete(task), () => pending.delete(task)), task;
|
|
1389
1493
|
}, void 0, timeout), control = (body) => ({
|
|
1390
1494
|
method: "POST",
|
|
1391
|
-
headers: { "content-type": "application/json", ...ticket ? { "x-
|
|
1495
|
+
headers: { "content-type": "application/json", ...ticket ? { "x-os-transfer": ticket } : {} },
|
|
1392
1496
|
body: JSON.stringify(body)
|
|
1393
1497
|
});
|
|
1394
1498
|
try {
|
|
1395
1499
|
let start = await request2((signal) => exchange(`${route}/start`, control(upload?.file ?? metadata), "control", signal));
|
|
1396
|
-
if (!start || typeof start != "object" || Array.isArray(start)) throw
|
|
1500
|
+
if (!start || typeof start != "object" || Array.isArray(start)) throw unavailable2();
|
|
1397
1501
|
let session = start;
|
|
1398
|
-
if (Object.keys(session).sort().join(",") !== "partBytes,ticket" || session.partBytes !== PART_BYTES || typeof session.ticket != "string" || !session.ticket || session.ticket.length > 64 * 1024) throw
|
|
1502
|
+
if (Object.keys(session).sort().join(",") !== "partBytes,ticket" || session.partBytes !== PART_BYTES || typeof session.ticket != "string" || !session.ticket || session.ticket.length > 64 * 1024) throw unavailable2();
|
|
1399
1503
|
ticket = session.ticket, input.file instanceof ReadableStream && (reader = input.file.getReader());
|
|
1400
1504
|
let lastProgress = Date.now(), next = async () => {
|
|
1401
1505
|
try {
|
|
1402
|
-
if (Date.now() - lastProgress >= TIMEOUT_MS) throw
|
|
1506
|
+
if (Date.now() - lastProgress >= TIMEOUT_MS) throw unavailable2();
|
|
1403
1507
|
let value = await request2(() => reader.read(), Math.max(1, TIMEOUT_MS - (Date.now() - lastProgress)));
|
|
1404
1508
|
return value.value?.byteLength && (lastProgress = Date.now()), value;
|
|
1405
1509
|
} catch (error) {
|
|
@@ -1420,41 +1524,41 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1420
1524
|
if (!chunk || offset === chunk.byteLength) {
|
|
1421
1525
|
chunk = void 0, offset = 0;
|
|
1422
1526
|
let value2 = await next();
|
|
1423
|
-
if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw
|
|
1527
|
+
if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid7();
|
|
1424
1528
|
}
|
|
1425
1529
|
let take = Math.min(length - filled, chunk.byteLength - offset);
|
|
1426
1530
|
part.set(chunk.subarray(offset, offset + take), filled), filled += take, offset += take, offset === chunk.byteLength && (chunk = void 0, offset = 0);
|
|
1427
1531
|
}
|
|
1428
1532
|
}
|
|
1429
|
-
if (part.byteLength !== length) throw
|
|
1533
|
+
if (part.byteLength !== length) throw invalid7();
|
|
1430
1534
|
if (reader && sent + length === metadata.size)
|
|
1431
1535
|
for (lastProgress = Date.now(); ; ) {
|
|
1432
1536
|
let value2 = await next();
|
|
1433
1537
|
if (value2.done) break;
|
|
1434
|
-
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw
|
|
1538
|
+
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid7();
|
|
1435
1539
|
}
|
|
1436
1540
|
let value = await request2((signal) => exchange(`${route}/part`, {
|
|
1437
1541
|
method: "POST",
|
|
1438
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1542
|
+
headers: { "content-type": "application/octet-stream", "x-os-transfer": ticket, "x-os-part": String(partNumber) },
|
|
1439
1543
|
body: part.buffer
|
|
1440
1544
|
}, "control", signal));
|
|
1441
1545
|
part = void 0;
|
|
1442
1546
|
let receipt = value;
|
|
1443
|
-
if (!receipt || typeof receipt != "object" || Object.keys(receipt).sort().join(",") !== "etag,partNumber" || receipt.partNumber !== partNumber || typeof receipt.etag != "string" || !receipt.etag || receipt.etag.length > 256 || /[\u0000-\u001f\u007f]/.test(receipt.etag)) throw
|
|
1547
|
+
if (!receipt || typeof receipt != "object" || Object.keys(receipt).sort().join(",") !== "etag,partNumber" || receipt.partNumber !== partNumber || typeof receipt.etag != "string" || !receipt.etag || receipt.etag.length > 256 || /[\u0000-\u001f\u007f]/.test(receipt.etag)) throw unavailable2();
|
|
1444
1548
|
receipts.push({ partNumber, etag: receipt.etag }), sent += length, lastProgress = Date.now();
|
|
1445
1549
|
}
|
|
1446
1550
|
if (upload) for (let name of Object.keys(upload.file.enrichments)) {
|
|
1447
1551
|
let bytes = await request2(() => upload.enrichment(name));
|
|
1448
|
-
if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw
|
|
1552
|
+
if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid7();
|
|
1449
1553
|
await request2((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
|
|
1450
1554
|
method: "POST",
|
|
1451
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1555
|
+
headers: { "content-type": "application/octet-stream", "x-os-transfer": ticket },
|
|
1452
1556
|
body: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
|
|
1453
1557
|
}, "control", signal));
|
|
1454
1558
|
}
|
|
1455
1559
|
await upload?.beforeComplete();
|
|
1456
1560
|
let completion = control({ parts: receipts });
|
|
1457
|
-
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw
|
|
1561
|
+
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw unavailable2();
|
|
1458
1562
|
return parseFileDescriptor(await request2(
|
|
1459
1563
|
(signal) => exchange(`${route}/complete`, completion, !0, signal),
|
|
1460
1564
|
TIMEOUT_MS + Math.ceil(metadata.size / (1024 * 1024)) * 1e3
|
|
@@ -1462,7 +1566,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1462
1566
|
} catch (error) {
|
|
1463
1567
|
throw reader && await reader.cancel(error).catch(() => {
|
|
1464
1568
|
}), ticket && await request2((signal) => exchange(`${route}/abort`, control({}), "control", signal)).catch(() => {
|
|
1465
|
-
}), error instanceof FileOperationError ? error :
|
|
1569
|
+
}), error instanceof FileOperationError ? error : unavailable2();
|
|
1466
1570
|
} finally {
|
|
1467
1571
|
chunk = void 0, reader?.releaseLock(), pending.size ? Promise.allSettled([...pending]).then(release) : release();
|
|
1468
1572
|
}
|
|
@@ -1479,13 +1583,13 @@ async function operation(work, initial, parent) {
|
|
|
1479
1583
|
}
|
|
1480
1584
|
}, signal = context2.signal && parent ? AbortSignal.any([context2.signal, parent]) : context2.signal ?? parent;
|
|
1481
1585
|
return context2.localFiles ? execute(signal ?? new AbortController().signal) : timed(execute, signal).catch((error) => {
|
|
1482
|
-
throw error instanceof FileOperationError ? error :
|
|
1586
|
+
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1483
1587
|
});
|
|
1484
1588
|
}
|
|
1485
1589
|
function contentPath(id3, name) {
|
|
1486
1590
|
let path = idPath(id3);
|
|
1487
1591
|
if (name === void 0) return `${path}/content`;
|
|
1488
|
-
if (!safeEnrichmentName(name)) throw
|
|
1592
|
+
if (!safeEnrichmentName(name)) throw invalid7();
|
|
1489
1593
|
return `${path}/enrichments/${encodeURIComponent(name)}/content`;
|
|
1490
1594
|
}
|
|
1491
1595
|
async function read(id3, names) {
|
|
@@ -1494,12 +1598,12 @@ async function read(id3, names) {
|
|
|
1494
1598
|
let path = contentPath(id3, names);
|
|
1495
1599
|
return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
|
|
1496
1600
|
}
|
|
1497
|
-
if (!Array.isArray(names)) throw
|
|
1601
|
+
if (!Array.isArray(names)) throw invalid7();
|
|
1498
1602
|
let distinct = [], seen = /* @__PURE__ */ new Set();
|
|
1499
1603
|
for (let name of names) {
|
|
1500
|
-
if (typeof name != "string" || !safeEnrichmentName(name)) throw
|
|
1604
|
+
if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid7();
|
|
1501
1605
|
if (!seen.has(name)) {
|
|
1502
|
-
if (seen.size === 16) throw
|
|
1606
|
+
if (seen.size === 16) throw invalid7();
|
|
1503
1607
|
seen.add(name), distinct.push(name);
|
|
1504
1608
|
}
|
|
1505
1609
|
}
|
|
@@ -1527,18 +1631,18 @@ var files = {
|
|
|
1527
1631
|
async upload(id3) {
|
|
1528
1632
|
return operation(async (context2, signal) => {
|
|
1529
1633
|
let file2 = await send(`${idPath(id3)}/upload`, { method: "POST" }, !0, context2, signal);
|
|
1530
|
-
if (file2.id !== id3) throw
|
|
1634
|
+
if (file2.id !== id3) throw unavailable2();
|
|
1531
1635
|
return file2;
|
|
1532
1636
|
});
|
|
1533
1637
|
},
|
|
1534
1638
|
async create(input, options) {
|
|
1535
1639
|
let context2 = await resolveFilesContext();
|
|
1536
1640
|
if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "size", "path", "name", "storage", "csv"].includes(key)) || options !== void 0 && (!options || typeof options != "object" || Array.isArray(options) || Object.keys(options).some((key) => key !== "requestKey")))
|
|
1537
|
-
throw
|
|
1641
|
+
throw invalid7();
|
|
1538
1642
|
let blob = input.file instanceof Blob, array3 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
|
|
1539
|
-
if (!blob && !array3 && !stream) throw
|
|
1643
|
+
if (!blob && !array3 && !stream) throw invalid7();
|
|
1540
1644
|
let intrinsic = blob ? input.file.size : array3 ? input.file.byteLength : void 0;
|
|
1541
|
-
if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw
|
|
1645
|
+
if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid7();
|
|
1542
1646
|
let name = input.name;
|
|
1543
1647
|
name === void 0 && blob && "name" in input.file && typeof input.file.name == "string" && (name = typeof globalThis.File < "u" && input.file instanceof globalThis.File ? input.file.name : input.file.name.split(/[\\/]/).at(-1));
|
|
1544
1648
|
let metadata = parseFileCreateMetadata({
|
|
@@ -1552,7 +1656,7 @@ var files = {
|
|
|
1552
1656
|
}, FILE_ORIGINAL_MAX_BYTES);
|
|
1553
1657
|
if (!context2.local && !context2.localFiles && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
1554
1658
|
let header = encodeURIComponent(JSON.stringify(metadata));
|
|
1555
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1659
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1556
1660
|
if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
|
|
1557
1661
|
if (active++, context2.localFiles && !routineTransport() && metadata.size > MAX_BYTES) {
|
|
1558
1662
|
let signal = context2.signal ?? new AbortController().signal, file2 = input.file, offset = 0, body = file2 instanceof Blob ? context2.signal ? file2 : file2.stream() : file2 instanceof ReadableStream ? file2 : new ReadableStream({
|
|
@@ -1568,7 +1672,7 @@ var files = {
|
|
|
1568
1672
|
try {
|
|
1569
1673
|
return await send("", { method: "POST", headers: {
|
|
1570
1674
|
"content-type": "application/octet-stream",
|
|
1571
|
-
"x-
|
|
1675
|
+
"x-os-file": header
|
|
1572
1676
|
}, body }, !0, context2, signal);
|
|
1573
1677
|
} finally {
|
|
1574
1678
|
active--;
|
|
@@ -1581,23 +1685,23 @@ var files = {
|
|
|
1581
1685
|
metadata.size,
|
|
1582
1686
|
signal
|
|
1583
1687
|
);
|
|
1584
|
-
if (bytes.byteLength !== metadata.size) throw
|
|
1585
|
-
if (signal.aborted) throw
|
|
1688
|
+
if (bytes.byteLength !== metadata.size) throw invalid7();
|
|
1689
|
+
if (signal.aborted) throw unavailable2();
|
|
1586
1690
|
return await send("", {
|
|
1587
1691
|
method: "POST",
|
|
1588
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1692
|
+
headers: { "content-type": "application/octet-stream", "x-os-file": header },
|
|
1589
1693
|
body: bytes.buffer
|
|
1590
1694
|
}, !0, context2, signal);
|
|
1591
1695
|
} finally {
|
|
1592
1696
|
active--;
|
|
1593
1697
|
}
|
|
1594
1698
|
}, context2.signal).catch((error) => {
|
|
1595
|
-
throw error instanceof FileOperationError ? error :
|
|
1699
|
+
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1596
1700
|
});
|
|
1597
1701
|
},
|
|
1598
1702
|
async enrich(input) {
|
|
1599
1703
|
let context2 = await resolveFilesContext();
|
|
1600
|
-
if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw
|
|
1704
|
+
if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw invalid7();
|
|
1601
1705
|
let path = `${idPath(input.file)}/enrichments`;
|
|
1602
1706
|
if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
|
|
1603
1707
|
throw new FileOperationError("request_too_large", 413);
|
|
@@ -1614,12 +1718,12 @@ var files = {
|
|
|
1614
1718
|
...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
|
|
1615
1719
|
...input.replace === void 0 ? {} : { replace: input.replace }
|
|
1616
1720
|
}, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
|
|
1617
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1721
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1618
1722
|
let result2 = await send(path, { method: "POST", headers: {
|
|
1619
1723
|
"content-type": "application/octet-stream",
|
|
1620
|
-
"x-
|
|
1724
|
+
"x-os-enrichment": header
|
|
1621
1725
|
}, body: bytes.buffer }, "enrichment", context3, signal);
|
|
1622
|
-
if (result2.name !== metadata.name) throw
|
|
1726
|
+
if (result2.name !== metadata.name) throw unavailable2();
|
|
1623
1727
|
return result2;
|
|
1624
1728
|
}, context2);
|
|
1625
1729
|
},
|
|
@@ -1633,7 +1737,7 @@ function validGoogleScopes(value) {
|
|
|
1633
1737
|
return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every((scope) => typeof scope == "string" && scope.length <= 256 && /^(https:\/\/www\.googleapis\.com\/auth\/[A-Za-z0-9._-]+|https:\/\/mail\.google\.com\/|openid|email|profile)$/.test(scope)) && new Set(value).size === value.length;
|
|
1634
1738
|
}
|
|
1635
1739
|
|
|
1636
|
-
var ROUTINE_CONNECTION_CREDENTIALS_ENV = "
|
|
1740
|
+
var ROUTINE_CONNECTION_CREDENTIALS_ENV = "OS_ROUTINE_CONNECTION_CREDENTIALS";
|
|
1637
1741
|
var connectionUuid = (v) => typeof v == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(v);
|
|
1638
1742
|
function runtimeConnection(lease) {
|
|
1639
1743
|
return lease.provider === "gmail" ? {
|
|
@@ -1688,12 +1792,12 @@ function object3(v) {
|
|
|
1688
1792
|
function keys2(v, allowed, required = allowed) {
|
|
1689
1793
|
(Object.keys(v).some((k) => !allowed.includes(k)) || required.some((k) => !Object.hasOwn(v, k))) && fail2("Invalid Airtable input");
|
|
1690
1794
|
}
|
|
1691
|
-
function
|
|
1795
|
+
function text3(v) {
|
|
1692
1796
|
return typeof v == "string" && v.length > 0 && v.length <= 1024;
|
|
1693
1797
|
}
|
|
1694
1798
|
function fields3(v, nonempty = !1) {
|
|
1695
1799
|
let result2 = object3(v);
|
|
1696
|
-
(nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !
|
|
1800
|
+
(nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !text3(k))) && fail2("Invalid Airtable fields");
|
|
1697
1801
|
try {
|
|
1698
1802
|
return serializable(result2);
|
|
1699
1803
|
} catch {
|
|
@@ -1780,10 +1884,10 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1780
1884
|
Array.isArray(page.tables) || fail2("Malformed Airtable tables");
|
|
1781
1885
|
for (let value of page.tables) {
|
|
1782
1886
|
let t = object3(value);
|
|
1783
|
-
(!tableId(t.id) || !
|
|
1887
|
+
(!tableId(t.id) || !text3(t.name) || !text3(t.primaryFieldId) || !Array.isArray(t.fields) || tables.some((existing) => existing.id === t.id)) && fail2("Malformed Airtable table");
|
|
1784
1888
|
let metadata = t.fields.map((value2) => {
|
|
1785
1889
|
let f = object3(value2);
|
|
1786
|
-
return (typeof f.id != "string" || !/^fld[A-Za-z0-9]+$/.test(f.id) || !
|
|
1890
|
+
return (typeof f.id != "string" || !/^fld[A-Za-z0-9]+$/.test(f.id) || !text3(f.name) || !text3(f.type)) && fail2("Malformed Airtable field"), { id: f.id, name: f.name, type: f.type, ...f.options === void 0 ? {} : { options: serializable(f.options) } };
|
|
1787
1891
|
});
|
|
1788
1892
|
(!metadata.some((f) => f.id === t.primaryFieldId) || new Set(metadata.map((f) => f.id)).size !== metadata.length) && fail2("Malformed Airtable fields"), tables.push({ id: t.id, name: t.name, primaryFieldId: t.primaryFieldId, fields: metadata });
|
|
1789
1893
|
}
|
|
@@ -1791,7 +1895,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1791
1895
|
} while (offset);
|
|
1792
1896
|
return tables;
|
|
1793
1897
|
}
|
|
1794
|
-
(!
|
|
1898
|
+
(!text3(input.table) || input.table === "." || input.table === "..") && fail2("Invalid Airtable table"), mutation && !tableId(input.table) && fail2("Airtable writes require a stable table ID");
|
|
1795
1899
|
let path = `${baseId}/${encodeURIComponent(input.table)}`;
|
|
1796
1900
|
if (operation2 === "records.get") {
|
|
1797
1901
|
keys2(input, ["table", "id"]), recordId(input.id) || fail2("Invalid Airtable record ID");
|
|
@@ -1799,7 +1903,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1799
1903
|
return result3.id !== input.id && fail2("Malformed Airtable record"), result3;
|
|
1800
1904
|
}
|
|
1801
1905
|
if (operation2 === "records.list") {
|
|
1802
|
-
keys2(input, ["table", "fields"], ["table"]), input.fields !== void 0 && (!Array.isArray(input.fields) || !input.fields.length || input.fields.some((f) => !
|
|
1906
|
+
keys2(input, ["table", "fields"], ["table"]), input.fields !== void 0 && (!Array.isArray(input.fields) || !input.fields.length || input.fields.some((f) => !text3(f)) || new Set(input.fields).size !== input.fields.length) && fail2("Invalid Airtable field selection");
|
|
1803
1907
|
let records2 = [], ids2 = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set(), offset;
|
|
1804
1908
|
do {
|
|
1805
1909
|
let query2 = new URLSearchParams();
|
|
@@ -1856,10 +1960,10 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1856
1960
|
}
|
|
1857
1961
|
function nextOffset(value, seen) {
|
|
1858
1962
|
if (value !== void 0)
|
|
1859
|
-
return (!
|
|
1963
|
+
return (!text3(value) || seen.has(value)) && fail2("Malformed Airtable pagination"), seen.add(value), value;
|
|
1860
1964
|
}
|
|
1861
1965
|
|
|
1862
|
-
var MANAGED_CONNECTION_CAPABILITY_ENV = "
|
|
1966
|
+
var MANAGED_CONNECTION_CAPABILITY_ENV = "OS_MANAGED_CONNECTION_CAPABILITY";
|
|
1863
1967
|
function managedConnections(capability) {
|
|
1864
1968
|
let endpoint = new URL(capability.endpoint);
|
|
1865
1969
|
if (endpoint.protocol !== "http:" || endpoint.hostname !== "127.0.0.1" || !endpoint.port || endpoint.pathname !== "/" || endpoint.search || endpoint.hash || endpoint.username || endpoint.password || !/^[0-9a-f-]{36}$/.test(capability.token)) throw new AirtableOperationError("Airtable capability unavailable");
|
|
@@ -2015,7 +2119,7 @@ function object4(value) {
|
|
|
2015
2119
|
function keys3(value, allowed, required = allowed) {
|
|
2016
2120
|
assert(Object.keys(value).every((key) => allowed.includes(key)) && required.every((key) => Object.hasOwn(value, key)));
|
|
2017
2121
|
}
|
|
2018
|
-
function
|
|
2122
|
+
function text4(value, empty2 = !1) {
|
|
2019
2123
|
return typeof value == "string" && (empty2 || !!value.trim());
|
|
2020
2124
|
}
|
|
2021
2125
|
function id2(value) {
|
|
@@ -2025,7 +2129,7 @@ function integer(value, minimum = 1) {
|
|
|
2025
2129
|
return Number.isSafeInteger(value) && Number(value) >= minimum;
|
|
2026
2130
|
}
|
|
2027
2131
|
function date(value) {
|
|
2028
|
-
return
|
|
2132
|
+
return text4(value) && Number.isFinite(Date.parse(value));
|
|
2029
2133
|
}
|
|
2030
2134
|
function optionalDate(value) {
|
|
2031
2135
|
return value === null || date(value);
|
|
@@ -2047,7 +2151,7 @@ function json(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
2047
2151
|
}
|
|
2048
2152
|
function recordReference(value) {
|
|
2049
2153
|
let record3 = object4(value);
|
|
2050
|
-
return keys3(record3, ["repository", "ref"]), assert(
|
|
2154
|
+
return keys3(record3, ["repository", "ref"]), assert(text4(record3.repository) && record3.repository === record3.repository.trim() && /^[a-z0-9][a-z0-9._/-]{0,127}$/.test(record3.repository) && !/\.\.|\/\//.test(record3.repository) && text4(record3.ref) && record3.ref === record3.ref.trim() && record3.ref.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)+$/.test(record3.ref)), record3;
|
|
2051
2155
|
}
|
|
2052
2156
|
function responseDefinition(value) {
|
|
2053
2157
|
let definition = object4(value);
|
|
@@ -2059,75 +2163,75 @@ function responseDefinition(value) {
|
|
|
2059
2163
|
assert(options.length > 0);
|
|
2060
2164
|
let values = options.map((value2) => {
|
|
2061
2165
|
let option = object4(value2);
|
|
2062
|
-
if (keys3(option, ["value", "label", "description", "note"], ["value", "label"]), assert(
|
|
2166
|
+
if (keys3(option, ["value", "label", "description", "note"], ["value", "label"]), assert(text4(option.value) && option.value === option.value.trim() && text4(option.label)), "description" in option && assert(text4(option.description)), "note" in option) {
|
|
2063
2167
|
let note = object4(option.note);
|
|
2064
|
-
keys3(note, ["placeholder"]), assert(
|
|
2168
|
+
keys3(note, ["placeholder"]), assert(text4(note.placeholder));
|
|
2065
2169
|
}
|
|
2066
2170
|
return option.value;
|
|
2067
2171
|
});
|
|
2068
2172
|
if (assert(new Set(values).size === values.length), "search" in source || "suggestions" in source) {
|
|
2069
2173
|
let search = object4(source.search);
|
|
2070
|
-
keys3(search, ["triggerLabel", "placeholder", "emptyLabel"]), assert(
|
|
2174
|
+
keys3(search, ["triggerLabel", "placeholder", "emptyLabel"]), assert(text4(search.triggerLabel) && text4(search.placeholder) && text4(search.emptyLabel));
|
|
2071
2175
|
let suggestions2 = array2(source.suggestions);
|
|
2072
|
-
assert(suggestions2.length <= 8 && suggestions2.every((value2) =>
|
|
2176
|
+
assert(suggestions2.length <= 8 && suggestions2.every((value2) => text4(value2) && values.includes(value2)) && new Set(suggestions2).size === suggestions2.length);
|
|
2073
2177
|
} else assert(options.length <= 9);
|
|
2074
2178
|
return;
|
|
2075
2179
|
}
|
|
2076
2180
|
assert(source.type === "records"), keys3(source, ["type", "collection", "refPrefix", "where", "display", "suggestions"], ["type", "collection", "display"]);
|
|
2077
2181
|
let collection = object4(source.collection);
|
|
2078
|
-
keys3(collection, ["repository", "name"]), recordReference({ repository: collection.repository, ref: "records/example" }), assert(
|
|
2182
|
+
keys3(collection, ["repository", "name"]), recordReference({ repository: collection.repository, ref: "records/example" }), assert(text4(collection.name) && /^[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*$/.test(collection.name)), "refPrefix" in source && assert(text4(source.refPrefix) && source.refPrefix.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)*\/$/.test(source.refPrefix));
|
|
2079
2183
|
let where = object4(source.where ?? {});
|
|
2080
2184
|
assert(Object.entries(where).every(([name, value2]) => /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name) && !["constructor", "prototype"].includes(name) && (value2 === null || typeof value2 == "string" || typeof value2 == "boolean" || typeof value2 == "number" && Number.isFinite(value2))));
|
|
2081
2185
|
let display = object4(source.display);
|
|
2082
2186
|
keys3(display, ["labelFields"]);
|
|
2083
2187
|
let labels = array2(display.labelFields);
|
|
2084
|
-
assert(labels.length > 0 && labels.length <= 2 && new Set(labels).size === labels.length && labels.every((value2) =>
|
|
2188
|
+
assert(labels.length > 0 && labels.length <= 2 && new Set(labels).size === labels.length && labels.every((value2) => text4(value2) && /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(value2)));
|
|
2085
2189
|
let suggestions = array2(source.suggestions ?? []), refs = suggestions.map((value2) => {
|
|
2086
2190
|
let suggestion = object4(value2);
|
|
2087
2191
|
keys3(suggestion, ["record", "reason"], ["record"]);
|
|
2088
2192
|
let record3 = recordReference(suggestion.record);
|
|
2089
|
-
return assert(record3.repository === collection.repository), "reason" in suggestion && assert(
|
|
2193
|
+
return assert(record3.repository === collection.repository), "reason" in suggestion && assert(text4(suggestion.reason)), record3.ref;
|
|
2090
2194
|
});
|
|
2091
2195
|
assert(suggestions.length <= 8 && new Set(refs).size === refs.length);
|
|
2092
2196
|
}
|
|
2093
2197
|
function inboxFile(value) {
|
|
2094
2198
|
let file2 = object4(value);
|
|
2095
|
-
keys3(file2, ["id", "name", "mediaType", "size", "sha256", "details"]), assert(id2(file2.id) &&
|
|
2199
|
+
keys3(file2, ["id", "name", "mediaType", "size", "sha256", "details"]), assert(id2(file2.id) && text4(file2.name) && !/[\x00-\x1f\x7f/\\]/.test(file2.name) && text4(file2.mediaType) && /^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(file2.mediaType) && integer(file2.size, 0) && file2.size <= 25 * 1024 * 1024 && typeof file2.sha256 == "string" && /^[0-9a-f]{64}$/.test(file2.sha256));
|
|
2096
2200
|
let details = object4(file2.details);
|
|
2097
2201
|
details.kind === "csv" ? (keys3(details, ["kind", "encoding", "delimiter", "headerRow", "dataRows"]), assert(file2.mediaType === "text/csv" && ["utf-8", "windows-1252"].includes(String(details.encoding)) && [",", ";", " "].includes(String(details.delimiter)) && integer(details.headerRow, 0) && integer(details.dataRows, 0))) : details.kind === "pdf" ? (keys3(details, ["kind", "pages"], ["kind"]), assert(file2.mediaType === "application/pdf" && (!("pages" in details) || integer(details.pages)))) : (keys3(details, ["kind"]), assert(details.kind === "other" && !["text/csv", "application/pdf"].includes(file2.mediaType)));
|
|
2098
2202
|
}
|
|
2099
2203
|
function fields4(value) {
|
|
2100
2204
|
let labels = array2(value).map((value2) => {
|
|
2101
2205
|
let field = object4(value2);
|
|
2102
|
-
return keys3(field, ["label", "value"]), assert(
|
|
2206
|
+
return keys3(field, ["label", "value"]), assert(text4(field.label) && text4(field.value)), field.label;
|
|
2103
2207
|
});
|
|
2104
2208
|
assert(new Set(labels).size === labels.length);
|
|
2105
2209
|
}
|
|
2106
2210
|
function block(value) {
|
|
2107
2211
|
let entry = object4(value);
|
|
2108
2212
|
if (entry.kind === "rich-text") {
|
|
2109
|
-
keys3(entry, ["kind", "markdown"]), assert(
|
|
2213
|
+
keys3(entry, ["kind", "markdown"]), assert(text4(entry.markdown));
|
|
2110
2214
|
return;
|
|
2111
2215
|
}
|
|
2112
2216
|
if (entry.kind === "asks") {
|
|
2113
2217
|
keys3(entry, ["kind", "problem", "asks"]);
|
|
2114
2218
|
let asks = array2(entry.asks);
|
|
2115
|
-
assert(
|
|
2219
|
+
assert(text4(entry.problem) && asks.length > 0 && asks.every(id2) && new Set(asks).size === asks.length);
|
|
2116
2220
|
return;
|
|
2117
2221
|
}
|
|
2118
2222
|
if (assert(["record", "records", "files"].includes(String(entry.kind))), keys3(
|
|
2119
2223
|
entry,
|
|
2120
2224
|
["kind", "label", "initiallyExpanded", ...entry.kind === "record" ? ["record", "view"] : entry.kind === "records" ? ["records", "view"] : ["files"]],
|
|
2121
2225
|
["kind", "label", entry.kind === "record" ? "record" : entry.kind === "records" ? "records" : "files"]
|
|
2122
|
-
), assert(
|
|
2226
|
+
), assert(text4(entry.label) && (!("initiallyExpanded" in entry) || typeof entry.initiallyExpanded == "boolean") && (!("view" in entry) || text4(entry.view) && entry.view === entry.view.trim())), entry.kind === "record") {
|
|
2123
2227
|
let record3 = object4(entry.record);
|
|
2124
|
-
keys3(record3, ["ref", "title", "fields"]), assert(
|
|
2228
|
+
keys3(record3, ["ref", "title", "fields"]), assert(text4(record3.ref) && record3.ref === record3.ref.trim() && text4(record3.title)), fields4(record3.fields);
|
|
2125
2229
|
return;
|
|
2126
2230
|
}
|
|
2127
2231
|
if (entry.kind === "records") {
|
|
2128
2232
|
let records = array2(entry.records), refs = records.map((value2) => {
|
|
2129
2233
|
let record3 = object4(value2);
|
|
2130
|
-
return keys3(record3, ["ref", "title", "description", "facts", "view"], ["ref", "title"]), assert(
|
|
2234
|
+
return keys3(record3, ["ref", "title", "description", "facts", "view"], ["ref", "title"]), assert(text4(record3.ref) && record3.ref === record3.ref.trim() && text4(record3.title)), "description" in record3 && assert(text4(record3.description)), "facts" in record3 && fields4(record3.facts), "view" in record3 && assert(text4(record3.view) && record3.view === record3.view.trim()), record3.ref;
|
|
2131
2235
|
});
|
|
2132
2236
|
assert(records.length > 0 && new Set(refs).size === refs.length);
|
|
2133
2237
|
return;
|
|
@@ -2137,7 +2241,7 @@ function block(value) {
|
|
|
2137
2241
|
}
|
|
2138
2242
|
function response(value) {
|
|
2139
2243
|
let answer = object4(value);
|
|
2140
|
-
return assert(Object.keys(answer).every((key) => ["selection", "note"].includes(key))), typeof answer.selection == "string" ? assert(
|
|
2244
|
+
return assert(Object.keys(answer).every((key) => ["selection", "note"].includes(key))), typeof answer.selection == "string" ? assert(text4(answer.selection) && answer.selection === answer.selection.trim()) : recordReference(answer.selection), Object.hasOwn(answer, "note") && assert(text4(answer.note)), answer;
|
|
2141
2245
|
}
|
|
2142
2246
|
function parseInboxRequest(value) {
|
|
2143
2247
|
try {
|
|
@@ -2146,55 +2250,55 @@ function parseInboxRequest(value) {
|
|
|
2146
2250
|
let operation2 = envelope.operation, input = { ...object4(envelope.input) }, required = operations[operation2];
|
|
2147
2251
|
assert(required.every((key) => Object.hasOwn(input, key)) && Object.keys(input).every((key) => required.includes(key) || operation2 === "questions.searchRecords" && key === "selected" || (operation2 === "items.list" || operation2 === "questions.list") && key === "beforeNumber" || operation2 === "questions.list" && key === "routines")), operation2 === "questions.list" && (assert(Object.hasOwn(input, "routines")), assert(array2(input.routines).every(isAppRoutineName)));
|
|
2148
2252
|
for (let key of ["itemId", "personId", "fileId"]) key in input && assert(id2(input[key]));
|
|
2149
|
-
return "revision" in input && assert(integer(input.revision)), "beforeNumber" in input && assert(integer(input.beforeNumber)), "questionId" in input && assert(
|
|
2253
|
+
return "revision" in input && assert(integer(input.revision)), "beforeNumber" in input && assert(integer(input.beforeNumber)), "questionId" in input && assert(text4(input.questionId) && input.questionId === input.questionId.trim()), "title" in input && assert(text4(input.title)), "lifecycle" in input && assert(input.lifecycle === "open" || input.lifecycle === "closed"), "query" in input && assert(text4(input.query, !0) && input.query.length <= 256), "selected" in input && recordReference(input.selected), "response" in input && response(input.response), assert(new TextEncoder().encode(JSON.stringify(envelope)).byteLength <= INBOX_INPUT_BYTES), "routines" in input && (input.routines = [...new Set(input.routines)]), { operation: operation2, input };
|
|
2150
2254
|
} catch {
|
|
2151
2255
|
throw new InboxOperationError(400, "invalid_input");
|
|
2152
2256
|
}
|
|
2153
2257
|
}
|
|
2154
2258
|
function parseInboxCurrent(value) {
|
|
2155
2259
|
let current2 = object4(value), workspace = object4(current2.workspace), viewer = object4(current2.viewer);
|
|
2156
|
-
return assert(id2(workspace.id) &&
|
|
2260
|
+
return assert(id2(workspace.id) && text4(workspace.slug) && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(workspace.slug) && text4(workspace.name) && text4(workspace.locale) && text4(workspace.timezone)), assert(id2(viewer.id) && text4(viewer.name) && text4(viewer.email)), {
|
|
2157
2261
|
workspace: { id: workspace.id, slug: workspace.slug, name: workspace.name, locale: workspace.locale, timezone: workspace.timezone },
|
|
2158
2262
|
viewer: { id: viewer.id, name: viewer.name, email: viewer.email }
|
|
2159
2263
|
};
|
|
2160
2264
|
}
|
|
2161
2265
|
function parseInboxItem(value) {
|
|
2162
2266
|
let item = object4(json(value));
|
|
2163
|
-
return assert(id2(item.id) && id2(item.workspaceId) && integer(item.number) && integer(item.revision) && integer(item.activityVersion, 0) && ["ask", "digest"].includes(String(item.kind)) && ["open", "closed"].includes(String(item.lifecycle)) &&
|
|
2267
|
+
return assert(id2(item.id) && id2(item.workspaceId) && integer(item.number) && integer(item.revision) && integer(item.activityVersion, 0) && ["ask", "digest"].includes(String(item.kind)) && ["open", "closed"].includes(String(item.lifecycle)) && text4(item.title) && text4(item.description, !0) && text4(item.author) && date(item.publishedAt) && optionalDate(item.seenAt) && optionalDate(item.digestReadAt)), item.outcome !== null && assert(text4(object4(item.outcome).outcome)), "canonicalRoutineId" in item && assert(item.canonicalRoutineId === null || isAppRoutineName(item.canonicalRoutineId)), item.kind === "ask" ? askMetadata(item) : assert(!("tags" in item) && !("recordRefs" in item)), array2(item.body).forEach(block), array2(item.views).forEach((value2) => {
|
|
2164
2268
|
let view = object4(value2);
|
|
2165
|
-
assert(
|
|
2269
|
+
assert(text4(view.id) && text4(view.view) && text4(view.implementation)), json(view.input);
|
|
2166
2270
|
}), array2(item.people).forEach((value2) => {
|
|
2167
2271
|
let person = object4(value2);
|
|
2168
|
-
assert(id2(person.id) &&
|
|
2272
|
+
assert(id2(person.id) && text4(person.name));
|
|
2169
2273
|
}), array2(item.questions).forEach((value2) => {
|
|
2170
2274
|
let question2 = object4(value2);
|
|
2171
|
-
if (assert(
|
|
2275
|
+
if (assert(text4(question2.id) && id2(question2.to) && text4(question2.prompt) && (question2.instructions === null || text4(question2.instructions, !0)) && typeof question2.available == "boolean"), responseDefinition(question2.response), assert(array2(question2.allowedResponders).every(id2)), question2.acceptedResponse !== null) {
|
|
2172
2276
|
let accepted = object4(question2.acceptedResponse);
|
|
2173
|
-
assert(id2(accepted.id) && id2(accepted.userId) && date(accepted.acceptedAt)), response(accepted.response), accepted.label === null ? delete accepted.label : "label" in accepted && assert(
|
|
2277
|
+
assert(id2(accepted.id) && id2(accepted.userId) && date(accepted.acceptedAt)), response(accepted.response), accepted.label === null ? delete accepted.label : "label" in accepted && assert(text4(accepted.label)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder));
|
|
2174
2278
|
}
|
|
2175
2279
|
if (question2.execution !== null) {
|
|
2176
2280
|
let execution = object4(question2.execution);
|
|
2177
2281
|
if (assert(id2(execution.id) && ["pending", "running", "completed", "failed"].includes(String(execution.state)) && integer(execution.attempt, 0)), "consequence" in execution) {
|
|
2178
2282
|
let consequence = object4(execution.consequence);
|
|
2179
|
-
assert(["pending", "running", "applied", "no-write", "stopped", "partial", "uncertain"].includes(String(consequence.state)) && (consequence.phase === null || ["loading", "invoking", "committing"].includes(String(consequence.phase))) && date(consequence.updatedAt) && typeof consequence.needsReconciliation == "boolean" && (consequence.reason === null ||
|
|
2283
|
+
assert(["pending", "running", "applied", "no-write", "stopped", "partial", "uncertain"].includes(String(consequence.state)) && (consequence.phase === null || ["loading", "invoking", "committing"].includes(String(consequence.phase))) && date(consequence.updatedAt) && typeof consequence.needsReconciliation == "boolean" && (consequence.reason === null || text4(consequence.reason, !0))), array2(consequence.evidence).forEach((value3) => {
|
|
2180
2284
|
let receipt = object4(value3);
|
|
2181
|
-
assert(
|
|
2285
|
+
assert(text4(receipt.repository) && text4(receipt.commit) && text4(receipt.diff, !0));
|
|
2182
2286
|
});
|
|
2183
2287
|
}
|
|
2184
2288
|
}
|
|
2185
2289
|
}), array2(item.linkedAsks).forEach((value2) => {
|
|
2186
2290
|
let linked = object4(value2);
|
|
2187
2291
|
if (assert(id2(linked.id)), linked.state === "unavailable") assert(typeof linked.done == "boolean");
|
|
2188
|
-
else if (assert(["yours", "done", "open", "theirs"].includes(String(linked.state)) &&
|
|
2292
|
+
else if (assert(["yours", "done", "open", "theirs"].includes(String(linked.state)) && text4(linked.title)), linked.state === "theirs") {
|
|
2189
2293
|
let assignee = object4(linked.assignee);
|
|
2190
|
-
assert(id2(assignee.id) &&
|
|
2294
|
+
assert(id2(assignee.id) && text4(assignee.name));
|
|
2191
2295
|
}
|
|
2192
2296
|
}), array2(item.activity).forEach((value2) => {
|
|
2193
2297
|
let event = object4(value2);
|
|
2194
|
-
assert(integer(event.id) &&
|
|
2298
|
+
assert(integer(event.id) && text4(event.type) && (event.actorId === null || id2(event.actorId)) && (event.questionId === null || text4(event.questionId)) && integer(event.revision) && date(event.createdAt)), object4(event.data);
|
|
2195
2299
|
}), array2(item.work).forEach((value2) => {
|
|
2196
2300
|
let work = object4(value2);
|
|
2197
|
-
assert(id2(work.id) &&
|
|
2301
|
+
assert(id2(work.id) && text4(work.questionId) && text4(work.reason) && optionalDate(work.settledAt));
|
|
2198
2302
|
}), item;
|
|
2199
2303
|
}
|
|
2200
2304
|
function parseAnswerableQuestion(value) {
|
|
@@ -2203,13 +2307,13 @@ function parseAnswerableQuestion(value) {
|
|
|
2203
2307
|
entry,
|
|
2204
2308
|
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
|
|
2205
2309
|
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
|
|
2206
|
-
), assert(id2(entry.itemId) && integer(entry.revision) &&
|
|
2310
|
+
), assert(id2(entry.itemId) && integer(entry.revision) && text4(entry.title) && text4(entry.inboxUrl));
|
|
2207
2311
|
let link = new URL(entry.inboxUrl), slug = link.hostname.slice(0, -13);
|
|
2208
|
-
return assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && entry.inboxUrl === `https://${slug}.oddington.ai/inbox/${entry.itemId}`), assert(isAppRoutineName(entry.routine) &&
|
|
2312
|
+
return assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && entry.inboxUrl === `https://${slug}.oddington.ai/inbox/${entry.itemId}`), assert(isAppRoutineName(entry.routine) && text4(entry.questionId) && entry.questionId === entry.questionId.trim() && text4(entry.prompt) && (!("instructions" in entry) || text4(entry.instructions, !0)) && typeof entry.answerable == "boolean"), responseDefinition(entry.response), askMetadata(entry), entry;
|
|
2209
2313
|
}
|
|
2210
2314
|
function askMetadata(entry) {
|
|
2211
2315
|
let tags = array2(entry.tags === void 0 ? [] : entry.tags);
|
|
2212
|
-
assert(tags.length <= 32 && tags.every((tag) =>
|
|
2316
|
+
assert(tags.length <= 32 && tags.every((tag) => text4(tag) && new TextEncoder().encode(tag).byteLength <= 64)), assert(new Set(tags).size === tags.length);
|
|
2213
2317
|
let refs = array2(entry.recordRefs === void 0 ? [] : entry.recordRefs);
|
|
2214
2318
|
refs.forEach((value) => {
|
|
2215
2319
|
let ref = object4(value);
|
|
@@ -2221,7 +2325,7 @@ function askMetadata(entry) {
|
|
|
2221
2325
|
}
|
|
2222
2326
|
function parseInboxAcceptance(value) {
|
|
2223
2327
|
let accepted = object4(value);
|
|
2224
|
-
return assert(id2(accepted.responseId) && date(accepted.acceptedAt)), "executionId" in accepted && assert(id2(accepted.executionId)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder)), "label" in accepted && assert(
|
|
2328
|
+
return assert(id2(accepted.responseId) && date(accepted.acceptedAt)), "executionId" in accepted && assert(id2(accepted.executionId)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder)), "label" in accepted && assert(text4(accepted.label)), accepted;
|
|
2225
2329
|
}
|
|
2226
2330
|
function parseInboxResult(operation2, value) {
|
|
2227
2331
|
if (operation2 === "current") return parseInboxCurrent(value);
|
|
@@ -2252,7 +2356,7 @@ function parseInboxResult(operation2, value) {
|
|
|
2252
2356
|
let candidates = array2(value);
|
|
2253
2357
|
return candidates.forEach((value2) => {
|
|
2254
2358
|
let person = object4(value2);
|
|
2255
|
-
assert(id2(person.id) &&
|
|
2359
|
+
assert(id2(person.id) && text4(person.name) && text4(person.email));
|
|
2256
2360
|
}), assert(new Set(candidates.map((value2) => object4(value2).id)).size === candidates.length), candidates;
|
|
2257
2361
|
}
|
|
2258
2362
|
if (operation2 === "items.addRecipient") {
|
|
@@ -2262,10 +2366,10 @@ function parseInboxResult(operation2, value) {
|
|
|
2262
2366
|
if (operation2 === "questions.answer") return parseInboxAcceptance(value);
|
|
2263
2367
|
if (operation2 === "questions.searchRecords") {
|
|
2264
2368
|
let result2 = object4(value);
|
|
2265
|
-
assert(
|
|
2369
|
+
assert(text4(result2.recordType) && integer(result2.eligibleCount, 0) && integer(result2.matchCount, 0) && Number(result2.matchCount) <= Number(result2.eligibleCount));
|
|
2266
2370
|
let labeled = (value2) => {
|
|
2267
2371
|
let record3 = object4(value2);
|
|
2268
|
-
recordReference({ repository: record3.repository, ref: record3.ref }), assert(
|
|
2372
|
+
recordReference({ repository: record3.repository, ref: record3.ref }), assert(text4(record3.label)), "reason" in record3 && assert(text4(record3.reason));
|
|
2269
2373
|
};
|
|
2270
2374
|
return array2(result2.matches).forEach(labeled), array2(result2.suggestions).forEach(labeled), "selected" in result2 && labeled(result2.selected), result2;
|
|
2271
2375
|
}
|
|
@@ -2379,7 +2483,7 @@ async function appResponse(response2, maximum, signal) {
|
|
|
2379
2483
|
});
|
|
2380
2484
|
};
|
|
2381
2485
|
signal.addEventListener("abort", abort, { once: !0 });
|
|
2382
|
-
let bytes = 0,
|
|
2486
|
+
let bytes = 0, text5 = "", decoder = new TextDecoder("utf-8", { fatal: !0 });
|
|
2383
2487
|
try {
|
|
2384
2488
|
for (; ; ) {
|
|
2385
2489
|
let chunk;
|
|
@@ -2390,13 +2494,13 @@ async function appResponse(response2, maximum, signal) {
|
|
|
2390
2494
|
}
|
|
2391
2495
|
if (signal.aborted) throw new Error();
|
|
2392
2496
|
if (chunk.done) {
|
|
2393
|
-
let value = JSON.parse(
|
|
2497
|
+
let value = JSON.parse(text5 + decoder.decode());
|
|
2394
2498
|
if (await responseChecks.get(response2)?.(value), signal.aborted) throw new Error();
|
|
2395
2499
|
return value;
|
|
2396
2500
|
}
|
|
2397
2501
|
if (bytes += chunk.value.byteLength, bytes > maximum)
|
|
2398
2502
|
throw abort(), new Error();
|
|
2399
|
-
|
|
2503
|
+
text5 += decoder.decode(chunk.value, { stream: !0 });
|
|
2400
2504
|
}
|
|
2401
2505
|
} finally {
|
|
2402
2506
|
signal.removeEventListener("abort", abort), reader.releaseLock();
|
|
@@ -2622,16 +2726,16 @@ function appContext(origin, active2) {
|
|
|
2622
2726
|
return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, {}, !1, !0);
|
|
2623
2727
|
}
|
|
2624
2728
|
async function requestFiles(suffix, init2, parent) {
|
|
2625
|
-
let
|
|
2729
|
+
let unavailable4 = () => new FileOperationError("unsupported_context", 400);
|
|
2626
2730
|
if (!current2() || !/^(?:|\/[0-9a-f-]{36}(?:\/(?:content|upload|enrichments(?:\/[^/?#]+\/content)?))?)$/i.test(suffix))
|
|
2627
|
-
throw
|
|
2628
|
-
let admitted = credential, signal = parent ? AbortSignal.any([access.signal, parent]) : access.signal, failure = () => current2() && !signal.aborted ? new FileOperationError("unavailable", 503, !0) :
|
|
2731
|
+
throw unavailable4();
|
|
2732
|
+
let admitted = credential, signal = parent ? AbortSignal.any([access.signal, parent]) : access.signal, failure = () => current2() && !signal.aborted ? new FileOperationError("unavailable", 503, !0) : unavailable4();
|
|
2629
2733
|
try {
|
|
2630
2734
|
return await hostedContent("", init2, signal, (_url, request2) => untilAborted(
|
|
2631
2735
|
send3(`files${suffix}`, admitted, signal, request2).then((value) => {
|
|
2632
2736
|
if (signal.aborted)
|
|
2633
2737
|
throw value.body?.cancel().catch(() => {
|
|
2634
|
-
}),
|
|
2738
|
+
}), unavailable4();
|
|
2635
2739
|
return value;
|
|
2636
2740
|
}),
|
|
2637
2741
|
signal
|
|
@@ -2733,9 +2837,9 @@ function validPair(value) {
|
|
|
2733
2837
|
return validProof(pair.credential) && validProof(pair.renewalCredential) && pair.credential !== pair.renewalCredential && validBinding(pair.context);
|
|
2734
2838
|
}
|
|
2735
2839
|
|
|
2736
|
-
var
|
|
2840
|
+
var unavailable3 = () => new InboxOperationError(503, "unavailable"), stale = () => new InboxOperationError(401, "authority_unavailable");
|
|
2737
2841
|
function hostFailure(error, context2) {
|
|
2738
|
-
return !context2.isCurrent() || context2.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") :
|
|
2842
|
+
return !context2.isCurrent() || context2.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") : unavailable3();
|
|
2739
2843
|
}
|
|
2740
2844
|
async function send2(operation2, input) {
|
|
2741
2845
|
let envelope = parseInboxRequest({ operation: operation2, input }), context2;
|
|
@@ -2755,12 +2859,12 @@ async function send2(operation2, input) {
|
|
|
2755
2859
|
[400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
|
|
2756
2860
|
response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
|
|
2757
2861
|
);
|
|
2758
|
-
if (response2.status !== 200) throw
|
|
2862
|
+
if (response2.status !== 200) throw unavailable3();
|
|
2759
2863
|
let parsed = parseInboxResult(operation2, value);
|
|
2760
|
-
if (check2(), operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw
|
|
2864
|
+
if (check2(), operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw unavailable3();
|
|
2761
2865
|
return parsed;
|
|
2762
2866
|
} catch (error) {
|
|
2763
|
-
throw check2(), error instanceof InboxOperationError ? error :
|
|
2867
|
+
throw check2(), error instanceof InboxOperationError ? error : unavailable3();
|
|
2764
2868
|
}
|
|
2765
2869
|
}
|
|
2766
2870
|
if (context2.endpoint !== `https://${context2.workspace}.oddington.ai` || ["auth", "www", "api", "os"].includes(context2.workspace)) throw stale();
|
|
@@ -2771,7 +2875,7 @@ async function send2(operation2, input) {
|
|
|
2771
2875
|
} catch (error) {
|
|
2772
2876
|
throw hostFailure(error, context2);
|
|
2773
2877
|
}
|
|
2774
|
-
if (!host) throw
|
|
2878
|
+
if (!host) throw unavailable3();
|
|
2775
2879
|
}
|
|
2776
2880
|
let check = () => {
|
|
2777
2881
|
if (!context2.isCurrent() || host && !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
|
|
@@ -2801,9 +2905,9 @@ async function send2(operation2, input) {
|
|
|
2801
2905
|
);
|
|
2802
2906
|
if (response2.status !== 200)
|
|
2803
2907
|
throw response2.body?.cancel().catch(() => {
|
|
2804
|
-
}),
|
|
2908
|
+
}), unavailable3();
|
|
2805
2909
|
if (operation2 === "files.read") {
|
|
2806
|
-
if (!response2.body) throw
|
|
2910
|
+
if (!response2.body) throw unavailable3();
|
|
2807
2911
|
let source = response2.body, reader, size = 0, cancel = async (reason) => {
|
|
2808
2912
|
try {
|
|
2809
2913
|
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
@@ -2819,7 +2923,7 @@ async function send2(operation2, input) {
|
|
|
2819
2923
|
reader.releaseLock(), controller.close();
|
|
2820
2924
|
return;
|
|
2821
2925
|
}
|
|
2822
|
-
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw
|
|
2926
|
+
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw unavailable3();
|
|
2823
2927
|
controller.enqueue(next.value);
|
|
2824
2928
|
} catch (error) {
|
|
2825
2929
|
controller.error(error), await cancel(error).catch(() => {
|
|
@@ -2831,16 +2935,16 @@ async function send2(operation2, input) {
|
|
|
2831
2935
|
return new Response(body, { status: response2.status, headers: response2.headers });
|
|
2832
2936
|
}
|
|
2833
2937
|
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
2834
|
-
if (check(), !bytes) throw
|
|
2938
|
+
if (check(), !bytes) throw unavailable3();
|
|
2835
2939
|
let value = JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)), parsed = parseInboxResult(operation2, value);
|
|
2836
|
-
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw
|
|
2940
|
+
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw unavailable3();
|
|
2837
2941
|
if ("itemId" in envelope.input) {
|
|
2838
2942
|
let item = operation2 === "items.read" ? parsed : operation2 === "items.rename" || operation2 === "items.setLifecycle" || operation2 === "items.addRecipient" ? parsed.item : void 0;
|
|
2839
|
-
if (item && (item.id !== envelope.input.itemId || "revision" in envelope.input && item.revision !== envelope.input.revision) || operation2 === "items.addRecipient" && parsed.addedPersonId !== envelope.input.personId || operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw
|
|
2943
|
+
if (item && (item.id !== envelope.input.itemId || "revision" in envelope.input && item.revision !== envelope.input.revision) || operation2 === "items.addRecipient" && parsed.addedPersonId !== envelope.input.personId || operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw unavailable3();
|
|
2840
2944
|
}
|
|
2841
2945
|
return parsed;
|
|
2842
2946
|
} catch (error) {
|
|
2843
|
-
throw check(), error instanceof InboxOperationError ? error :
|
|
2947
|
+
throw check(), error instanceof InboxOperationError ? error : unavailable3();
|
|
2844
2948
|
}
|
|
2845
2949
|
}
|
|
2846
2950
|
var inbox = {
|
|
@@ -2860,14 +2964,14 @@ var inbox = {
|
|
|
2860
2964
|
throw hostFailure(error, initial);
|
|
2861
2965
|
}
|
|
2862
2966
|
if (initial.kind === "local") throw new InboxOperationError(403, "access_denied");
|
|
2863
|
-
if (!host) throw
|
|
2967
|
+
if (!host) throw unavailable3();
|
|
2864
2968
|
let check = () => {
|
|
2865
2969
|
if (!initial.isCurrent() || !host.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
|
|
2866
2970
|
};
|
|
2867
2971
|
do {
|
|
2868
2972
|
check();
|
|
2869
2973
|
let page = await send2("items.list", beforeNumber === void 0 ? {} : { beforeNumber });
|
|
2870
|
-
if (check(), beforeNumber !== void 0 && (page.items.some((item) => item.number >= beforeNumber) || page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber)) throw
|
|
2974
|
+
if (check(), beforeNumber !== void 0 && (page.items.some((item) => item.number >= beforeNumber) || page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber)) throw unavailable3();
|
|
2871
2975
|
if (items.push(...page.items), page.nextBeforeNumber === null) return items;
|
|
2872
2976
|
beforeNumber = page.nextBeforeNumber;
|
|
2873
2977
|
} while (!0);
|
|
@@ -2901,7 +3005,7 @@ var inbox = {
|
|
|
2901
3005
|
routines,
|
|
2902
3006
|
...beforeNumber === void 0 ? {} : { beforeNumber }
|
|
2903
3007
|
});
|
|
2904
|
-
if (check(), page.questions.some((question2) => question2.inboxUrl !== `https://${initial.workspace}.oddington.ai/inbox/${question2.itemId}` || !routines.includes(question2.routine)) || beforeNumber !== void 0 && page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber) throw
|
|
3008
|
+
if (check(), page.questions.some((question2) => question2.inboxUrl !== `https://${initial.workspace}.oddington.ai/inbox/${question2.itemId}` || !routines.includes(question2.routine)) || beforeNumber !== void 0 && page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber) throw unavailable3();
|
|
2905
3009
|
if (questions.push(...page.questions), page.nextBeforeNumber === null) return questions;
|
|
2906
3010
|
beforeNumber = page.nextBeforeNumber;
|
|
2907
3011
|
} while (!0);
|
|
@@ -3483,7 +3587,7 @@ function handle(key, id3, context2) {
|
|
|
3483
3587
|
async function describeAppRoutine(key) {
|
|
3484
3588
|
let descriptor = appDescriptors().find((item) => item.id === key);
|
|
3485
3589
|
if (!descriptor) return fail3("authority_unavailable");
|
|
3486
|
-
let
|
|
3590
|
+
let unavailable4 = () => ({
|
|
3487
3591
|
...structuredClone(descriptor),
|
|
3488
3592
|
connections: descriptor.connections.map((connection) => ({ ...connection, available: !1 })),
|
|
3489
3593
|
readiness: { state: "unavailable", reason: "capability_unavailable", message: "Routine capability unavailable." }
|
|
@@ -3492,11 +3596,11 @@ async function describeAppRoutine(key) {
|
|
|
3492
3596
|
let value = await request(key, "describe", void 0, 1048576);
|
|
3493
3597
|
return (!only(value, "id,title,input,connections,steps,readiness") || !value.readiness || !Array.isArray(value.connections) || structure({ ...value, readiness: void 0, connections: value.connections.map(({ available, ...item }) => item) }) !== structure(descriptor) || value.connections.some((item) => typeof item.available != "boolean") || !(value.readiness.state === "ready" && only(value.readiness, "state,placement") && value.readiness.placement === "local" || value.readiness.state === "unavailable" && only(value.readiness, "state,reason,message") && ["not_deployed", "definition_invalid", "capability_unavailable"].includes(value.readiness.reason) && message(value.readiness.message))) && fail3("execution_unavailable"), value;
|
|
3494
3598
|
} catch {
|
|
3495
|
-
return
|
|
3599
|
+
return unavailable4();
|
|
3496
3600
|
}
|
|
3497
3601
|
}
|
|
3498
3602
|
function appRoutineBinding(key) {
|
|
3499
|
-
return Object.freeze({
|
|
3603
|
+
return (typeof key != "string" || !identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable"), Object.freeze({
|
|
3500
3604
|
describe: () => describeAppRoutine(key),
|
|
3501
3605
|
async run(...args) {
|
|
3502
3606
|
args.length > 1 && fail3("invalid_input");
|
|
@@ -3530,6 +3634,7 @@ function appRoutineBinding(key) {
|
|
|
3530
3634
|
|
|
3531
3635
|
var app = Object.freeze({
|
|
3532
3636
|
listRoutines: () => Promise.all(appDescriptors().map(({ id: id3 }) => describeAppRoutine(id3))),
|
|
3637
|
+
routine: appRoutineBinding,
|
|
3533
3638
|
routines: new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
3534
3639
|
get(_target, key) {
|
|
3535
3640
|
if (!(typeof key != "string" || !appDescriptors().some((item) => item.id === key)))
|
|
@@ -3569,10 +3674,10 @@ function routineDataEnvelope(command) {
|
|
|
3569
3674
|
}
|
|
3570
3675
|
|
|
3571
3676
|
function routinePublicationClient2(options = {}) {
|
|
3572
|
-
let environment = {}, installed2 = routineTransport(), local3 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.
|
|
3677
|
+
let environment = {}, installed2 = routineTransport(), local3 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.OS_ROUTINE_WORKSPACE, capability = options.capability ?? environment.OS_ROUTINE_RUN;
|
|
3573
3678
|
if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
|
|
3574
3679
|
throw new Error("A workspace and valid optional routine capability are required");
|
|
3575
|
-
let workingRoot = options.workingRoot ?? environment.
|
|
3680
|
+
let workingRoot = options.workingRoot ?? environment.OS_INBOX_WORKING_ROOT ?? void 0, headers = capability ? { "x-os-run": capability } : {}, request2 = options.request ?? (capability ? async (path, init2) => {
|
|
3576
3681
|
if (path === "/api/data") return fetch(`https://${workspace}.oddington.ai/api/data`, { ...init2, redirect: "error" });
|
|
3577
3682
|
let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
|
|
3578
3683
|
if (workspace.length > 63 || ["auth", "www", "api", "os"].includes(workspace) || target.origin !== origin || target.search || target.hash || target.username || target.password || !/^\/api\/inbox\/(check|publish|resolve|files)$/.test(path) || init2?.method !== "POST")
|
|
@@ -3588,7 +3693,7 @@ function routinePublicationClient2(options = {}) {
|
|
|
3588
3693
|
headers: {
|
|
3589
3694
|
"content-type": "application/json",
|
|
3590
3695
|
...headers,
|
|
3591
|
-
...writing || reading ? { "x-
|
|
3696
|
+
...writing || reading ? { "x-os-workspace": workspace, "x-os-captured-records": "1" } : {}
|
|
3592
3697
|
},
|
|
3593
3698
|
body: JSON.stringify(writing ? routineDataEnvelope(validateRoutineRecordWrite(body)) : reading ? { operation: "records.select", request: validateRecordRead(body) } : body)
|
|
3594
3699
|
}), result2 = await response2.json();
|