@oddington/sdk 0.1.22 → 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/README.md +55 -6
- package/dist/browser.js +501 -287
- package/dist/index.js +10 -10
- package/dist/types/packages/sdk/src/public.d.ts +12 -2
- package/dist/types/packages/sdk/src/routine-definition-types.d.ts +12 -2
- package/dist/types/shared/airtable-contract.d.ts +1 -0
- package/dist/types/shared/app-descriptor.d.ts +3 -0
- package/dist/types/shared/app-routine-contract.d.ts +1 -0
- package/dist/types/shared/connection-runtime.d.ts +20 -0
- package/dist/types/shared/data-contract.d.ts +24 -2
- package/dist/types/shared/inbox-contract.d.ts +9 -1
- package/dist/types/shared/inbox-member-types.d.ts +15 -2
- package/package.json +2 -2
package/dist/browser.js
CHANGED
|
@@ -285,7 +285,7 @@ function validatePublication(value) {
|
|
|
285
285
|
"views",
|
|
286
286
|
"body",
|
|
287
287
|
"notifyImmediately",
|
|
288
|
-
...source.kind === "ask" ? ["questions"] : []
|
|
288
|
+
...source.kind === "ask" ? ["questions", "tags", "recordRefs"] : []
|
|
289
289
|
], "publication"), source.notifyImmediately !== void 0 && typeof source.notifyImmediately != "boolean" && fail("notifyImmediately must be a boolean");
|
|
290
290
|
let itemPresentation = { ...presentation(source), ...source.notifyImmediately === void 0 ? {} : { notifyImmediately: source.notifyImmediately } }, linkedAsks = (itemPresentation.body ?? []).flatMap((block2) => block2.kind === "asks" ? block2.asks : []);
|
|
291
291
|
if (new Set(linkedAsks).size !== linkedAsks.length && fail("Ask belongs to more than one problem"), source.kind === "digest") return {
|
|
@@ -297,10 +297,24 @@ function validatePublication(value) {
|
|
|
297
297
|
let questions = array(source.questions === void 0 ? [] : source.questions, "questions").map((value2) => question(value2));
|
|
298
298
|
new Set(questions.map((entry) => entry.id)).size !== questions.length && fail("Duplicate question ID");
|
|
299
299
|
let extra = source.recipients === void 0 ? [] : distinctPeople(source.recipients, "recipients", !1);
|
|
300
|
-
|
|
300
|
+
!questions.length && !extra.length && fail("Ask requires at least one recipient");
|
|
301
|
+
let tags = array(source.tags === void 0 ? [] : source.tags, "Ask tags").map((value2) => {
|
|
302
|
+
let tag = text(value2, "Ask tag");
|
|
303
|
+
return new TextEncoder().encode(tag).byteLength > 64 && fail("Ask tag exceeds 64 UTF-8 bytes"), tag;
|
|
304
|
+
});
|
|
305
|
+
(tags.length > 32 || new Set(tags).size !== tags.length) && fail("Ask tags exceed bounds or contain duplicates");
|
|
306
|
+
let recordRefs = array(source.recordRefs === void 0 ? [] : source.recordRefs, "Ask Record references").map((value2) => {
|
|
307
|
+
let row = object(value2, "Ask Record reference");
|
|
308
|
+
keys(row, ["repository", "id"], "Ask Record reference");
|
|
309
|
+
let { repository, ref } = validateRecordReference({ repository: row.repository, ref: row.id });
|
|
310
|
+
return { repository, id: ref };
|
|
311
|
+
});
|
|
312
|
+
return new Set(recordRefs.map((ref) => JSON.stringify([ref.repository, ref.id]))).size !== recordRefs.length && fail("Ask Record references contain duplicates"), {
|
|
301
313
|
kind: "ask",
|
|
302
314
|
...itemPresentation,
|
|
303
315
|
questions,
|
|
316
|
+
tags,
|
|
317
|
+
recordRefs,
|
|
304
318
|
recipients: [.../* @__PURE__ */ new Set([...extra, ...questions.flatMap((entry) => [entry.to, ...entry.allowedResponders])])]
|
|
305
319
|
};
|
|
306
320
|
}
|
|
@@ -335,7 +349,7 @@ function createInboxPublisher(transport) {
|
|
|
335
349
|
return {
|
|
336
350
|
async publishAsk(value, options) {
|
|
337
351
|
let source = object(value, "ask");
|
|
338
|
-
keys(source, ["title", "description", "recipients", "views", "body", "questions", "notifyImmediately"], "ask");
|
|
352
|
+
keys(source, ["title", "description", "recipients", "views", "body", "questions", "notifyImmediately", "tags", "recordRefs"], "ask");
|
|
339
353
|
let result2 = await transport.publish({
|
|
340
354
|
requestKey: publicationRequestKey(options),
|
|
341
355
|
item: validatePublication({ ...source, kind: "ask" })
|
|
@@ -391,44 +405,44 @@ var FileOperationError = class extends Error {
|
|
|
391
405
|
retryable;
|
|
392
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;
|
|
393
407
|
function parseFileDescriptor(value) {
|
|
394
|
-
let
|
|
408
|
+
let invalid8 = () => {
|
|
395
409
|
throw new FileOperationError("unavailable", 503, !0);
|
|
396
410
|
};
|
|
397
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
411
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
398
412
|
let f = value;
|
|
399
|
-
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();
|
|
400
414
|
let d = f.details;
|
|
401
415
|
if (d.kind === "other") {
|
|
402
|
-
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();
|
|
403
417
|
} else if (d.kind === "csv") {
|
|
404
|
-
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();
|
|
405
419
|
} else if (d.kind === "pdf") {
|
|
406
|
-
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
|
|
407
|
-
} 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();
|
|
408
422
|
for (let [name, descriptor] of Object.entries(f.enrichments)) {
|
|
409
|
-
if (!safeEnrichmentName(name)) return
|
|
423
|
+
if (!safeEnrichmentName(name)) return invalid8();
|
|
410
424
|
parseEnrichmentDescriptor(descriptor);
|
|
411
425
|
}
|
|
412
|
-
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ?
|
|
426
|
+
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid8() : f;
|
|
413
427
|
}
|
|
414
428
|
function parseEnrichmentDescriptor(value) {
|
|
415
|
-
let
|
|
429
|
+
let invalid8 = () => {
|
|
416
430
|
throw new FileOperationError("unavailable", 503, !0);
|
|
417
431
|
};
|
|
418
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
432
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
419
433
|
let d = value;
|
|
420
|
-
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;
|
|
421
435
|
}
|
|
422
436
|
function safeEnrichmentName(value) {
|
|
423
437
|
return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
|
|
424
438
|
}
|
|
425
439
|
function parseFileEnrichMetadata(value, maxBytes) {
|
|
426
|
-
let
|
|
440
|
+
let invalid8 = () => {
|
|
427
441
|
throw new FileOperationError("invalid_input", 400);
|
|
428
442
|
};
|
|
429
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
443
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
430
444
|
let d = value;
|
|
431
|
-
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();
|
|
432
446
|
if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
433
447
|
return d;
|
|
434
448
|
}
|
|
@@ -439,23 +453,23 @@ function safeFilePath(value) {
|
|
|
439
453
|
return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
|
|
440
454
|
}
|
|
441
455
|
function parseFileCreateMetadata(value, maxBytes) {
|
|
442
|
-
let
|
|
456
|
+
let invalid8 = () => {
|
|
443
457
|
throw new FileOperationError("invalid_input", 400);
|
|
444
458
|
};
|
|
445
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
459
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
446
460
|
let input = value;
|
|
447
|
-
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();
|
|
448
462
|
let path = input.path === void 0 ? "Files" : input.path;
|
|
449
|
-
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();
|
|
450
464
|
if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
451
|
-
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();
|
|
452
466
|
let csv;
|
|
453
467
|
if (input.csv !== void 0) {
|
|
454
|
-
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();
|
|
455
469
|
let hints = input.csv;
|
|
456
|
-
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();
|
|
457
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;
|
|
458
|
-
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();
|
|
459
473
|
csv = { encoding, delimiter, headerRow };
|
|
460
474
|
}
|
|
461
475
|
return {
|
|
@@ -517,8 +531,9 @@ function parseAppRoutineContract(value) {
|
|
|
517
531
|
case "array":
|
|
518
532
|
return !fields2(value2, ["type", "items", "maxItems"]) || !Number.isSafeInteger(value2.maxItems) || value2.maxItems < 1 || value2.maxItems > 64 ? invalidContract() : { type: "array", items: schema2(value2.items, depth + 1), maxItems: value2.maxItems };
|
|
519
533
|
case "boolean":
|
|
520
|
-
case "file":
|
|
521
534
|
return fields2(value2, ["type"]) ? { type: value2.type } : invalidContract();
|
|
535
|
+
case "file":
|
|
536
|
+
return !fields2(value2, ["type"], ["storage"]) || owns(value2, "storage") && value2.storage !== "local" && value2.storage !== "remote" ? invalidContract() : { type: "file", ...owns(value2, "storage") ? { storage: value2.storage } : {} };
|
|
522
537
|
case "string":
|
|
523
538
|
return !fields2(value2, ["type"], ["maxLength"]) || owns(value2, "maxLength") && (!Number.isSafeInteger(value2.maxLength) || value2.maxLength < 0 || value2.maxLength > 4096) ? invalidContract() : { type: "string", ...owns(value2, "maxLength") ? { maxLength: value2.maxLength } : {} };
|
|
524
539
|
case "integer":
|
|
@@ -716,7 +731,7 @@ var schema = {
|
|
|
716
731
|
boolean() {
|
|
717
732
|
return declaration({ type: "boolean" });
|
|
718
733
|
}
|
|
719
|
-
}, file = () => declaration({ type: "file" }), definitions = /* @__PURE__ */ new WeakMap(), defineRoutine = (definition) => {
|
|
734
|
+
}, file = (options = {}) => (assertRoutineFields(options, ["storage"]), declaration({ type: "file", ...options })), definitions = /* @__PURE__ */ new WeakMap(), defineRoutine = (definition) => {
|
|
720
735
|
if (assertRoutineFields(definition, ["id", "title", "input", "steps", "result", "access", "responses", "run"]), !isAppRoutineName(definition.id) || definition.title !== void 0 && !routineTitle(definition.title) || typeof definition.run != "function") return invalidContract3();
|
|
721
736
|
let input = definition.input === void 0 ? { schema: empty, default: {} } : schemaMetadata(definition.input), result2 = definition.result === void 0 ? void 0 : schemaMetadata(definition.result).schema, access = parseRoutineAccess(definition.access);
|
|
722
737
|
assertRoutineFields(definition.steps ?? {});
|
|
@@ -795,6 +810,12 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
795
810
|
...guarded({
|
|
796
811
|
...runtime,
|
|
797
812
|
run: freezeRoutineMetadata({ ...runtime.run }),
|
|
813
|
+
connections: { ...runtime.connections, get: async (identity) => {
|
|
814
|
+
if (!active2 || broken || !contract.access.connections?.includes(identity)) throw new Error("Connection unavailable");
|
|
815
|
+
let value = await runtime.connections.get(identity);
|
|
816
|
+
if (!active2 || broken) throw new Error("Run authority ended");
|
|
817
|
+
return value;
|
|
818
|
+
} },
|
|
798
819
|
inbox: { ...runtime.inbox, publishAsk: (value, options) => runtime.inbox.publishAsk(qualify(value), options) }
|
|
799
820
|
}),
|
|
800
821
|
step(id3, ...input2) {
|
|
@@ -936,6 +957,15 @@ function captureRecordsSearchInput(query, options) {
|
|
|
936
957
|
return { query, options: captured };
|
|
937
958
|
}
|
|
938
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
|
+
|
|
939
969
|
var DATA_REQUEST_LIMIT = 256 * 1024, invalidChange = () => {
|
|
940
970
|
throw new DataOperationError("invalid_change", !1, "unapplied");
|
|
941
971
|
};
|
|
@@ -1029,16 +1059,16 @@ function routineTransport() {
|
|
|
1029
1059
|
return installed;
|
|
1030
1060
|
}
|
|
1031
1061
|
|
|
1032
|
-
var memberContext;
|
|
1033
|
-
function installMemberContext(resolve) {
|
|
1034
|
-
return memberContext = resolve, () => {
|
|
1035
|
-
memberContext === resolve && (memberContext = void 0);
|
|
1062
|
+
var memberContext, retainedContext;
|
|
1063
|
+
function installMemberContext(resolve, retained = resolve) {
|
|
1064
|
+
return memberContext = resolve, retainedContext = retained, () => {
|
|
1065
|
+
memberContext === resolve && (memberContext = void 0, retainedContext = void 0);
|
|
1036
1066
|
};
|
|
1037
1067
|
}
|
|
1038
|
-
async function resolveAppContext() {
|
|
1068
|
+
async function resolveAppContext(retained = !1) {
|
|
1039
1069
|
let host = memberContext;
|
|
1040
1070
|
if (!host) throw new Error("App context unavailable.");
|
|
1041
|
-
let context2 = await host();
|
|
1071
|
+
let context2 = await (retained ? retainedContext : host)();
|
|
1042
1072
|
if (host !== memberContext || !context2.isCurrent() || context2.expiresAt <= Date.now() || context2.kind !== "local" && (typeof context2.accessToken != "string" || !/^[^\s]{1,8192}$/.test(context2.accessToken)))
|
|
1043
1073
|
throw new Error("App context unavailable.");
|
|
1044
1074
|
return context2;
|
|
@@ -1063,13 +1093,22 @@ async function resolveFilesContext() {
|
|
|
1063
1093
|
let environment = {}, host = memberContext;
|
|
1064
1094
|
if (host) {
|
|
1065
1095
|
let context2 = await host();
|
|
1066
|
-
if (context2.
|
|
1096
|
+
if (host !== memberContext || !context2.isCurrent() || context2.expiresAt <= Date.now()) throw new Error();
|
|
1097
|
+
if (context2.kind === "local") return {
|
|
1098
|
+
url: `private:app:${context2.workspace}/${context2.memberId}`,
|
|
1099
|
+
headers: {},
|
|
1100
|
+
isCurrent: context2.isCurrent,
|
|
1101
|
+
signal: context2.signal,
|
|
1102
|
+
local: void 0,
|
|
1103
|
+
localFiles: context2.requestFiles
|
|
1104
|
+
};
|
|
1067
1105
|
if (!Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now() || typeof context2.accessToken != "string" || !/^[^\s]{1,8192}$/.test(context2.accessToken)) throw new Error();
|
|
1068
1106
|
return {
|
|
1069
1107
|
...filesContext(context2.workspace, context2.endpoint, { authorization: `Bearer ${context2.accessToken}` }),
|
|
1070
1108
|
isCurrent: context2.isCurrent,
|
|
1071
1109
|
local: void 0,
|
|
1072
|
-
localFiles: void 0
|
|
1110
|
+
localFiles: void 0,
|
|
1111
|
+
signal: void 0
|
|
1073
1112
|
};
|
|
1074
1113
|
}
|
|
1075
1114
|
throw new Error();
|
|
@@ -1079,14 +1118,102 @@ async function resolveFilesContext() {
|
|
|
1079
1118
|
}
|
|
1080
1119
|
function filesContext(workspace, endpoint, headers) {
|
|
1081
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();
|
|
1082
|
-
return { url: `${endpoint}/api/files`, headers: { ...headers, "x-
|
|
1121
|
+
return { url: `${endpoint}/api/files`, headers: { ...headers, "x-os-workspace": workspace }, isCurrent: () => !0 };
|
|
1083
1122
|
}
|
|
1084
1123
|
function checked(workspace, endpoint, headers) {
|
|
1085
1124
|
if (!workspace || !/^[a-z0-9][a-z0-9-]{0,127}$/.test(workspace)) throw new Error();
|
|
1086
1125
|
let origin = new URL(endpoint);
|
|
1087
1126
|
if (origin.protocol !== "https:" || origin.username || origin.password || origin.search || origin.hash || origin.pathname !== "/")
|
|
1088
1127
|
throw new Error();
|
|
1089
|
-
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 };
|
|
1090
1217
|
}
|
|
1091
1218
|
|
|
1092
1219
|
var data = {
|
|
@@ -1109,13 +1236,20 @@ var data = {
|
|
|
1109
1236
|
throw error instanceof DataOperationError ? error : new DataOperationError("unavailable", !0);
|
|
1110
1237
|
}
|
|
1111
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 });
|
|
1112
1244
|
return {
|
|
1113
1245
|
collections: {
|
|
1114
1246
|
list: () => send3({ operation: "collections.list" }),
|
|
1115
1247
|
schema: (name) => send3({ operation: "collections.schema", name })
|
|
1116
1248
|
},
|
|
1117
1249
|
records: {
|
|
1118
|
-
|
|
1250
|
+
read: read2,
|
|
1251
|
+
select,
|
|
1252
|
+
...recordPagination(select),
|
|
1119
1253
|
search: async (query, options) => send3({ operation: "records.search", ...captureRecordsSearchInput(query, options) })
|
|
1120
1254
|
},
|
|
1121
1255
|
history: {
|
|
@@ -1182,7 +1316,65 @@ var data = {
|
|
|
1182
1316
|
}
|
|
1183
1317
|
};
|
|
1184
1318
|
|
|
1185
|
-
|
|
1319
|
+
async function hostedContent(url, init2, parent, upstream = fetch, check = async () => {
|
|
1320
|
+
}, failure) {
|
|
1321
|
+
let delivery = new AbortController(), abort = () => delivery.abort(parent.reason);
|
|
1322
|
+
parent.addEventListener("abort", abort, { once: !0 }), parent.aborted && abort();
|
|
1323
|
+
let detach = () => parent.removeEventListener("abort", abort);
|
|
1324
|
+
try {
|
|
1325
|
+
let response2 = await upstream(url, { ...init2, signal: delivery.signal });
|
|
1326
|
+
try {
|
|
1327
|
+
if (await check(), delivery.signal.aborted) throw failure?.() ?? new FileOperationError("unavailable", 503, !0);
|
|
1328
|
+
} catch (error) {
|
|
1329
|
+
throw response2.body?.cancel().catch(() => {
|
|
1330
|
+
}), error;
|
|
1331
|
+
}
|
|
1332
|
+
if (!response2.body)
|
|
1333
|
+
return detach(), response2;
|
|
1334
|
+
let source = response2.body, reader, settled = !1, output, cancel = async (reason) => {
|
|
1335
|
+
if (!settled) {
|
|
1336
|
+
settled = !0, detach(), delivery.signal.removeEventListener("abort", stop), delivery.abort(reason);
|
|
1337
|
+
try {
|
|
1338
|
+
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
if (error !== delivery.signal.reason && !(error instanceof Error && error.name === "AbortError")) throw error;
|
|
1341
|
+
} finally {
|
|
1342
|
+
reader?.releaseLock();
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}, stop = () => {
|
|
1346
|
+
if (settled) return;
|
|
1347
|
+
let error = failure?.() ?? delivery.signal.reason;
|
|
1348
|
+
cancel(error).catch(() => {
|
|
1349
|
+
}), output.error(error);
|
|
1350
|
+
}, body = new ReadableStream({
|
|
1351
|
+
start(controller) {
|
|
1352
|
+
output = controller, delivery.signal.addEventListener("abort", stop, { once: !0 }), delivery.signal.aborted && stop();
|
|
1353
|
+
},
|
|
1354
|
+
async pull(controller) {
|
|
1355
|
+
try {
|
|
1356
|
+
if (await check(), settled) return;
|
|
1357
|
+
reader ??= source.getReader();
|
|
1358
|
+
let { done, value } = await reader.read();
|
|
1359
|
+
if (await check(), settled) return;
|
|
1360
|
+
done ? (settled = !0, detach(), delivery.signal.removeEventListener("abort", stop), reader.releaseLock(), controller.close()) : controller.enqueue(value);
|
|
1361
|
+
} catch (error) {
|
|
1362
|
+
if (settled) return;
|
|
1363
|
+
controller.error(failure?.() ?? error), await cancel(error).catch(() => {
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1367
|
+
cancel
|
|
1368
|
+
}, { highWaterMark: 0 }), wrapped = new Response(body, { status: response2.status, statusText: response2.statusText, headers: response2.headers });
|
|
1369
|
+
for (let key of ["url", "redirected", "type"])
|
|
1370
|
+
Object.defineProperty(wrapped, key, { value: response2[key] });
|
|
1371
|
+
return wrapped;
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
throw detach(), delivery.abort(error), error;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
|
|
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 = {
|
|
1186
1378
|
400: ["invalid_input", "unsupported_context"],
|
|
1187
1379
|
401: ["unauthenticated"],
|
|
1188
1380
|
403: ["access_denied"],
|
|
@@ -1192,26 +1384,33 @@ var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES =
|
|
|
1192
1384
|
429: ["capacity"],
|
|
1193
1385
|
503: ["integrity", "unavailable"]
|
|
1194
1386
|
};
|
|
1195
|
-
async function boundedBytes(stream, limit) {
|
|
1387
|
+
async function boundedBytes(stream, limit, signal) {
|
|
1196
1388
|
if (!stream) return new Uint8Array();
|
|
1197
|
-
let reader = stream.getReader(), bytes = new Uint8Array(limit), size = 0
|
|
1389
|
+
let reader = stream.getReader(), bytes = new Uint8Array(limit), size = 0, cancel = () => {
|
|
1390
|
+
reader.cancel().catch(() => {
|
|
1391
|
+
});
|
|
1392
|
+
};
|
|
1393
|
+
signal?.addEventListener("abort", cancel, { once: !0 }), signal?.aborted && cancel();
|
|
1198
1394
|
try {
|
|
1199
1395
|
for (; ; ) {
|
|
1200
1396
|
let { done, value } = await reader.read();
|
|
1397
|
+
if (signal?.aborted) throw unavailable2();
|
|
1201
1398
|
if (done) break;
|
|
1202
|
-
if (!(value instanceof Uint8Array)) throw
|
|
1399
|
+
if (!(value instanceof Uint8Array)) throw invalid7();
|
|
1203
1400
|
if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
|
|
1204
1401
|
bytes.set(value, size - value.byteLength);
|
|
1205
1402
|
}
|
|
1403
|
+
} catch (error) {
|
|
1404
|
+
throw cancel(), error;
|
|
1206
1405
|
} finally {
|
|
1207
|
-
reader.releaseLock();
|
|
1406
|
+
signal?.removeEventListener("abort", cancel), reader.releaseLock();
|
|
1208
1407
|
}
|
|
1209
1408
|
return bytes.slice(0, size);
|
|
1210
1409
|
}
|
|
1211
1410
|
async function timed(work, parent, timeout = TIMEOUT_MS) {
|
|
1212
1411
|
let controller = new AbortController(), timer, abort, expiry = new Promise((_, reject) => {
|
|
1213
1412
|
abort = () => {
|
|
1214
|
-
controller.abort(), reject(
|
|
1413
|
+
controller.abort(), reject(unavailable2());
|
|
1215
1414
|
}, timer = setTimeout(abort, timeout), parent?.addEventListener("abort", abort, { once: !0 }), parent?.aborted && abort();
|
|
1216
1415
|
});
|
|
1217
1416
|
try {
|
|
@@ -1225,56 +1424,12 @@ async function result(response2, maximum = RESULT_BYTES) {
|
|
|
1225
1424
|
let bytes = await boundedBytes(response2.body, maximum);
|
|
1226
1425
|
return JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes));
|
|
1227
1426
|
} catch {
|
|
1228
|
-
throw
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
async function hostedContent(url, init2, parent, upstream = fetch) {
|
|
1232
|
-
let delivery = new AbortController(), abort = () => delivery.abort(parent.reason);
|
|
1233
|
-
parent.addEventListener("abort", abort, { once: !0 }), parent.aborted && abort();
|
|
1234
|
-
let detach = () => parent.removeEventListener("abort", abort);
|
|
1235
|
-
try {
|
|
1236
|
-
let response2 = await upstream(url, { ...init2, signal: delivery.signal });
|
|
1237
|
-
if (delivery.signal.aborted)
|
|
1238
|
-
throw response2.body?.cancel().catch(() => {
|
|
1239
|
-
}), unavailable();
|
|
1240
|
-
if (!response2.body)
|
|
1241
|
-
return detach(), response2;
|
|
1242
|
-
let source = response2.body, reader, settled = !1, cancel = async (reason) => {
|
|
1243
|
-
if (!settled) {
|
|
1244
|
-
settled = !0, detach(), delivery.abort(reason);
|
|
1245
|
-
try {
|
|
1246
|
-
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
1247
|
-
} catch (error) {
|
|
1248
|
-
if (error !== delivery.signal.reason && !(error instanceof Error && error.name === "AbortError")) throw error;
|
|
1249
|
-
} finally {
|
|
1250
|
-
reader?.releaseLock();
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
}, body = new ReadableStream({
|
|
1254
|
-
async pull(controller) {
|
|
1255
|
-
try {
|
|
1256
|
-
reader ??= source.getReader();
|
|
1257
|
-
let { done, value } = await reader.read();
|
|
1258
|
-
if (settled) return;
|
|
1259
|
-
done ? (settled = !0, detach(), reader.releaseLock(), controller.close()) : controller.enqueue(value);
|
|
1260
|
-
} catch (error) {
|
|
1261
|
-
if (settled) return;
|
|
1262
|
-
controller.error(error), await cancel(error).catch(() => {
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
},
|
|
1266
|
-
cancel
|
|
1267
|
-
}, { highWaterMark: 0 }), wrapped = new Response(body, { status: response2.status, statusText: response2.statusText, headers: response2.headers });
|
|
1268
|
-
for (let key of ["url", "redirected", "type"])
|
|
1269
|
-
Object.defineProperty(wrapped, key, { value: response2[key] });
|
|
1270
|
-
return wrapped;
|
|
1271
|
-
} catch (error) {
|
|
1272
|
-
throw detach(), delivery.abort(error), error;
|
|
1427
|
+
throw unavailable2();
|
|
1273
1428
|
}
|
|
1274
1429
|
}
|
|
1275
1430
|
async function send(suffix, init2, descriptor, initial, parent) {
|
|
1276
1431
|
let original = initial, checkCurrent = (context2 = original) => {
|
|
1277
|
-
if (parent?.aborted) throw
|
|
1432
|
+
if (parent?.aborted) throw unavailable2();
|
|
1278
1433
|
if (!original.isCurrent() || context2.url !== original.url) throw new FileOperationError("unsupported_context", 400);
|
|
1279
1434
|
};
|
|
1280
1435
|
for (let attempt = 0; attempt < ATTEMPTS; attempt++) {
|
|
@@ -1282,7 +1437,7 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1282
1437
|
let context2 = await resolveFilesContext();
|
|
1283
1438
|
checkCurrent(context2);
|
|
1284
1439
|
try {
|
|
1285
|
-
let response2 = await (async () => {
|
|
1440
|
+
let response2 = context2.localFiles ? await context2.localFiles(suffix, init2, parent) : await (async () => {
|
|
1286
1441
|
let url = `${context2.url}${suffix}`, request2 = {
|
|
1287
1442
|
...init2,
|
|
1288
1443
|
signal: parent,
|
|
@@ -1294,11 +1449,11 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1294
1449
|
})();
|
|
1295
1450
|
if (!response2.ok) {
|
|
1296
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);
|
|
1297
|
-
throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") :
|
|
1452
|
+
throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") : unavailable2();
|
|
1298
1453
|
}
|
|
1299
1454
|
if (response2.status !== (descriptor === 204 ? 204 : 200) || descriptor === 204 && response2.body !== null)
|
|
1300
1455
|
throw response2.body?.cancel().catch(() => {
|
|
1301
|
-
}),
|
|
1456
|
+
}), unavailable2();
|
|
1302
1457
|
try {
|
|
1303
1458
|
checkCurrent();
|
|
1304
1459
|
} catch (error) {
|
|
@@ -1312,21 +1467,21 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1312
1467
|
return checkCurrent(), value;
|
|
1313
1468
|
let parsed;
|
|
1314
1469
|
if (descriptor === "enrichment") {
|
|
1315
|
-
if (!value || typeof value != "object" || Array.isArray(value)) throw
|
|
1470
|
+
if (!value || typeof value != "object" || Array.isArray(value)) throw unavailable2();
|
|
1316
1471
|
let { name, ...metadata } = value;
|
|
1317
|
-
if (!safeEnrichmentName(name)) throw
|
|
1472
|
+
if (!safeEnrichmentName(name)) throw unavailable2();
|
|
1318
1473
|
parsed = { name, ...parseEnrichmentDescriptor(metadata) };
|
|
1319
1474
|
} else parsed = parseFileDescriptor(value);
|
|
1320
1475
|
return checkCurrent(), parsed;
|
|
1321
1476
|
} catch (error) {
|
|
1322
|
-
let failure = error instanceof FileOperationError ? error :
|
|
1477
|
+
let failure = error instanceof FileOperationError ? error : unavailable2();
|
|
1323
1478
|
if (init2.body instanceof ReadableStream || !failure.retryable || attempt + 1 === ATTEMPTS) throw failure;
|
|
1324
1479
|
}
|
|
1325
1480
|
}
|
|
1326
|
-
throw
|
|
1481
|
+
throw unavailable2();
|
|
1327
1482
|
}
|
|
1328
1483
|
function idPath(id3) {
|
|
1329
|
-
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw
|
|
1484
|
+
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid7();
|
|
1330
1485
|
return `/${id3}`;
|
|
1331
1486
|
}
|
|
1332
1487
|
async function multipartCreate(input, metadata, exchange, release = () => {
|
|
@@ -1337,18 +1492,18 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1337
1492
|
return pending.add(task), task.then(() => pending.delete(task), () => pending.delete(task)), task;
|
|
1338
1493
|
}, void 0, timeout), control = (body) => ({
|
|
1339
1494
|
method: "POST",
|
|
1340
|
-
headers: { "content-type": "application/json", ...ticket ? { "x-
|
|
1495
|
+
headers: { "content-type": "application/json", ...ticket ? { "x-os-transfer": ticket } : {} },
|
|
1341
1496
|
body: JSON.stringify(body)
|
|
1342
1497
|
});
|
|
1343
1498
|
try {
|
|
1344
1499
|
let start = await request2((signal) => exchange(`${route}/start`, control(upload?.file ?? metadata), "control", signal));
|
|
1345
|
-
if (!start || typeof start != "object" || Array.isArray(start)) throw
|
|
1500
|
+
if (!start || typeof start != "object" || Array.isArray(start)) throw unavailable2();
|
|
1346
1501
|
let session = start;
|
|
1347
|
-
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();
|
|
1348
1503
|
ticket = session.ticket, input.file instanceof ReadableStream && (reader = input.file.getReader());
|
|
1349
1504
|
let lastProgress = Date.now(), next = async () => {
|
|
1350
1505
|
try {
|
|
1351
|
-
if (Date.now() - lastProgress >= TIMEOUT_MS) throw
|
|
1506
|
+
if (Date.now() - lastProgress >= TIMEOUT_MS) throw unavailable2();
|
|
1352
1507
|
let value = await request2(() => reader.read(), Math.max(1, TIMEOUT_MS - (Date.now() - lastProgress)));
|
|
1353
1508
|
return value.value?.byteLength && (lastProgress = Date.now()), value;
|
|
1354
1509
|
} catch (error) {
|
|
@@ -1369,41 +1524,41 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1369
1524
|
if (!chunk || offset === chunk.byteLength) {
|
|
1370
1525
|
chunk = void 0, offset = 0;
|
|
1371
1526
|
let value2 = await next();
|
|
1372
|
-
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();
|
|
1373
1528
|
}
|
|
1374
1529
|
let take = Math.min(length - filled, chunk.byteLength - offset);
|
|
1375
1530
|
part.set(chunk.subarray(offset, offset + take), filled), filled += take, offset += take, offset === chunk.byteLength && (chunk = void 0, offset = 0);
|
|
1376
1531
|
}
|
|
1377
1532
|
}
|
|
1378
|
-
if (part.byteLength !== length) throw
|
|
1533
|
+
if (part.byteLength !== length) throw invalid7();
|
|
1379
1534
|
if (reader && sent + length === metadata.size)
|
|
1380
1535
|
for (lastProgress = Date.now(); ; ) {
|
|
1381
1536
|
let value2 = await next();
|
|
1382
1537
|
if (value2.done) break;
|
|
1383
|
-
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw
|
|
1538
|
+
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid7();
|
|
1384
1539
|
}
|
|
1385
1540
|
let value = await request2((signal) => exchange(`${route}/part`, {
|
|
1386
1541
|
method: "POST",
|
|
1387
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1542
|
+
headers: { "content-type": "application/octet-stream", "x-os-transfer": ticket, "x-os-part": String(partNumber) },
|
|
1388
1543
|
body: part.buffer
|
|
1389
1544
|
}, "control", signal));
|
|
1390
1545
|
part = void 0;
|
|
1391
1546
|
let receipt = value;
|
|
1392
|
-
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();
|
|
1393
1548
|
receipts.push({ partNumber, etag: receipt.etag }), sent += length, lastProgress = Date.now();
|
|
1394
1549
|
}
|
|
1395
1550
|
if (upload) for (let name of Object.keys(upload.file.enrichments)) {
|
|
1396
1551
|
let bytes = await request2(() => upload.enrichment(name));
|
|
1397
|
-
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();
|
|
1398
1553
|
await request2((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
|
|
1399
1554
|
method: "POST",
|
|
1400
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1555
|
+
headers: { "content-type": "application/octet-stream", "x-os-transfer": ticket },
|
|
1401
1556
|
body: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
|
|
1402
1557
|
}, "control", signal));
|
|
1403
1558
|
}
|
|
1404
1559
|
await upload?.beforeComplete();
|
|
1405
1560
|
let completion = control({ parts: receipts });
|
|
1406
|
-
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw
|
|
1561
|
+
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw unavailable2();
|
|
1407
1562
|
return parseFileDescriptor(await request2(
|
|
1408
1563
|
(signal) => exchange(`${route}/complete`, completion, !0, signal),
|
|
1409
1564
|
TIMEOUT_MS + Math.ceil(metadata.size / (1024 * 1024)) * 1e3
|
|
@@ -1411,7 +1566,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1411
1566
|
} catch (error) {
|
|
1412
1567
|
throw reader && await reader.cancel(error).catch(() => {
|
|
1413
1568
|
}), ticket && await request2((signal) => exchange(`${route}/abort`, control({}), "control", signal)).catch(() => {
|
|
1414
|
-
}), error instanceof FileOperationError ? error :
|
|
1569
|
+
}), error instanceof FileOperationError ? error : unavailable2();
|
|
1415
1570
|
} finally {
|
|
1416
1571
|
chunk = void 0, reader?.releaseLock(), pending.size ? Promise.allSettled([...pending]).then(release) : release();
|
|
1417
1572
|
}
|
|
@@ -1419,20 +1574,22 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1419
1574
|
async function operation(work, initial, parent) {
|
|
1420
1575
|
let context2 = initial ?? await resolveFilesContext();
|
|
1421
1576
|
if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
|
|
1422
|
-
|
|
1577
|
+
active++;
|
|
1578
|
+
let execute = async (signal2) => {
|
|
1423
1579
|
try {
|
|
1424
|
-
return await work(context2,
|
|
1580
|
+
return await work(context2, signal2);
|
|
1425
1581
|
} finally {
|
|
1426
1582
|
active--;
|
|
1427
1583
|
}
|
|
1428
|
-
}, parent
|
|
1429
|
-
|
|
1584
|
+
}, signal = context2.signal && parent ? AbortSignal.any([context2.signal, parent]) : context2.signal ?? parent;
|
|
1585
|
+
return context2.localFiles ? execute(signal ?? new AbortController().signal) : timed(execute, signal).catch((error) => {
|
|
1586
|
+
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1430
1587
|
});
|
|
1431
1588
|
}
|
|
1432
1589
|
function contentPath(id3, name) {
|
|
1433
1590
|
let path = idPath(id3);
|
|
1434
1591
|
if (name === void 0) return `${path}/content`;
|
|
1435
|
-
if (!safeEnrichmentName(name)) throw
|
|
1592
|
+
if (!safeEnrichmentName(name)) throw invalid7();
|
|
1436
1593
|
return `${path}/enrichments/${encodeURIComponent(name)}/content`;
|
|
1437
1594
|
}
|
|
1438
1595
|
async function read(id3, names) {
|
|
@@ -1441,12 +1598,12 @@ async function read(id3, names) {
|
|
|
1441
1598
|
let path = contentPath(id3, names);
|
|
1442
1599
|
return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
|
|
1443
1600
|
}
|
|
1444
|
-
if (!Array.isArray(names)) throw
|
|
1601
|
+
if (!Array.isArray(names)) throw invalid7();
|
|
1445
1602
|
let distinct = [], seen = /* @__PURE__ */ new Set();
|
|
1446
1603
|
for (let name of names) {
|
|
1447
|
-
if (typeof name != "string" || !safeEnrichmentName(name)) throw
|
|
1604
|
+
if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid7();
|
|
1448
1605
|
if (!seen.has(name)) {
|
|
1449
|
-
if (seen.size === 16) throw
|
|
1606
|
+
if (seen.size === 16) throw invalid7();
|
|
1450
1607
|
seen.add(name), distinct.push(name);
|
|
1451
1608
|
}
|
|
1452
1609
|
}
|
|
@@ -1474,18 +1631,18 @@ var files = {
|
|
|
1474
1631
|
async upload(id3) {
|
|
1475
1632
|
return operation(async (context2, signal) => {
|
|
1476
1633
|
let file2 = await send(`${idPath(id3)}/upload`, { method: "POST" }, !0, context2, signal);
|
|
1477
|
-
if (file2.id !== id3) throw
|
|
1634
|
+
if (file2.id !== id3) throw unavailable2();
|
|
1478
1635
|
return file2;
|
|
1479
1636
|
});
|
|
1480
1637
|
},
|
|
1481
1638
|
async create(input, options) {
|
|
1482
1639
|
let context2 = await resolveFilesContext();
|
|
1483
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")))
|
|
1484
|
-
throw
|
|
1641
|
+
throw invalid7();
|
|
1485
1642
|
let blob = input.file instanceof Blob, array3 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
|
|
1486
|
-
if (!blob && !array3 && !stream) throw
|
|
1643
|
+
if (!blob && !array3 && !stream) throw invalid7();
|
|
1487
1644
|
let intrinsic = blob ? input.file.size : array3 ? input.file.byteLength : void 0;
|
|
1488
|
-
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();
|
|
1489
1646
|
let name = input.name;
|
|
1490
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));
|
|
1491
1648
|
let metadata = parseFileCreateMetadata({
|
|
@@ -1497,33 +1654,54 @@ var files = {
|
|
|
1497
1654
|
...blob && input.file.type === "application/pdf" ? { inputMediaType: "application/pdf" } : {},
|
|
1498
1655
|
requestKey: options?.requestKey === void 0 ? routineTransport()?.key("files") ?? crypto.randomUUID() : options.requestKey
|
|
1499
1656
|
}, FILE_ORIGINAL_MAX_BYTES);
|
|
1500
|
-
if (!context2.local && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
1657
|
+
if (!context2.local && !context2.localFiles && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
1501
1658
|
let header = encodeURIComponent(JSON.stringify(metadata));
|
|
1502
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1659
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1503
1660
|
if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
|
|
1504
|
-
|
|
1661
|
+
if (active++, context2.localFiles && !routineTransport() && metadata.size > MAX_BYTES) {
|
|
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({
|
|
1663
|
+
pull(controller) {
|
|
1664
|
+
if (offset === file2.byteLength) {
|
|
1665
|
+
controller.close();
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
let end = Math.min(offset + 256 * 1024, file2.byteLength);
|
|
1669
|
+
controller.enqueue(file2.subarray(offset, end)), offset = end;
|
|
1670
|
+
}
|
|
1671
|
+
}, { highWaterMark: 0 });
|
|
1672
|
+
try {
|
|
1673
|
+
return await send("", { method: "POST", headers: {
|
|
1674
|
+
"content-type": "application/octet-stream",
|
|
1675
|
+
"x-os-file": header
|
|
1676
|
+
}, body }, !0, context2, signal);
|
|
1677
|
+
} finally {
|
|
1678
|
+
active--;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return metadata.size > MAX_BYTES ? multipartCreate(input, metadata, (suffix, init2, kind, signal) => kind === !0 ? send(suffix, init2, !0, context2, signal) : send(suffix, init2, "control", context2, signal)) : timed(async (signal) => {
|
|
1505
1682
|
try {
|
|
1506
1683
|
let bytes = array3 ? input.file.slice() : await boundedBytes(
|
|
1507
1684
|
blob ? input.file.stream() : input.file,
|
|
1508
|
-
metadata.size
|
|
1685
|
+
metadata.size,
|
|
1686
|
+
signal
|
|
1509
1687
|
);
|
|
1510
|
-
if (bytes.byteLength !== metadata.size) throw
|
|
1511
|
-
if (signal.aborted) throw
|
|
1688
|
+
if (bytes.byteLength !== metadata.size) throw invalid7();
|
|
1689
|
+
if (signal.aborted) throw unavailable2();
|
|
1512
1690
|
return await send("", {
|
|
1513
1691
|
method: "POST",
|
|
1514
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1692
|
+
headers: { "content-type": "application/octet-stream", "x-os-file": header },
|
|
1515
1693
|
body: bytes.buffer
|
|
1516
1694
|
}, !0, context2, signal);
|
|
1517
1695
|
} finally {
|
|
1518
1696
|
active--;
|
|
1519
1697
|
}
|
|
1520
|
-
}).catch((error) => {
|
|
1521
|
-
throw error instanceof FileOperationError ? error :
|
|
1698
|
+
}, context2.signal).catch((error) => {
|
|
1699
|
+
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1522
1700
|
});
|
|
1523
1701
|
},
|
|
1524
1702
|
async enrich(input) {
|
|
1525
1703
|
let context2 = await resolveFilesContext();
|
|
1526
|
-
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();
|
|
1527
1705
|
let path = `${idPath(input.file)}/enrichments`;
|
|
1528
1706
|
if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
|
|
1529
1707
|
throw new FileOperationError("request_too_large", 413);
|
|
@@ -1540,12 +1718,12 @@ var files = {
|
|
|
1540
1718
|
...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
|
|
1541
1719
|
...input.replace === void 0 ? {} : { replace: input.replace }
|
|
1542
1720
|
}, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
|
|
1543
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1721
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1544
1722
|
let result2 = await send(path, { method: "POST", headers: {
|
|
1545
1723
|
"content-type": "application/octet-stream",
|
|
1546
|
-
"x-
|
|
1724
|
+
"x-os-enrichment": header
|
|
1547
1725
|
}, body: bytes.buffer }, "enrichment", context3, signal);
|
|
1548
|
-
if (result2.name !== metadata.name) throw
|
|
1726
|
+
if (result2.name !== metadata.name) throw unavailable2();
|
|
1549
1727
|
return result2;
|
|
1550
1728
|
}, context2);
|
|
1551
1729
|
},
|
|
@@ -1559,8 +1737,26 @@ function validGoogleScopes(value) {
|
|
|
1559
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;
|
|
1560
1738
|
}
|
|
1561
1739
|
|
|
1562
|
-
var ROUTINE_CONNECTION_CREDENTIALS_ENV = "
|
|
1740
|
+
var ROUTINE_CONNECTION_CREDENTIALS_ENV = "OS_ROUTINE_CONNECTION_CREDENTIALS";
|
|
1563
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);
|
|
1742
|
+
function runtimeConnection(lease) {
|
|
1743
|
+
return lease.provider === "gmail" ? {
|
|
1744
|
+
id: `gmail/${lease.name}`,
|
|
1745
|
+
provider: lease.provider,
|
|
1746
|
+
name: lease.name,
|
|
1747
|
+
accountEmail: lease.accountEmail,
|
|
1748
|
+
scopes: [...lease.scopes],
|
|
1749
|
+
accessToken: lease.accessToken,
|
|
1750
|
+
expiresAt: lease.expiresAt
|
|
1751
|
+
} : {
|
|
1752
|
+
id: `airtable/${lease.name}`,
|
|
1753
|
+
provider: lease.provider,
|
|
1754
|
+
name: lease.name,
|
|
1755
|
+
baseId: lease.baseId,
|
|
1756
|
+
accessToken: lease.accessToken,
|
|
1757
|
+
runExpiresAt: lease.runExpiresAt
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1564
1760
|
function parseConnectionLease(raw, now = Date.now()) {
|
|
1565
1761
|
let v = raw;
|
|
1566
1762
|
if (!v || typeof v != "object" || Array.isArray(v) || !connectionUuid(v.connectionId) || !connectionUuid(v.runId) || typeof v.name != "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(v.name) || typeof v.accessToken != "string" || !/^[A-Za-z0-9._~+/-]{1,8192}={0,2}$/.test(v.accessToken))
|
|
@@ -1596,12 +1792,12 @@ function object3(v) {
|
|
|
1596
1792
|
function keys2(v, allowed, required = allowed) {
|
|
1597
1793
|
(Object.keys(v).some((k) => !allowed.includes(k)) || required.some((k) => !Object.hasOwn(v, k))) && fail2("Invalid Airtable input");
|
|
1598
1794
|
}
|
|
1599
|
-
function
|
|
1795
|
+
function text3(v) {
|
|
1600
1796
|
return typeof v == "string" && v.length > 0 && v.length <= 1024;
|
|
1601
1797
|
}
|
|
1602
1798
|
function fields3(v, nonempty = !1) {
|
|
1603
1799
|
let result2 = object3(v);
|
|
1604
|
-
(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");
|
|
1605
1801
|
try {
|
|
1606
1802
|
return serializable(result2);
|
|
1607
1803
|
} catch {
|
|
@@ -1622,7 +1818,9 @@ function equal(a, b) {
|
|
|
1622
1818
|
));
|
|
1623
1819
|
}
|
|
1624
1820
|
function createConnections(transport) {
|
|
1625
|
-
return {
|
|
1821
|
+
return { async get() {
|
|
1822
|
+
throw new Error("Connection unavailable");
|
|
1823
|
+
}, airtable(name) {
|
|
1626
1824
|
(typeof name != "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(name)) && fail2("Invalid Airtable connection name");
|
|
1627
1825
|
let call = (operation2, input) => transport(name, operation2, input);
|
|
1628
1826
|
return {
|
|
@@ -1686,10 +1884,10 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1686
1884
|
Array.isArray(page.tables) || fail2("Malformed Airtable tables");
|
|
1687
1885
|
for (let value of page.tables) {
|
|
1688
1886
|
let t = object3(value);
|
|
1689
|
-
(!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");
|
|
1690
1888
|
let metadata = t.fields.map((value2) => {
|
|
1691
1889
|
let f = object3(value2);
|
|
1692
|
-
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) } };
|
|
1693
1891
|
});
|
|
1694
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 });
|
|
1695
1893
|
}
|
|
@@ -1697,7 +1895,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1697
1895
|
} while (offset);
|
|
1698
1896
|
return tables;
|
|
1699
1897
|
}
|
|
1700
|
-
(!
|
|
1898
|
+
(!text3(input.table) || input.table === "." || input.table === "..") && fail2("Invalid Airtable table"), mutation && !tableId(input.table) && fail2("Airtable writes require a stable table ID");
|
|
1701
1899
|
let path = `${baseId}/${encodeURIComponent(input.table)}`;
|
|
1702
1900
|
if (operation2 === "records.get") {
|
|
1703
1901
|
keys2(input, ["table", "id"]), recordId(input.id) || fail2("Invalid Airtable record ID");
|
|
@@ -1705,7 +1903,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1705
1903
|
return result3.id !== input.id && fail2("Malformed Airtable record"), result3;
|
|
1706
1904
|
}
|
|
1707
1905
|
if (operation2 === "records.list") {
|
|
1708
|
-
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");
|
|
1709
1907
|
let records2 = [], ids2 = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set(), offset;
|
|
1710
1908
|
do {
|
|
1711
1909
|
let query2 = new URLSearchParams();
|
|
@@ -1762,10 +1960,10 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1762
1960
|
}
|
|
1763
1961
|
function nextOffset(value, seen) {
|
|
1764
1962
|
if (value !== void 0)
|
|
1765
|
-
return (!
|
|
1963
|
+
return (!text3(value) || seen.has(value)) && fail2("Malformed Airtable pagination"), seen.add(value), value;
|
|
1766
1964
|
}
|
|
1767
1965
|
|
|
1768
|
-
var MANAGED_CONNECTION_CAPABILITY_ENV = "
|
|
1966
|
+
var MANAGED_CONNECTION_CAPABILITY_ENV = "OS_MANAGED_CONNECTION_CAPABILITY";
|
|
1769
1967
|
function managedConnections(capability) {
|
|
1770
1968
|
let endpoint = new URL(capability.endpoint);
|
|
1771
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");
|
|
@@ -1804,46 +2002,19 @@ async function reportLocalRoutineEffect(value) {
|
|
|
1804
2002
|
await observer?.(value);
|
|
1805
2003
|
}
|
|
1806
2004
|
|
|
1807
|
-
var
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
if (installed2) return await installed2.request("airtable", { name, operation: operation2, input: serializable(input) });
|
|
1811
|
-
let managed = process.env[MANAGED_CONNECTION_CAPABILITY_ENV];
|
|
1812
|
-
if (managed) {
|
|
1813
|
-
let client = managedConnections(JSON.parse(managed)).airtable(name);
|
|
1814
|
-
return operation2 === "tables.list" ? await client.tables.list() : await client.records[operation2.slice(8)](input);
|
|
1815
|
-
}
|
|
1816
|
-
let raw = JSON.parse(process.env[ROUTINE_CONNECTION_CREDENTIALS_ENV] ?? "[]");
|
|
1817
|
-
if (!Array.isArray(raw)) throw new Error();
|
|
1818
|
-
let leases = raw.map((value) => parseConnectionLease(value));
|
|
1819
|
-
if (leases.some((lease2) => lease2.provider !== "airtable") || new Set(leases.map((lease2) => lease2.name)).size !== leases.length) throw new Error();
|
|
1820
|
-
let lease = leases.find((lease2) => lease2.name === name);
|
|
1821
|
-
if (!lease || lease.provider !== "airtable") throw new Error();
|
|
1822
|
-
let writing = ["records.create", "records.update", "records.delete"].includes(operation2), captured = serializable(input), result2;
|
|
1823
|
-
try {
|
|
1824
|
-
result2 = await executeAirtableOperation(lease, operation2, captured);
|
|
1825
|
-
} catch (error) {
|
|
1826
|
-
throw writing && error instanceof AirtableOperationError && await reportLocalRoutineEffect({
|
|
1827
|
-
type: "effect",
|
|
1828
|
-
connection: `airtable/${name}`,
|
|
1829
|
-
operation: operation2,
|
|
1830
|
-
input: captured,
|
|
1831
|
-
effect: error.effect,
|
|
1832
|
-
receipts: error.receipts
|
|
1833
|
-
}), error;
|
|
1834
|
-
}
|
|
1835
|
-
return writing && await reportLocalRoutineEffect({
|
|
1836
|
-
type: "effect",
|
|
1837
|
-
connection: `airtable/${name}`,
|
|
1838
|
-
operation: operation2,
|
|
1839
|
-
input: captured,
|
|
1840
|
-
effect: "confirmed",
|
|
1841
|
-
receipts: [result2.receipt]
|
|
1842
|
-
}), result2;
|
|
1843
|
-
} catch (error) {
|
|
1844
|
-
throw error instanceof AirtableOperationError ? error : new AirtableOperationError("Airtable connection unavailable");
|
|
1845
|
-
}
|
|
2005
|
+
var local;
|
|
2006
|
+
var airtable = /* @__PURE__ */ createConnections(async (name, operation2, input) => {
|
|
2007
|
+
throw new AirtableOperationError("Airtable connection unavailable");
|
|
1846
2008
|
});
|
|
2009
|
+
function runtimeConnections() {
|
|
2010
|
+
return {
|
|
2011
|
+
...airtable,
|
|
2012
|
+
async get(identity) {
|
|
2013
|
+
throw new Error("Connection unavailable");
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
var connections = /* @__PURE__ */ runtimeConnections();
|
|
1847
2018
|
|
|
1848
2019
|
var LOCAL_ROUTINE_VALUE_BYTES = 256 * 1024;
|
|
1849
2020
|
|
|
@@ -1948,7 +2119,7 @@ function object4(value) {
|
|
|
1948
2119
|
function keys3(value, allowed, required = allowed) {
|
|
1949
2120
|
assert(Object.keys(value).every((key) => allowed.includes(key)) && required.every((key) => Object.hasOwn(value, key)));
|
|
1950
2121
|
}
|
|
1951
|
-
function
|
|
2122
|
+
function text4(value, empty2 = !1) {
|
|
1952
2123
|
return typeof value == "string" && (empty2 || !!value.trim());
|
|
1953
2124
|
}
|
|
1954
2125
|
function id2(value) {
|
|
@@ -1958,7 +2129,7 @@ function integer(value, minimum = 1) {
|
|
|
1958
2129
|
return Number.isSafeInteger(value) && Number(value) >= minimum;
|
|
1959
2130
|
}
|
|
1960
2131
|
function date(value) {
|
|
1961
|
-
return
|
|
2132
|
+
return text4(value) && Number.isFinite(Date.parse(value));
|
|
1962
2133
|
}
|
|
1963
2134
|
function optionalDate(value) {
|
|
1964
2135
|
return value === null || date(value);
|
|
@@ -1980,7 +2151,7 @@ function json(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
1980
2151
|
}
|
|
1981
2152
|
function recordReference(value) {
|
|
1982
2153
|
let record3 = object4(value);
|
|
1983
|
-
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;
|
|
1984
2155
|
}
|
|
1985
2156
|
function responseDefinition(value) {
|
|
1986
2157
|
let definition = object4(value);
|
|
@@ -1992,75 +2163,75 @@ function responseDefinition(value) {
|
|
|
1992
2163
|
assert(options.length > 0);
|
|
1993
2164
|
let values = options.map((value2) => {
|
|
1994
2165
|
let option = object4(value2);
|
|
1995
|
-
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) {
|
|
1996
2167
|
let note = object4(option.note);
|
|
1997
|
-
keys3(note, ["placeholder"]), assert(
|
|
2168
|
+
keys3(note, ["placeholder"]), assert(text4(note.placeholder));
|
|
1998
2169
|
}
|
|
1999
2170
|
return option.value;
|
|
2000
2171
|
});
|
|
2001
2172
|
if (assert(new Set(values).size === values.length), "search" in source || "suggestions" in source) {
|
|
2002
2173
|
let search = object4(source.search);
|
|
2003
|
-
keys3(search, ["triggerLabel", "placeholder", "emptyLabel"]), assert(
|
|
2174
|
+
keys3(search, ["triggerLabel", "placeholder", "emptyLabel"]), assert(text4(search.triggerLabel) && text4(search.placeholder) && text4(search.emptyLabel));
|
|
2004
2175
|
let suggestions2 = array2(source.suggestions);
|
|
2005
|
-
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);
|
|
2006
2177
|
} else assert(options.length <= 9);
|
|
2007
2178
|
return;
|
|
2008
2179
|
}
|
|
2009
2180
|
assert(source.type === "records"), keys3(source, ["type", "collection", "refPrefix", "where", "display", "suggestions"], ["type", "collection", "display"]);
|
|
2010
2181
|
let collection = object4(source.collection);
|
|
2011
|
-
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));
|
|
2012
2183
|
let where = object4(source.where ?? {});
|
|
2013
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))));
|
|
2014
2185
|
let display = object4(source.display);
|
|
2015
2186
|
keys3(display, ["labelFields"]);
|
|
2016
2187
|
let labels = array2(display.labelFields);
|
|
2017
|
-
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)));
|
|
2018
2189
|
let suggestions = array2(source.suggestions ?? []), refs = suggestions.map((value2) => {
|
|
2019
2190
|
let suggestion = object4(value2);
|
|
2020
2191
|
keys3(suggestion, ["record", "reason"], ["record"]);
|
|
2021
2192
|
let record3 = recordReference(suggestion.record);
|
|
2022
|
-
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;
|
|
2023
2194
|
});
|
|
2024
2195
|
assert(suggestions.length <= 8 && new Set(refs).size === refs.length);
|
|
2025
2196
|
}
|
|
2026
2197
|
function inboxFile(value) {
|
|
2027
2198
|
let file2 = object4(value);
|
|
2028
|
-
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));
|
|
2029
2200
|
let details = object4(file2.details);
|
|
2030
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)));
|
|
2031
2202
|
}
|
|
2032
2203
|
function fields4(value) {
|
|
2033
2204
|
let labels = array2(value).map((value2) => {
|
|
2034
2205
|
let field = object4(value2);
|
|
2035
|
-
return keys3(field, ["label", "value"]), assert(
|
|
2206
|
+
return keys3(field, ["label", "value"]), assert(text4(field.label) && text4(field.value)), field.label;
|
|
2036
2207
|
});
|
|
2037
2208
|
assert(new Set(labels).size === labels.length);
|
|
2038
2209
|
}
|
|
2039
2210
|
function block(value) {
|
|
2040
2211
|
let entry = object4(value);
|
|
2041
2212
|
if (entry.kind === "rich-text") {
|
|
2042
|
-
keys3(entry, ["kind", "markdown"]), assert(
|
|
2213
|
+
keys3(entry, ["kind", "markdown"]), assert(text4(entry.markdown));
|
|
2043
2214
|
return;
|
|
2044
2215
|
}
|
|
2045
2216
|
if (entry.kind === "asks") {
|
|
2046
2217
|
keys3(entry, ["kind", "problem", "asks"]);
|
|
2047
2218
|
let asks = array2(entry.asks);
|
|
2048
|
-
assert(
|
|
2219
|
+
assert(text4(entry.problem) && asks.length > 0 && asks.every(id2) && new Set(asks).size === asks.length);
|
|
2049
2220
|
return;
|
|
2050
2221
|
}
|
|
2051
2222
|
if (assert(["record", "records", "files"].includes(String(entry.kind))), keys3(
|
|
2052
2223
|
entry,
|
|
2053
2224
|
["kind", "label", "initiallyExpanded", ...entry.kind === "record" ? ["record", "view"] : entry.kind === "records" ? ["records", "view"] : ["files"]],
|
|
2054
2225
|
["kind", "label", entry.kind === "record" ? "record" : entry.kind === "records" ? "records" : "files"]
|
|
2055
|
-
), 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") {
|
|
2056
2227
|
let record3 = object4(entry.record);
|
|
2057
|
-
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);
|
|
2058
2229
|
return;
|
|
2059
2230
|
}
|
|
2060
2231
|
if (entry.kind === "records") {
|
|
2061
2232
|
let records = array2(entry.records), refs = records.map((value2) => {
|
|
2062
2233
|
let record3 = object4(value2);
|
|
2063
|
-
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;
|
|
2064
2235
|
});
|
|
2065
2236
|
assert(records.length > 0 && new Set(refs).size === refs.length);
|
|
2066
2237
|
return;
|
|
@@ -2070,7 +2241,7 @@ function block(value) {
|
|
|
2070
2241
|
}
|
|
2071
2242
|
function response(value) {
|
|
2072
2243
|
let answer = object4(value);
|
|
2073
|
-
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;
|
|
2074
2245
|
}
|
|
2075
2246
|
function parseInboxRequest(value) {
|
|
2076
2247
|
try {
|
|
@@ -2079,78 +2250,82 @@ function parseInboxRequest(value) {
|
|
|
2079
2250
|
let operation2 = envelope.operation, input = { ...object4(envelope.input) }, required = operations[operation2];
|
|
2080
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)));
|
|
2081
2252
|
for (let key of ["itemId", "personId", "fileId"]) key in input && assert(id2(input[key]));
|
|
2082
|
-
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 };
|
|
2083
2254
|
} catch {
|
|
2084
2255
|
throw new InboxOperationError(400, "invalid_input");
|
|
2085
2256
|
}
|
|
2086
2257
|
}
|
|
2087
2258
|
function parseInboxCurrent(value) {
|
|
2088
2259
|
let current2 = object4(value), workspace = object4(current2.workspace), viewer = object4(current2.viewer);
|
|
2089
|
-
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)), {
|
|
2090
2261
|
workspace: { id: workspace.id, slug: workspace.slug, name: workspace.name, locale: workspace.locale, timezone: workspace.timezone },
|
|
2091
2262
|
viewer: { id: viewer.id, name: viewer.name, email: viewer.email }
|
|
2092
2263
|
};
|
|
2093
2264
|
}
|
|
2094
2265
|
function parseInboxItem(value) {
|
|
2095
2266
|
let item = object4(json(value));
|
|
2096
|
-
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) => {
|
|
2097
2268
|
let view = object4(value2);
|
|
2098
|
-
assert(
|
|
2269
|
+
assert(text4(view.id) && text4(view.view) && text4(view.implementation)), json(view.input);
|
|
2099
2270
|
}), array2(item.people).forEach((value2) => {
|
|
2100
2271
|
let person = object4(value2);
|
|
2101
|
-
assert(id2(person.id) &&
|
|
2272
|
+
assert(id2(person.id) && text4(person.name));
|
|
2102
2273
|
}), array2(item.questions).forEach((value2) => {
|
|
2103
2274
|
let question2 = object4(value2);
|
|
2104
|
-
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) {
|
|
2105
2276
|
let accepted = object4(question2.acceptedResponse);
|
|
2106
|
-
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));
|
|
2107
2278
|
}
|
|
2108
2279
|
if (question2.execution !== null) {
|
|
2109
2280
|
let execution = object4(question2.execution);
|
|
2110
2281
|
if (assert(id2(execution.id) && ["pending", "running", "completed", "failed"].includes(String(execution.state)) && integer(execution.attempt, 0)), "consequence" in execution) {
|
|
2111
2282
|
let consequence = object4(execution.consequence);
|
|
2112
|
-
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) => {
|
|
2113
2284
|
let receipt = object4(value3);
|
|
2114
|
-
assert(
|
|
2285
|
+
assert(text4(receipt.repository) && text4(receipt.commit) && text4(receipt.diff, !0));
|
|
2115
2286
|
});
|
|
2116
2287
|
}
|
|
2117
2288
|
}
|
|
2118
2289
|
}), array2(item.linkedAsks).forEach((value2) => {
|
|
2119
2290
|
let linked = object4(value2);
|
|
2120
2291
|
if (assert(id2(linked.id)), linked.state === "unavailable") assert(typeof linked.done == "boolean");
|
|
2121
|
-
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") {
|
|
2122
2293
|
let assignee = object4(linked.assignee);
|
|
2123
|
-
assert(id2(assignee.id) &&
|
|
2294
|
+
assert(id2(assignee.id) && text4(assignee.name));
|
|
2124
2295
|
}
|
|
2125
2296
|
}), array2(item.activity).forEach((value2) => {
|
|
2126
2297
|
let event = object4(value2);
|
|
2127
|
-
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);
|
|
2128
2299
|
}), array2(item.work).forEach((value2) => {
|
|
2129
2300
|
let work = object4(value2);
|
|
2130
|
-
assert(id2(work.id) &&
|
|
2301
|
+
assert(id2(work.id) && text4(work.questionId) && text4(work.reason) && optionalDate(work.settledAt));
|
|
2131
2302
|
}), item;
|
|
2132
2303
|
}
|
|
2133
2304
|
function parseAnswerableQuestion(value) {
|
|
2134
2305
|
let entry = object4(json(value));
|
|
2135
2306
|
keys3(
|
|
2136
2307
|
entry,
|
|
2137
|
-
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "recordRefs", "instructions"],
|
|
2138
|
-
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"
|
|
2139
|
-
), assert(id2(entry.itemId) && integer(entry.revision) &&
|
|
2308
|
+
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
|
|
2309
|
+
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
|
|
2310
|
+
), assert(id2(entry.itemId) && integer(entry.revision) && text4(entry.title) && text4(entry.inboxUrl));
|
|
2140
2311
|
let link = new URL(entry.inboxUrl), slug = link.hostname.slice(0, -13);
|
|
2141
|
-
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) &&
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
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;
|
|
2313
|
+
}
|
|
2314
|
+
function askMetadata(entry) {
|
|
2315
|
+
let tags = array2(entry.tags === void 0 ? [] : entry.tags);
|
|
2316
|
+
assert(tags.length <= 32 && tags.every((tag) => text4(tag) && new TextEncoder().encode(tag).byteLength <= 64)), assert(new Set(tags).size === tags.length);
|
|
2317
|
+
let refs = array2(entry.recordRefs === void 0 ? [] : entry.recordRefs);
|
|
2318
|
+
refs.forEach((value) => {
|
|
2319
|
+
let ref = object4(value);
|
|
2320
|
+
keys3(ref, ["repository", "id"]), recordReference({ repository: ref.repository, ref: ref.id });
|
|
2321
|
+
}), assert(new Set(refs.map((value) => {
|
|
2322
|
+
let ref = object4(value);
|
|
2148
2323
|
return JSON.stringify([ref.repository, ref.id]);
|
|
2149
|
-
})).size === refs.length), entry;
|
|
2324
|
+
})).size === refs.length), entry.tags = tags, entry.recordRefs = refs;
|
|
2150
2325
|
}
|
|
2151
2326
|
function parseInboxAcceptance(value) {
|
|
2152
2327
|
let accepted = object4(value);
|
|
2153
|
-
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;
|
|
2154
2329
|
}
|
|
2155
2330
|
function parseInboxResult(operation2, value) {
|
|
2156
2331
|
if (operation2 === "current") return parseInboxCurrent(value);
|
|
@@ -2181,7 +2356,7 @@ function parseInboxResult(operation2, value) {
|
|
|
2181
2356
|
let candidates = array2(value);
|
|
2182
2357
|
return candidates.forEach((value2) => {
|
|
2183
2358
|
let person = object4(value2);
|
|
2184
|
-
assert(id2(person.id) &&
|
|
2359
|
+
assert(id2(person.id) && text4(person.name) && text4(person.email));
|
|
2185
2360
|
}), assert(new Set(candidates.map((value2) => object4(value2).id)).size === candidates.length), candidates;
|
|
2186
2361
|
}
|
|
2187
2362
|
if (operation2 === "items.addRecipient") {
|
|
@@ -2191,10 +2366,10 @@ function parseInboxResult(operation2, value) {
|
|
|
2191
2366
|
if (operation2 === "questions.answer") return parseInboxAcceptance(value);
|
|
2192
2367
|
if (operation2 === "questions.searchRecords") {
|
|
2193
2368
|
let result2 = object4(value);
|
|
2194
|
-
assert(
|
|
2369
|
+
assert(text4(result2.recordType) && integer(result2.eligibleCount, 0) && integer(result2.matchCount, 0) && Number(result2.matchCount) <= Number(result2.eligibleCount));
|
|
2195
2370
|
let labeled = (value2) => {
|
|
2196
2371
|
let record3 = object4(value2);
|
|
2197
|
-
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));
|
|
2198
2373
|
};
|
|
2199
2374
|
return array2(result2.matches).forEach(labeled), array2(result2.suggestions).forEach(labeled), "selected" in result2 && labeled(result2.selected), result2;
|
|
2200
2375
|
}
|
|
@@ -2308,7 +2483,7 @@ async function appResponse(response2, maximum, signal) {
|
|
|
2308
2483
|
});
|
|
2309
2484
|
};
|
|
2310
2485
|
signal.addEventListener("abort", abort, { once: !0 });
|
|
2311
|
-
let bytes = 0,
|
|
2486
|
+
let bytes = 0, text5 = "", decoder = new TextDecoder("utf-8", { fatal: !0 });
|
|
2312
2487
|
try {
|
|
2313
2488
|
for (; ; ) {
|
|
2314
2489
|
let chunk;
|
|
@@ -2319,13 +2494,13 @@ async function appResponse(response2, maximum, signal) {
|
|
|
2319
2494
|
}
|
|
2320
2495
|
if (signal.aborted) throw new Error();
|
|
2321
2496
|
if (chunk.done) {
|
|
2322
|
-
let value = JSON.parse(
|
|
2497
|
+
let value = JSON.parse(text5 + decoder.decode());
|
|
2323
2498
|
if (await responseChecks.get(response2)?.(value), signal.aborted) throw new Error();
|
|
2324
2499
|
return value;
|
|
2325
2500
|
}
|
|
2326
2501
|
if (bytes += chunk.value.byteLength, bytes > maximum)
|
|
2327
2502
|
throw abort(), new Error();
|
|
2328
|
-
|
|
2503
|
+
text5 += decoder.decode(chunk.value, { stream: !0 });
|
|
2329
2504
|
}
|
|
2330
2505
|
} finally {
|
|
2331
2506
|
signal.removeEventListener("abort", abort), reader.releaseLock();
|
|
@@ -2376,10 +2551,12 @@ function appContext(origin, active2) {
|
|
|
2376
2551
|
credentials: "omit",
|
|
2377
2552
|
redirect: "error",
|
|
2378
2553
|
cache: "no-store",
|
|
2554
|
+
...init2.body instanceof ReadableStream ? { duplex: "half" } : {},
|
|
2379
2555
|
referrerPolicy: "no-referrer",
|
|
2380
2556
|
signal,
|
|
2381
2557
|
headers: {
|
|
2382
2558
|
...init2.body === void 0 ? {} : { "content-type": "application/json" },
|
|
2559
|
+
...Object.fromEntries(new Headers(init2.headers)),
|
|
2383
2560
|
authorization: `Bearer ${candidate}`
|
|
2384
2561
|
}
|
|
2385
2562
|
});
|
|
@@ -2545,11 +2722,37 @@ function appContext(origin, active2) {
|
|
|
2545
2722
|
async function requestRoutine(key, suffix, init2 = {}) {
|
|
2546
2723
|
return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, init2);
|
|
2547
2724
|
}
|
|
2548
|
-
async function
|
|
2725
|
+
async function requestRetainedRoutine(key, suffix) {
|
|
2726
|
+
return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, {}, !1, !0);
|
|
2727
|
+
}
|
|
2728
|
+
async function requestFiles(suffix, init2, parent) {
|
|
2729
|
+
let unavailable4 = () => new FileOperationError("unsupported_context", 400);
|
|
2730
|
+
if (!current2() || !/^(?:|\/[0-9a-f-]{36}(?:\/(?:content|upload|enrichments(?:\/[^/?#]+\/content)?))?)$/i.test(suffix))
|
|
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();
|
|
2733
|
+
try {
|
|
2734
|
+
return await hostedContent("", init2, signal, (_url, request2) => untilAborted(
|
|
2735
|
+
send3(`files${suffix}`, admitted, signal, request2).then((value) => {
|
|
2736
|
+
if (signal.aborted)
|
|
2737
|
+
throw value.body?.cancel().catch(() => {
|
|
2738
|
+
}), unavailable4();
|
|
2739
|
+
return value;
|
|
2740
|
+
}),
|
|
2741
|
+
signal
|
|
2742
|
+
), () => settledAccess(signal), failure);
|
|
2743
|
+
} catch {
|
|
2744
|
+
throw failure();
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
async function requestChecked(path, init2, inbox2 = !1, retained2 = !1) {
|
|
2549
2748
|
if (!current2()) throw new Error("Local app context unavailable.");
|
|
2550
|
-
let admitted = credential, signal = access.signal, response2 = await send3(path, credential, signal, init2)
|
|
2551
|
-
|
|
2552
|
-
|
|
2749
|
+
let admitted = credential, signal = access.signal, response2 = await send3(path, credential, signal, init2), check = async () => {
|
|
2750
|
+
if (retained2) {
|
|
2751
|
+
if (signal.aborted || !current2()) throw new Error("Local app context unavailable.");
|
|
2752
|
+
} else await settledAccess(signal);
|
|
2753
|
+
};
|
|
2754
|
+
return await check(), (response2.status === 401 || !inbox2 && response2.status === 403) && admitted === credential && current2() && invalidate(), responseChecks.set(response2, async (value) => {
|
|
2755
|
+
await check(), admitted === credential && current2() && value && typeof value == "object" && "error" in value && value.error === "authority_unavailable" && invalidate();
|
|
2553
2756
|
}), response2;
|
|
2554
2757
|
}
|
|
2555
2758
|
function context2() {
|
|
@@ -2566,8 +2769,10 @@ function appContext(origin, active2) {
|
|
|
2566
2769
|
issued === credential && current2() && invalidate();
|
|
2567
2770
|
},
|
|
2568
2771
|
requestRoutine,
|
|
2772
|
+
requestRetainedRoutine,
|
|
2569
2773
|
requestData,
|
|
2570
2774
|
requestInbox,
|
|
2775
|
+
requestFiles,
|
|
2571
2776
|
requestAvailability: (key) => requestRoutine(key, "availability", { method: "GET" })
|
|
2572
2777
|
};
|
|
2573
2778
|
}
|
|
@@ -2576,22 +2781,22 @@ function appContext(origin, active2) {
|
|
|
2576
2781
|
try {
|
|
2577
2782
|
if (!alive()) throw new Error();
|
|
2578
2783
|
if (!pair) {
|
|
2579
|
-
let candidate2 = stored(),
|
|
2580
|
-
pair =
|
|
2784
|
+
let candidate2 = stored(), retained3 = readPair(candidate2);
|
|
2785
|
+
pair = retained3, binding = { ...retained3.context }, credential = retained3.credential, serialized = candidate2;
|
|
2581
2786
|
}
|
|
2582
2787
|
if (expireAccess(), binding.expiresAt <= Date.now()) {
|
|
2583
2788
|
if (await renew(), !current2()) throw new AppRenewalUnavailable();
|
|
2584
2789
|
return context2();
|
|
2585
2790
|
}
|
|
2586
2791
|
await synchronize();
|
|
2587
|
-
let candidate = stored(),
|
|
2792
|
+
let candidate = stored(), retained2 = readPair(candidate);
|
|
2588
2793
|
if (attempted = candidate ?? void 0, !current2()) throw new AppRenewalUnavailable();
|
|
2589
|
-
let value = await proof(
|
|
2794
|
+
let value = await proof(retained2.credential);
|
|
2590
2795
|
if (stored() !== candidate || serialized !== candidate)
|
|
2591
2796
|
return await synchronize(), context2();
|
|
2592
2797
|
if (!current2()) throw new Error();
|
|
2593
2798
|
if (expiry && binding && value.expiresAt > binding.expiresAt) throw new Error();
|
|
2594
|
-
return (!expiry || value.expiresAt !== binding.expiresAt) && install(value,
|
|
2799
|
+
return (!expiry || value.expiresAt !== binding.expiresAt) && install(value, retained2, candidate), context2();
|
|
2595
2800
|
} catch (error) {
|
|
2596
2801
|
if (alive() && error instanceof AppRenewalUnavailable)
|
|
2597
2802
|
throw new Error();
|
|
@@ -2606,7 +2811,12 @@ function appContext(origin, active2) {
|
|
|
2606
2811
|
}, resolve = () => resolution2 || (resolution2 = resolveOnce().finally(() => {
|
|
2607
2812
|
resolution2 = void 0;
|
|
2608
2813
|
}), resolution2);
|
|
2609
|
-
return { resolve,
|
|
2814
|
+
return { resolve, retained: async () => {
|
|
2815
|
+
if (!expiry && alive() && (binding ? current2() && resolution2 : readPair(stored()).context.expiresAt > Date.now()))
|
|
2816
|
+
return resolve();
|
|
2817
|
+
if (!expiry || !current2()) throw new Error("Local app context unavailable.");
|
|
2818
|
+
return context2();
|
|
2819
|
+
}, start: () => {
|
|
2610
2820
|
startup = setTimeout(() => {
|
|
2611
2821
|
alive() && !resolution2 && !binding && resolve().catch(() => {
|
|
2612
2822
|
});
|
|
@@ -2627,9 +2837,9 @@ function validPair(value) {
|
|
|
2627
2837
|
return validProof(pair.credential) && validProof(pair.renewalCredential) && pair.credential !== pair.renewalCredential && validBinding(pair.context);
|
|
2628
2838
|
}
|
|
2629
2839
|
|
|
2630
|
-
var
|
|
2840
|
+
var unavailable3 = () => new InboxOperationError(503, "unavailable"), stale = () => new InboxOperationError(401, "authority_unavailable");
|
|
2631
2841
|
function hostFailure(error, context2) {
|
|
2632
|
-
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();
|
|
2633
2843
|
}
|
|
2634
2844
|
async function send2(operation2, input) {
|
|
2635
2845
|
let envelope = parseInboxRequest({ operation: operation2, input }), context2;
|
|
@@ -2649,12 +2859,12 @@ async function send2(operation2, input) {
|
|
|
2649
2859
|
[400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
|
|
2650
2860
|
response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
|
|
2651
2861
|
);
|
|
2652
|
-
if (response2.status !== 200) throw
|
|
2862
|
+
if (response2.status !== 200) throw unavailable3();
|
|
2653
2863
|
let parsed = parseInboxResult(operation2, value);
|
|
2654
|
-
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();
|
|
2655
2865
|
return parsed;
|
|
2656
2866
|
} catch (error) {
|
|
2657
|
-
throw check2(), error instanceof InboxOperationError ? error :
|
|
2867
|
+
throw check2(), error instanceof InboxOperationError ? error : unavailable3();
|
|
2658
2868
|
}
|
|
2659
2869
|
}
|
|
2660
2870
|
if (context2.endpoint !== `https://${context2.workspace}.oddington.ai` || ["auth", "www", "api", "os"].includes(context2.workspace)) throw stale();
|
|
@@ -2665,7 +2875,7 @@ async function send2(operation2, input) {
|
|
|
2665
2875
|
} catch (error) {
|
|
2666
2876
|
throw hostFailure(error, context2);
|
|
2667
2877
|
}
|
|
2668
|
-
if (!host) throw
|
|
2878
|
+
if (!host) throw unavailable3();
|
|
2669
2879
|
}
|
|
2670
2880
|
let check = () => {
|
|
2671
2881
|
if (!context2.isCurrent() || host && !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
|
|
@@ -2695,9 +2905,9 @@ async function send2(operation2, input) {
|
|
|
2695
2905
|
);
|
|
2696
2906
|
if (response2.status !== 200)
|
|
2697
2907
|
throw response2.body?.cancel().catch(() => {
|
|
2698
|
-
}),
|
|
2908
|
+
}), unavailable3();
|
|
2699
2909
|
if (operation2 === "files.read") {
|
|
2700
|
-
if (!response2.body) throw
|
|
2910
|
+
if (!response2.body) throw unavailable3();
|
|
2701
2911
|
let source = response2.body, reader, size = 0, cancel = async (reason) => {
|
|
2702
2912
|
try {
|
|
2703
2913
|
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
@@ -2713,7 +2923,7 @@ async function send2(operation2, input) {
|
|
|
2713
2923
|
reader.releaseLock(), controller.close();
|
|
2714
2924
|
return;
|
|
2715
2925
|
}
|
|
2716
|
-
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw
|
|
2926
|
+
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw unavailable3();
|
|
2717
2927
|
controller.enqueue(next.value);
|
|
2718
2928
|
} catch (error) {
|
|
2719
2929
|
controller.error(error), await cancel(error).catch(() => {
|
|
@@ -2725,16 +2935,16 @@ async function send2(operation2, input) {
|
|
|
2725
2935
|
return new Response(body, { status: response2.status, headers: response2.headers });
|
|
2726
2936
|
}
|
|
2727
2937
|
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
2728
|
-
if (check(), !bytes) throw
|
|
2938
|
+
if (check(), !bytes) throw unavailable3();
|
|
2729
2939
|
let value = JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)), parsed = parseInboxResult(operation2, value);
|
|
2730
|
-
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw
|
|
2940
|
+
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw unavailable3();
|
|
2731
2941
|
if ("itemId" in envelope.input) {
|
|
2732
2942
|
let item = operation2 === "items.read" ? parsed : operation2 === "items.rename" || operation2 === "items.setLifecycle" || operation2 === "items.addRecipient" ? parsed.item : void 0;
|
|
2733
|
-
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();
|
|
2734
2944
|
}
|
|
2735
2945
|
return parsed;
|
|
2736
2946
|
} catch (error) {
|
|
2737
|
-
throw check(), error instanceof InboxOperationError ? error :
|
|
2947
|
+
throw check(), error instanceof InboxOperationError ? error : unavailable3();
|
|
2738
2948
|
}
|
|
2739
2949
|
}
|
|
2740
2950
|
var inbox = {
|
|
@@ -2754,14 +2964,14 @@ var inbox = {
|
|
|
2754
2964
|
throw hostFailure(error, initial);
|
|
2755
2965
|
}
|
|
2756
2966
|
if (initial.kind === "local") throw new InboxOperationError(403, "access_denied");
|
|
2757
|
-
if (!host) throw
|
|
2967
|
+
if (!host) throw unavailable3();
|
|
2758
2968
|
let check = () => {
|
|
2759
2969
|
if (!initial.isCurrent() || !host.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
|
|
2760
2970
|
};
|
|
2761
2971
|
do {
|
|
2762
2972
|
check();
|
|
2763
2973
|
let page = await send2("items.list", beforeNumber === void 0 ? {} : { beforeNumber });
|
|
2764
|
-
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();
|
|
2765
2975
|
if (items.push(...page.items), page.nextBeforeNumber === null) return items;
|
|
2766
2976
|
beforeNumber = page.nextBeforeNumber;
|
|
2767
2977
|
} while (!0);
|
|
@@ -2795,7 +3005,7 @@ var inbox = {
|
|
|
2795
3005
|
routines,
|
|
2796
3006
|
...beforeNumber === void 0 ? {} : { beforeNumber }
|
|
2797
3007
|
});
|
|
2798
|
-
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();
|
|
2799
3009
|
if (questions.push(...page.questions), page.nextBeforeNumber === null) return questions;
|
|
2800
3010
|
beforeNumber = page.nextBeforeNumber;
|
|
2801
3011
|
} while (!0);
|
|
@@ -2832,8 +3042,8 @@ function init({ auth: input }) {
|
|
|
2832
3042
|
url.protocol === "https:" && !url.port && !url.username && !url.password && !url.search && !url.hash && url.pathname === "/" && /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(slug) && slug !== "auth" && (endpoint = url.origin, workspace = slug);
|
|
2833
3043
|
} catch {
|
|
2834
3044
|
}
|
|
2835
|
-
let active2 = !0, revision = 0, person, token, binding = {},
|
|
2836
|
-
if (
|
|
3045
|
+
let active2 = !0, revision = 0, person, token, binding = {}, local3 = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, resolve = async () => {
|
|
3046
|
+
if (local3) return local3.resolve();
|
|
2837
3047
|
if (!active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
|
|
2838
3048
|
let started = revision, { data: { session }, error } = await auth2.getSession();
|
|
2839
3049
|
if (!active2 || globalThis.location.origin !== endpoint || started !== revision || error || !session || person !== void 0 && person !== session.user.id)
|
|
@@ -2852,13 +3062,13 @@ function init({ auth: input }) {
|
|
|
2852
3062
|
memberId: session.user.id,
|
|
2853
3063
|
binding
|
|
2854
3064
|
};
|
|
2855
|
-
}), dispose = () => {
|
|
2856
|
-
active2 && (active2 = !1,
|
|
3065
|
+
}, uninstall = installMemberContext(resolve, local3 ? local3.retained : resolve), dispose = () => {
|
|
3066
|
+
active2 && (active2 = !1, local3?.dispose(), revision++, subscription?.unsubscribe(), stopDisposal?.(), uninstall(), installedDispose === dispose && (installedDispose = void 0));
|
|
2857
3067
|
};
|
|
2858
3068
|
installedDispose = dispose, stopDisposal = registered?.onDispose(dispose), active2 && (subscription = auth2.onAuthStateChange((event, session) => {
|
|
2859
3069
|
let next = session?.user.id ?? null;
|
|
2860
|
-
(event === "SIGNED_OUT" || person !== void 0 && next !== person || registered && person !== void 0 && event === "SIGNED_IN" && token !== session?.access_token) && (revision++,
|
|
2861
|
-
}).data.subscription,
|
|
3070
|
+
(event === "SIGNED_OUT" || person !== void 0 && next !== person || registered && person !== void 0 && event === "SIGNED_IN" && token !== session?.access_token) && (revision++, local3?.invalidate()), person = next, token = session?.access_token;
|
|
3071
|
+
}).data.subscription, local3?.start());
|
|
2862
3072
|
}
|
|
2863
3073
|
var os = { init };
|
|
2864
3074
|
|
|
@@ -3303,16 +3513,16 @@ function current(context2) {
|
|
|
3303
3513
|
function appDescriptors() {
|
|
3304
3514
|
return globalThis[/* @__PURE__ */ Symbol.for("oddington.app.descriptor")]?.routines ?? [];
|
|
3305
3515
|
}
|
|
3306
|
-
async function
|
|
3307
|
-
let context2 = await resolveAppContext().catch(() => fail3("authority_unavailable"));
|
|
3516
|
+
async function local2(retained = !1) {
|
|
3517
|
+
let context2 = await resolveAppContext(retained).catch(() => fail3("authority_unavailable"));
|
|
3308
3518
|
return context2.kind !== "local" ? fail3("execution_unavailable") : (current(context2), context2);
|
|
3309
3519
|
}
|
|
3310
|
-
async function request(key, suffix, init2, maximum = SUMMARY_BYTES, retained) {
|
|
3520
|
+
async function request(key, suffix, init2, maximum = SUMMARY_BYTES, retained, read2 = !1) {
|
|
3311
3521
|
(!identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable");
|
|
3312
|
-
let context2 = retained ?? await
|
|
3522
|
+
let context2 = retained ?? await local2(read2);
|
|
3313
3523
|
current(context2);
|
|
3314
3524
|
try {
|
|
3315
|
-
let response2 = await context2.requestRoutine(key, suffix, init2), value = await appResponse(response2, maximum, context2.signal);
|
|
3525
|
+
let response2 = await (read2 ? context2.requestRetainedRoutine(key, suffix) : context2.requestRoutine(key, suffix, init2)), value = await appResponse(response2, maximum, context2.signal);
|
|
3316
3526
|
if (current(context2), !response2.ok) {
|
|
3317
3527
|
let reason = value?.error;
|
|
3318
3528
|
reason === "authority_unavailable" && (context2.invalidate(), fail3(reason)), (reason === "invalid_input" || reason === "execution_unavailable") && fail3(reason), fail3("execution_unavailable");
|
|
@@ -3358,11 +3568,15 @@ function structure(value) {
|
|
|
3358
3568
|
return JSON.stringify(value, (_key, item) => item && typeof item == "object" && !Array.isArray(item) ? Object.fromEntries(Object.keys(item).sort().map((key) => [key, item[key]])) : item);
|
|
3359
3569
|
}
|
|
3360
3570
|
function handle(key, id3, context2) {
|
|
3361
|
-
|
|
3362
|
-
|
|
3571
|
+
(!identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable"), (typeof id3 != "string" || !uuid.test(id3)) && fail3("invalid_input");
|
|
3572
|
+
let read2 = async () => summary(await request(key, `runs/${id3}`, void 0, SUMMARY_BYTES, context2, !0), key, id3);
|
|
3573
|
+
return routineRunHandle({
|
|
3574
|
+
async current() {
|
|
3575
|
+
return current(context2), read2();
|
|
3576
|
+
},
|
|
3363
3577
|
async step(step) {
|
|
3364
3578
|
(typeof step != "string" || !identifier.test(step)) && fail3("invalid_input");
|
|
3365
|
-
let value = await request(key, `runs/${id3}/steps/${step}`, void 0, 514 * 1024, context2);
|
|
3579
|
+
let value = await request(key, `runs/${id3}/steps/${step}`, void 0, 514 * 1024, context2, !0);
|
|
3366
3580
|
return (!only(value, "id,title,status,startedAt,finishedAt,summary,data") || value.id !== step || !validStep(value)) && fail3("execution_unavailable"), value;
|
|
3367
3581
|
},
|
|
3368
3582
|
async publish() {
|
|
@@ -3373,7 +3587,7 @@ function handle(key, id3, context2) {
|
|
|
3373
3587
|
async function describeAppRoutine(key) {
|
|
3374
3588
|
let descriptor = appDescriptors().find((item) => item.id === key);
|
|
3375
3589
|
if (!descriptor) return fail3("authority_unavailable");
|
|
3376
|
-
let
|
|
3590
|
+
let unavailable4 = () => ({
|
|
3377
3591
|
...structuredClone(descriptor),
|
|
3378
3592
|
connections: descriptor.connections.map((connection) => ({ ...connection, available: !1 })),
|
|
3379
3593
|
readiness: { state: "unavailable", reason: "capability_unavailable", message: "Routine capability unavailable." }
|
|
@@ -3382,11 +3596,11 @@ async function describeAppRoutine(key) {
|
|
|
3382
3596
|
let value = await request(key, "describe", void 0, 1048576);
|
|
3383
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;
|
|
3384
3598
|
} catch {
|
|
3385
|
-
return
|
|
3599
|
+
return unavailable4();
|
|
3386
3600
|
}
|
|
3387
3601
|
}
|
|
3388
3602
|
function appRoutineBinding(key) {
|
|
3389
|
-
return Object.freeze({
|
|
3603
|
+
return (typeof key != "string" || !identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable"), Object.freeze({
|
|
3390
3604
|
describe: () => describeAppRoutine(key),
|
|
3391
3605
|
async run(...args) {
|
|
3392
3606
|
args.length > 1 && fail3("invalid_input");
|
|
@@ -3401,19 +3615,18 @@ function appRoutineBinding(key) {
|
|
|
3401
3615
|
} catch {
|
|
3402
3616
|
return fail3("invalid_input");
|
|
3403
3617
|
}
|
|
3404
|
-
let context2 = await
|
|
3618
|
+
let context2 = await local2(), run = summary(await request(key, "runs", { method: "POST", body: encoded }, SUMMARY_BYTES, context2), key);
|
|
3405
3619
|
return handle(key, run.id, context2);
|
|
3406
3620
|
},
|
|
3407
3621
|
runs: Object.freeze({
|
|
3408
3622
|
async list() {
|
|
3409
|
-
let value = await request(key, "runs", void 0, 20 * SUMMARY_BYTES);
|
|
3623
|
+
let value = await request(key, "runs", void 0, 20 * SUMMARY_BYTES, void 0, !0);
|
|
3410
3624
|
if (!Array.isArray(value) || value.length > 20) return fail3("execution_unavailable");
|
|
3411
3625
|
let runs = value.map((run) => summary(run, key));
|
|
3412
3626
|
return new Set(runs.map((run) => run.id)).size !== runs.length && fail3("execution_unavailable"), runs;
|
|
3413
3627
|
},
|
|
3414
3628
|
async get(id3) {
|
|
3415
|
-
|
|
3416
|
-
return await run.current(), run;
|
|
3629
|
+
return (typeof id3 != "string" || !uuid.test(id3)) && fail3("invalid_input"), (!identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable"), handle(key, id3, await local2(!0));
|
|
3417
3630
|
}
|
|
3418
3631
|
})
|
|
3419
3632
|
});
|
|
@@ -3421,6 +3634,7 @@ function appRoutineBinding(key) {
|
|
|
3421
3634
|
|
|
3422
3635
|
var app = Object.freeze({
|
|
3423
3636
|
listRoutines: () => Promise.all(appDescriptors().map(({ id: id3 }) => describeAppRoutine(id3))),
|
|
3637
|
+
routine: appRoutineBinding,
|
|
3424
3638
|
routines: new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
3425
3639
|
get(_target, key) {
|
|
3426
3640
|
if (!(typeof key != "string" || !appDescriptors().some((item) => item.id === key)))
|
|
@@ -3460,10 +3674,10 @@ function routineDataEnvelope(command) {
|
|
|
3460
3674
|
}
|
|
3461
3675
|
|
|
3462
3676
|
function routinePublicationClient2(options = {}) {
|
|
3463
|
-
let environment = {}, installed2 = routineTransport(),
|
|
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;
|
|
3464
3678
|
if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
|
|
3465
3679
|
throw new Error("A workspace and valid optional routine capability are required");
|
|
3466
|
-
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) => {
|
|
3467
3681
|
if (path === "/api/data") return fetch(`https://${workspace}.oddington.ai/api/data`, { ...init2, redirect: "error" });
|
|
3468
3682
|
let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
|
|
3469
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")
|
|
@@ -3473,13 +3687,13 @@ function routinePublicationClient2(options = {}) {
|
|
|
3473
3687
|
throw new Error("Member publication requires a host-supplied request");
|
|
3474
3688
|
});
|
|
3475
3689
|
async function send3(operation2, body) {
|
|
3476
|
-
if (
|
|
3690
|
+
if (local3) return await local3(operation2, body);
|
|
3477
3691
|
let writing = operation2 === "records/update", reading = operation2 === "records/read", response2 = await request2(writing || reading ? "/api/data" : `/api/inbox/${operation2}`, {
|
|
3478
3692
|
method: "POST",
|
|
3479
3693
|
headers: {
|
|
3480
3694
|
"content-type": "application/json",
|
|
3481
3695
|
...headers,
|
|
3482
|
-
...writing || reading ? { "x-
|
|
3696
|
+
...writing || reading ? { "x-os-workspace": workspace, "x-os-captured-records": "1" } : {}
|
|
3483
3697
|
},
|
|
3484
3698
|
body: JSON.stringify(writing ? routineDataEnvelope(validateRoutineRecordWrite(body)) : reading ? { operation: "records.select", request: validateRecordRead(body) } : body)
|
|
3485
3699
|
}), result2 = await response2.json();
|
|
@@ -3520,7 +3734,7 @@ function routinePublicationClient2(options = {}) {
|
|
|
3520
3734
|
files: {
|
|
3521
3735
|
async add(value) {
|
|
3522
3736
|
let input = validateFileAddOptions(value);
|
|
3523
|
-
if (
|
|
3737
|
+
if (local3) return validateInboxFile(await local3("files/add", input));
|
|
3524
3738
|
throw workingRoot ? new Error("Inbox file reads require a Node working root") : new Error("Inbox file reads require a working root");
|
|
3525
3739
|
}
|
|
3526
3740
|
},
|