@oddington/sdk 0.1.23 → 0.1.25
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 +401 -180
- package/dist/index.js +9 -9
- package/dist/types/packages/sdk/src/public.d.ts +11 -3
- package/dist/types/packages/sdk/src/routine-definition-types.d.ts +18 -1
- package/dist/types/shared/connection-runtime.d.ts +13 -2
- package/dist/types/shared/data-contract.d.ts +24 -2
- package/dist/types/shared/files-contract.d.ts +11 -2
- package/dist/types/shared/inbox-member-types.d.ts +2 -0
- package/dist/types/shared/routine-ai-contract.d.ts +40 -0
- package/dist/types/shared/routine-definition-contract.d.ts +1 -1
- package/dist/types/shared/routine-deployment-contract.d.ts +1 -1
- package/package.json +2 -2
package/dist/browser.js
CHANGED
|
@@ -405,44 +405,51 @@ var FileOperationError = class extends Error {
|
|
|
405
405
|
retryable;
|
|
406
406
|
}, FILE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/, FILE_ORIGINAL_MAX_BYTES = 5 * 1024 ** 3;
|
|
407
407
|
function parseFileDescriptor(value) {
|
|
408
|
-
let
|
|
408
|
+
let invalid8 = () => {
|
|
409
409
|
throw new FileOperationError("unavailable", 503, !0);
|
|
410
410
|
};
|
|
411
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
411
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
412
412
|
let f = value;
|
|
413
|
-
if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return
|
|
413
|
+
if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return invalid8();
|
|
414
414
|
let d = f.details;
|
|
415
415
|
if (d.kind === "other") {
|
|
416
|
-
if (Object.keys(d).length !== 1 ||
|
|
416
|
+
if (Object.keys(d).length !== 1 || ![
|
|
417
|
+
"application/octet-stream",
|
|
418
|
+
"text/plain",
|
|
419
|
+
"text/markdown",
|
|
420
|
+
"application/json",
|
|
421
|
+
"image/png",
|
|
422
|
+
"image/jpeg"
|
|
423
|
+
].includes(f.mediaType)) return invalid8();
|
|
417
424
|
} else if (d.kind === "csv") {
|
|
418
|
-
if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return
|
|
425
|
+
if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return invalid8();
|
|
419
426
|
} else if (d.kind === "pdf") {
|
|
420
|
-
if (f.mediaType !== "application/pdf" || Object.keys(d).some((key) => !["kind", "pages"].includes(key)) || "pages" in d && (!Number.isSafeInteger(d.pages) || d.pages < 1)) return
|
|
421
|
-
} else return
|
|
427
|
+
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();
|
|
428
|
+
} else return invalid8();
|
|
422
429
|
for (let [name, descriptor] of Object.entries(f.enrichments)) {
|
|
423
|
-
if (!safeEnrichmentName(name)) return
|
|
430
|
+
if (!safeEnrichmentName(name)) return invalid8();
|
|
424
431
|
parseEnrichmentDescriptor(descriptor);
|
|
425
432
|
}
|
|
426
|
-
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ?
|
|
433
|
+
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid8() : f;
|
|
427
434
|
}
|
|
428
435
|
function parseEnrichmentDescriptor(value) {
|
|
429
|
-
let
|
|
436
|
+
let invalid8 = () => {
|
|
430
437
|
throw new FileOperationError("unavailable", 503, !0);
|
|
431
438
|
};
|
|
432
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
439
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
433
440
|
let d = value;
|
|
434
|
-
return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ?
|
|
441
|
+
return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ? invalid8() : d;
|
|
435
442
|
}
|
|
436
443
|
function safeEnrichmentName(value) {
|
|
437
444
|
return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
|
|
438
445
|
}
|
|
439
446
|
function parseFileEnrichMetadata(value, maxBytes) {
|
|
440
|
-
let
|
|
447
|
+
let invalid8 = () => {
|
|
441
448
|
throw new FileOperationError("invalid_input", 400);
|
|
442
449
|
};
|
|
443
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
450
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
444
451
|
let d = value;
|
|
445
|
-
if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return
|
|
452
|
+
if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid8();
|
|
446
453
|
if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
447
454
|
return d;
|
|
448
455
|
}
|
|
@@ -452,31 +459,36 @@ function safeFileName(value) {
|
|
|
452
459
|
function safeFilePath(value) {
|
|
453
460
|
return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
|
|
454
461
|
}
|
|
462
|
+
var ORIGINAL_MEDIA_TYPES = ["application/pdf", "text/plain", "text/markdown", "application/json", "image/png", "image/jpeg"];
|
|
463
|
+
function declaredOriginalMediaType(value) {
|
|
464
|
+
let normalized = value.split(";", 1)[0].trim().toLowerCase();
|
|
465
|
+
return ORIGINAL_MEDIA_TYPES.includes(normalized) ? normalized : void 0;
|
|
466
|
+
}
|
|
455
467
|
function parseFileCreateMetadata(value, maxBytes) {
|
|
456
|
-
let
|
|
468
|
+
let invalid8 = () => {
|
|
457
469
|
throw new FileOperationError("invalid_input", 400);
|
|
458
470
|
};
|
|
459
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
471
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid8();
|
|
460
472
|
let input = value;
|
|
461
|
-
if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return
|
|
473
|
+
if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return invalid8();
|
|
462
474
|
let path = input.path === void 0 ? "Files" : input.path;
|
|
463
|
-
if (!safeFileName(input.name) || !safeFilePath(path) || path.split("/")[0].toLowerCase() === ".os" || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || input.inputMediaType !== void 0 && input.inputMediaType
|
|
475
|
+
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 && (typeof input.inputMediaType != "string" || !ORIGINAL_MEDIA_TYPES.includes(input.inputMediaType)) || !Number.isSafeInteger(input.size) || input.size < 0) return invalid8();
|
|
464
476
|
if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
465
|
-
if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return
|
|
477
|
+
if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return invalid8();
|
|
466
478
|
let csv;
|
|
467
479
|
if (input.csv !== void 0) {
|
|
468
|
-
if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return
|
|
480
|
+
if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid8();
|
|
469
481
|
let hints = input.csv;
|
|
470
|
-
if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return
|
|
482
|
+
if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid8();
|
|
471
483
|
let encoding = hints.encoding === void 0 ? "utf-8" : hints.encoding, delimiter = hints.delimiter === void 0 ? "," : hints.delimiter, headerRow = hints.headerRow === void 0 ? 1 : hints.headerRow;
|
|
472
|
-
if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return
|
|
484
|
+
if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid8();
|
|
473
485
|
csv = { encoding, delimiter, headerRow };
|
|
474
486
|
}
|
|
475
487
|
return {
|
|
476
488
|
name: input.name,
|
|
477
489
|
path,
|
|
478
490
|
...input.storage ? { storage: input.storage } : {},
|
|
479
|
-
...input.inputMediaType ===
|
|
491
|
+
...input.inputMediaType === void 0 ? {} : { inputMediaType: input.inputMediaType },
|
|
480
492
|
...csv ? { csv } : {},
|
|
481
493
|
size: input.size,
|
|
482
494
|
requestKey: input.requestKey
|
|
@@ -590,14 +602,16 @@ function validateRoutineSchemaValue(schema2, value) {
|
|
|
590
602
|
var ROUTINE_DECLARATION_SCHEMA = "https://schemas.oddington.ai/routine/v1.json", ROUTINE_SOURCE_LIMITS = { files: 2e4, bytes: 256 * 1024 * 1024, declarationBytes: 64 * 1024 };
|
|
591
603
|
var invalid = (field) => {
|
|
592
604
|
throw new Error(`Invalid routine declaration: ${field}`);
|
|
593
|
-
}, object2 = (value, fields5, field) => ((!value || typeof value != "object" || Array.isArray(value) || Object.
|
|
605
|
+
}, object2 = (value, fields5, field) => ((!value || typeof value != "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null || Reflect.ownKeys(value).some((key) => typeof key != "string" || !fields5.includes(key) || !Object.getOwnPropertyDescriptor(value, key).enumerable || !Object.hasOwn(Object.getOwnPropertyDescriptor(value, key), "value"))) && invalid(field), value), routineAlias = (value) => typeof value == "string" && /^[a-z][a-z0-9-]{0,62}$/.test(value), list = (value, field, allowed, qualified = !1) => value === void 0 ? [] : ((!Array.isArray(value) || value.length > 64 || value.some((item) => !(routineAlias(item) || qualified && typeof item == "string" && item.split("/").length === 2 && item.split("/").every(routineAlias)) || allowed && !allowed.includes(item)) || new Set(value).size !== value.length) && invalid(field), [...value].sort());
|
|
594
606
|
function routineAssetPattern(value) {
|
|
595
607
|
return typeof value == "string" && value.length <= 512 && !value.startsWith("/") && !value.includes("\\") && !value.includes(":") && value.split("/").every((part) => !!part && part !== "." && part !== ".." && /^[a-zA-Z0-9_.*-]+$/.test(part));
|
|
596
608
|
}
|
|
597
609
|
function parseRoutineDeclaration(value) {
|
|
598
610
|
let v = object2(value, ["$schema", "access", "runtime", "retry", "assets"], "fields");
|
|
599
611
|
v.$schema !== ROUTINE_DECLARATION_SCHEMA && invalid("$schema");
|
|
600
|
-
let access = object2(v.access === void 0 ? {} : v.access, ["repositories", "connections", "
|
|
612
|
+
let access = object2(v.access === void 0 ? {} : v.access, ["repositories", "connections", "ai", "files", "publish"], "access");
|
|
613
|
+
Object.hasOwn(access, "ai") && access.ai !== !0 && invalid("access.ai");
|
|
614
|
+
let rawRepositories = access.repositories === void 0 ? {} : access.repositories, repositories = object2(rawRepositories, rawRepositories && typeof rawRepositories == "object" ? Object.keys(rawRepositories) : [], "access.repositories");
|
|
601
615
|
Object.keys(repositories).length > 64 && invalid("access.repositories");
|
|
602
616
|
let grants = {};
|
|
603
617
|
for (let key of Object.keys(repositories).sort())
|
|
@@ -615,7 +629,7 @@ function parseRoutineDeclaration(value) {
|
|
|
615
629
|
access: {
|
|
616
630
|
repositories: grants,
|
|
617
631
|
connections: list(access.connections, "access.connections", void 0, !0),
|
|
618
|
-
|
|
632
|
+
...access.ai === !0 ? { ai: !0 } : {},
|
|
619
633
|
...access.files === void 0 ? {} : { files: access.files },
|
|
620
634
|
publish: list(access.publish, "access.publish", ["asks", "digests"])
|
|
621
635
|
},
|
|
@@ -663,7 +677,7 @@ function assertRoutineFields(value, allowed) {
|
|
|
663
677
|
}
|
|
664
678
|
function parseRoutineAccess(value) {
|
|
665
679
|
try {
|
|
666
|
-
value !== void 0 && assertRoutineJson(value), assertRoutineFields(value ?? {}, ["repositories", "connections", "
|
|
680
|
+
value !== void 0 && assertRoutineJson(value), assertRoutineFields(value ?? {}, ["repositories", "connections", "ai", "files", "publish"]);
|
|
667
681
|
let access = value, names = access?.connections ?? [];
|
|
668
682
|
if (!Array.isArray(names) || names.length > 64 || new Set(names).size !== names.length || names.some((name) => typeof name != "string" || name.split("/").length !== 2 || name.split("/").some((part) => !isAppRoutineName(part)))) return invalidContract2();
|
|
669
683
|
let parsed = parseRoutineDeclaration({ $schema: ROUTINE_DECLARATION_SCHEMA, access: { ...access, connections: [] } }).access;
|
|
@@ -673,6 +687,52 @@ function parseRoutineAccess(value) {
|
|
|
673
687
|
}
|
|
674
688
|
}
|
|
675
689
|
|
|
690
|
+
var ROUTINE_AI_VALUE_BYTES = 256 * 1024, ROUTINE_AI_EVIDENCE_BYTES = 4 * 1024;
|
|
691
|
+
var RoutineAIError = class extends Error {
|
|
692
|
+
constructor(code) {
|
|
693
|
+
super(code);
|
|
694
|
+
this.code = code;
|
|
695
|
+
this.name = "RoutineAIError";
|
|
696
|
+
}
|
|
697
|
+
code;
|
|
698
|
+
};
|
|
699
|
+
function capture(value, invalid8, oversized) {
|
|
700
|
+
try {
|
|
701
|
+
assertRoutineJson(value);
|
|
702
|
+
let encoded = JSON.stringify(value);
|
|
703
|
+
if (new TextEncoder().encode(encoded).byteLength > ROUTINE_AI_VALUE_BYTES) throw new RoutineAIError(oversized);
|
|
704
|
+
return freezeRoutineMetadata(JSON.parse(encoded));
|
|
705
|
+
} catch (error) {
|
|
706
|
+
throw error instanceof RoutineAIError ? error : new RoutineAIError(invalid8);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
function parseRoutineAIRequest(value) {
|
|
710
|
+
let v = capture(value, "invalid_input", "input_too_large");
|
|
711
|
+
try {
|
|
712
|
+
if (assertRoutineFields(v, v.kind === "generateObject" ? ["kind", "instructions", "input", "schema"] : ["kind", "instructions", "input"]), !["generateText", "generateObject"].includes(v.kind) || typeof v.instructions != "string" || !v.instructions.trim()) throw new Error();
|
|
713
|
+
let input = typeof v.input == "string" ? v.input : parseFileDescriptor(v.input);
|
|
714
|
+
if (v.kind === "generateText") return freezeRoutineMetadata({ kind: v.kind, instructions: v.instructions, input });
|
|
715
|
+
let schema2 = parseAppRoutineContract({ routine: "ai", input: v.schema, steps: [{ id: "generate" }] }).input;
|
|
716
|
+
return freezeRoutineMetadata({ kind: v.kind, instructions: v.instructions, input, schema: schema2 });
|
|
717
|
+
} catch {
|
|
718
|
+
throw new RoutineAIError("invalid_input");
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
function parseRoutineAIResult(request2, value) {
|
|
722
|
+
let v = capture(value, "invalid_output", "output_too_large");
|
|
723
|
+
try {
|
|
724
|
+
if (request2.kind === "generateText") {
|
|
725
|
+
if (assertRoutineFields(v, ["text"]), typeof v.text != "string" || !v.text.trim()) throw new Error();
|
|
726
|
+
return freezeRoutineMetadata({ text: v.text });
|
|
727
|
+
} else {
|
|
728
|
+
if (assertRoutineFields(v, ["object"]), !Object.hasOwn(v, "object")) throw new Error();
|
|
729
|
+
return validateRoutineSchemaValue(request2.schema, v.object), freezeRoutineMetadata({ object: v.object });
|
|
730
|
+
}
|
|
731
|
+
} catch {
|
|
732
|
+
throw new RoutineAIError("invalid_output");
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
676
736
|
var LIMIT = 256 * 1024, invalid3 = () => {
|
|
677
737
|
throw new AppRoutineContractError("invalid_value");
|
|
678
738
|
}, invalidContract3 = () => {
|
|
@@ -683,7 +743,7 @@ function captureJson(value) {
|
|
|
683
743
|
let encoded = JSON.stringify(value);
|
|
684
744
|
return new TextEncoder().encode(encoded).byteLength > LIMIT ? invalid3() : freezeRoutineMetadata(JSON.parse(encoded));
|
|
685
745
|
}
|
|
686
|
-
function
|
|
746
|
+
function capture2(schema2, value) {
|
|
687
747
|
let captured = captureJson(value);
|
|
688
748
|
return validateRoutineSchemaValue(schema2, captured), captured;
|
|
689
749
|
}
|
|
@@ -709,7 +769,7 @@ function declaration(value, defaults) {
|
|
|
709
769
|
} catch {
|
|
710
770
|
return invalidContract3();
|
|
711
771
|
}
|
|
712
|
-
let parsed = freezeRoutineMetadata(parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input), captured = defaults ?
|
|
772
|
+
let parsed = freezeRoutineMetadata(parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input), captured = defaults ? capture2(parsed, defaults.value) : void 0, builder = Object.defineProperty({ ...parsed }, "default", { value: (value2) => declaration(parsed, { value: value2 }) });
|
|
713
773
|
return schemas.set(builder, { schema: parsed, ...defaults ? { default: captured } : {} }), Object.freeze(builder);
|
|
714
774
|
}
|
|
715
775
|
var schema = {
|
|
@@ -794,10 +854,32 @@ function inspectRoutineDefinition(definition) {
|
|
|
794
854
|
}
|
|
795
855
|
function captureRoutineInput(definition, input) {
|
|
796
856
|
let contract = inspectRoutineDefinition(definition);
|
|
797
|
-
return
|
|
857
|
+
return capture2(contract.input, input === void 0 && Object.hasOwn(contract, "inputDefault") ? contract.inputDefault : input);
|
|
798
858
|
}
|
|
799
859
|
async function executeRoutineDefinition(definition, input, runtime) {
|
|
800
|
-
let captured = captureRoutineInput(definition, input), { contract, steps, run } = definitions.get(definition), active2 = !0, accepting = !0, broken = !1, work = Promise.resolve(),
|
|
860
|
+
let captured = captureRoutineInput(definition, input), { contract, steps, run } = definitions.get(definition), active2 = !0, accepting = !0, broken = !1, work = Promise.resolve(), aiFailure, aiWork = /* @__PURE__ */ new Set(), generate = (kind, value) => {
|
|
861
|
+
let operation2 = (async () => {
|
|
862
|
+
if (!active2 || broken || contract.access.ai !== !0) throw new RoutineAIError("access_denied");
|
|
863
|
+
if (!runtime.ai) throw new RoutineAIError("capability_unavailable");
|
|
864
|
+
let request2;
|
|
865
|
+
try {
|
|
866
|
+
assertRoutineFields(value, kind === "generateObject" ? ["instructions", "input", "schema"] : ["instructions", "input"]), request2 = parseRoutineAIRequest({
|
|
867
|
+
kind,
|
|
868
|
+
instructions: value.instructions,
|
|
869
|
+
input: value.input,
|
|
870
|
+
...kind === "generateObject" ? { schema: schemaMetadata(value.schema).schema } : {}
|
|
871
|
+
});
|
|
872
|
+
} catch (error) {
|
|
873
|
+
throw error instanceof RoutineAIError ? error : new RoutineAIError("invalid_input");
|
|
874
|
+
}
|
|
875
|
+
let result3 = await runtime.ai[kind](request2);
|
|
876
|
+
if (!active2 || broken) throw new RoutineAIError("access_denied");
|
|
877
|
+
return parseRoutineAIResult(request2, result3);
|
|
878
|
+
})();
|
|
879
|
+
return aiWork.add(operation2), operation2.then(() => aiWork.delete(operation2), (error) => {
|
|
880
|
+
aiFailure ??= error, broken = !0, aiWork.delete(operation2);
|
|
881
|
+
}), operation2;
|
|
882
|
+
}, called = /* @__PURE__ */ new Set(), reached = /* @__PURE__ */ new Set(), guarded = (value, receiver) => typeof value == "function" ? (...args) => {
|
|
801
883
|
if (!active2 || broken) throw new Error("Run authority ended");
|
|
802
884
|
return guarded(Reflect.apply(value, receiver, args));
|
|
803
885
|
} : value && typeof value == "object" && !(value instanceof Promise) ? new Proxy({ ...value }, {
|
|
@@ -810,6 +892,10 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
810
892
|
...guarded({
|
|
811
893
|
...runtime,
|
|
812
894
|
run: freezeRoutineMetadata({ ...runtime.run }),
|
|
895
|
+
ai: {
|
|
896
|
+
generateText: (value) => generate("generateText", value),
|
|
897
|
+
generateObject: (value) => generate("generateObject", value)
|
|
898
|
+
},
|
|
813
899
|
connections: { ...runtime.connections, get: async (identity) => {
|
|
814
900
|
if (!active2 || broken || !contract.access.connections?.includes(identity)) throw new Error("Connection unavailable");
|
|
815
901
|
let value = await runtime.connections.get(identity);
|
|
@@ -850,10 +936,11 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
850
936
|
} catch (error) {
|
|
851
937
|
failure = error, broken = !0;
|
|
852
938
|
}
|
|
853
|
-
accepting = !1, await work
|
|
939
|
+
for (accepting = !1, await work; aiWork.size; ) await Promise.allSettled([...aiWork]);
|
|
940
|
+
active2 = !1;
|
|
854
941
|
for (let step of contract.steps) reached.has(step.id) || await runtime.step(step.id, { status: "skipped" });
|
|
855
|
-
if (broken) throw failure ?? new AppRoutineContractError("invalid_value");
|
|
856
|
-
if (contract.result !== void 0) return
|
|
942
|
+
if (broken) throw failure ?? aiFailure ?? new AppRoutineContractError("invalid_value");
|
|
943
|
+
if (contract.result !== void 0) return capture2(contract.result, result2);
|
|
857
944
|
if (result2 !== void 0) return invalid3();
|
|
858
945
|
}
|
|
859
946
|
|
|
@@ -957,6 +1044,15 @@ function captureRecordsSearchInput(query, options) {
|
|
|
957
1044
|
return { query, options: captured };
|
|
958
1045
|
}
|
|
959
1046
|
|
|
1047
|
+
function captureRecordsReadRefs(value) {
|
|
1048
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > 100)
|
|
1049
|
+
throw new DataOperationError("invalid_query");
|
|
1050
|
+
let refs = historyArray(value);
|
|
1051
|
+
if (!refs.every((ref) => validRecordRef(ref) && !/[\r\n]/.test(ref)) || new Set(refs).size !== refs.length)
|
|
1052
|
+
throw new DataOperationError("invalid_query");
|
|
1053
|
+
return refs;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
960
1056
|
var DATA_REQUEST_LIMIT = 256 * 1024, invalidChange = () => {
|
|
961
1057
|
throw new DataOperationError("invalid_change", !1, "unapplied");
|
|
962
1058
|
};
|
|
@@ -1109,14 +1205,102 @@ async function resolveFilesContext() {
|
|
|
1109
1205
|
}
|
|
1110
1206
|
function filesContext(workspace, endpoint, headers) {
|
|
1111
1207
|
if (!workspace || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(workspace) || workspace.length > 63 || ["auth", "www", "api", "os"].includes(workspace) || endpoint !== `https://${workspace}.oddington.ai`) throw new Error();
|
|
1112
|
-
return { url: `${endpoint}/api/files`, headers: { ...headers, "x-
|
|
1208
|
+
return { url: `${endpoint}/api/files`, headers: { ...headers, "x-os-workspace": workspace }, isCurrent: () => !0 };
|
|
1113
1209
|
}
|
|
1114
1210
|
function checked(workspace, endpoint, headers) {
|
|
1115
1211
|
if (!workspace || !/^[a-z0-9][a-z0-9-]{0,127}$/.test(workspace)) throw new Error();
|
|
1116
1212
|
let origin = new URL(endpoint);
|
|
1117
1213
|
if (origin.protocol !== "https:" || origin.username || origin.password || origin.search || origin.hash || origin.pathname !== "/")
|
|
1118
1214
|
throw new Error();
|
|
1119
|
-
return { url: `${origin.origin}/api/data`, headers: { ...headers, "x-
|
|
1215
|
+
return { url: `${origin.origin}/api/data`, headers: { ...headers, "x-os-workspace": workspace } };
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
var invalid6 = () => {
|
|
1219
|
+
throw new DataOperationError("invalid_query");
|
|
1220
|
+
}, unavailable = () => {
|
|
1221
|
+
throw new DataOperationError("unavailable");
|
|
1222
|
+
}, text2 = (value) => typeof value == "string" && value.length > 0;
|
|
1223
|
+
function capture3(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
|
|
1224
|
+
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return value;
|
|
1225
|
+
if (!value || typeof value != "object" || ancestors.has(value) || depth > 32) return invalid6();
|
|
1226
|
+
ancestors.add(value);
|
|
1227
|
+
try {
|
|
1228
|
+
return Array.isArray(value) ? historyArray(value).map((item) => capture3(item, ancestors, depth + 1)) : Object.fromEntries(Object.entries(historyProperties(value)).map(([key, descriptor]) => [key, capture3(descriptor.value, ancestors, depth + 1)]));
|
|
1229
|
+
} finally {
|
|
1230
|
+
ancestors.delete(value);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
function recordPagination(select) {
|
|
1234
|
+
function pages(query) {
|
|
1235
|
+
let captured = capture3(query), names = Object.keys(historyProperties(captured));
|
|
1236
|
+
for (let name of names) {
|
|
1237
|
+
let selection2 = historyProperties(captured[name]);
|
|
1238
|
+
if (Object.hasOwn(selection2, "$")) {
|
|
1239
|
+
let options = historyProperties(selection2.$.value);
|
|
1240
|
+
if (Object.hasOwn(options, "after")) return invalid6();
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
return iterate();
|
|
1244
|
+
async function* iterate() {
|
|
1245
|
+
let state = new Map(names.map((name) => [name, {
|
|
1246
|
+
seen: /* @__PURE__ */ new Set(),
|
|
1247
|
+
total: 0,
|
|
1248
|
+
count: void 0,
|
|
1249
|
+
next: void 0
|
|
1250
|
+
}])), active2 = names, version;
|
|
1251
|
+
do {
|
|
1252
|
+
let request2 = Object.fromEntries(active2.map((name) => {
|
|
1253
|
+
let selection2 = captured[name], next = state.get(name).next;
|
|
1254
|
+
return [name, next === void 0 ? selection2 : { ...selection2, $: { ...selection2.$, after: next } }];
|
|
1255
|
+
})), response2 = await select(request2), page;
|
|
1256
|
+
try {
|
|
1257
|
+
page = capture3(response2);
|
|
1258
|
+
let keys4 = Object.keys(historyProperties(page));
|
|
1259
|
+
(keys4.length !== active2.length + 1 || keys4.some((key) => key !== "$meta" && !active2.includes(key))) && unavailable();
|
|
1260
|
+
let meta = page.$meta;
|
|
1261
|
+
(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();
|
|
1262
|
+
for (let name of active2) {
|
|
1263
|
+
let records = historyArray(page[name]), metadata = Object.hasOwn(meta.collections, name) ? meta.collections[name] : {};
|
|
1264
|
+
(Object.keys(historyProperties(metadata)).some((key) => key !== "count" && key !== "next") || Object.hasOwn(metadata, "next") && !text2(metadata.next)) && unavailable();
|
|
1265
|
+
for (let record3 of records) {
|
|
1266
|
+
historyProperties(record3);
|
|
1267
|
+
let row = record3;
|
|
1268
|
+
(!validRecordRef(row.$ref) || !text2(row.$version)) && unavailable();
|
|
1269
|
+
}
|
|
1270
|
+
let current2 = state.get(name);
|
|
1271
|
+
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;
|
|
1272
|
+
}
|
|
1273
|
+
} catch {
|
|
1274
|
+
return unavailable();
|
|
1275
|
+
}
|
|
1276
|
+
let collections = Object.fromEntries(names.map((name) => {
|
|
1277
|
+
let current2 = state.get(name);
|
|
1278
|
+
return [name, {
|
|
1279
|
+
...current2.count === void 0 ? {} : { count: current2.count },
|
|
1280
|
+
...current2.next === void 0 ? {} : { next: current2.next }
|
|
1281
|
+
}];
|
|
1282
|
+
})), output = Object.fromEntries(names.map((name) => [name, active2.includes(name) ? page[name] : []]));
|
|
1283
|
+
active2 = active2.filter((name) => state.get(name).next !== void 0), yield { ...output, $meta: { version, collections } };
|
|
1284
|
+
} while (active2.length);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
async function all(query, options) {
|
|
1288
|
+
let properties = historyProperties(options), maxRecords = properties.maxRecords?.value;
|
|
1289
|
+
(Object.keys(properties).join(",") !== "maxRecords" || !Number.isSafeInteger(maxRecords) || maxRecords < 1) && invalid6();
|
|
1290
|
+
let result2, total = 0;
|
|
1291
|
+
for await (let page of pages(query)) {
|
|
1292
|
+
let names = Object.keys(page.$meta.collections), size = names.reduce((sum, name) => sum + page[name].length, 0);
|
|
1293
|
+
if (size > maxRecords - total) throw new DataOperationError("capacity");
|
|
1294
|
+
total += size, result2 ??= { ...Object.fromEntries(names.map((name) => [name, []])), $meta: page.$meta };
|
|
1295
|
+
for (let name of names) {
|
|
1296
|
+
let target = result2[name];
|
|
1297
|
+
for (let record3 of page[name]) target.push(record3);
|
|
1298
|
+
}
|
|
1299
|
+
result2.$meta = page.$meta;
|
|
1300
|
+
}
|
|
1301
|
+
return result2;
|
|
1302
|
+
}
|
|
1303
|
+
return { pages, all };
|
|
1120
1304
|
}
|
|
1121
1305
|
|
|
1122
1306
|
var data = {
|
|
@@ -1139,13 +1323,20 @@ var data = {
|
|
|
1139
1323
|
throw error instanceof DataOperationError ? error : new DataOperationError("unavailable", !0);
|
|
1140
1324
|
}
|
|
1141
1325
|
}
|
|
1326
|
+
async function read2(input) {
|
|
1327
|
+
let refs = captureRecordsReadRefs(typeof input == "string" ? [input] : input), result2 = await send3({ operation: "records.read", refs });
|
|
1328
|
+
return typeof input == "string" ? result2.records[0] : result2;
|
|
1329
|
+
}
|
|
1330
|
+
let select = (query) => send3({ operation: "records.select", query });
|
|
1142
1331
|
return {
|
|
1143
1332
|
collections: {
|
|
1144
1333
|
list: () => send3({ operation: "collections.list" }),
|
|
1145
1334
|
schema: (name) => send3({ operation: "collections.schema", name })
|
|
1146
1335
|
},
|
|
1147
1336
|
records: {
|
|
1148
|
-
|
|
1337
|
+
read: read2,
|
|
1338
|
+
select,
|
|
1339
|
+
...recordPagination(select),
|
|
1149
1340
|
search: async (query, options) => send3({ operation: "records.search", ...captureRecordsSearchInput(query, options) })
|
|
1150
1341
|
},
|
|
1151
1342
|
history: {
|
|
@@ -1270,7 +1461,7 @@ async function hostedContent(url, init2, parent, upstream = fetch, check = async
|
|
|
1270
1461
|
}
|
|
1271
1462
|
}
|
|
1272
1463
|
|
|
1273
|
-
var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0,
|
|
1464
|
+
var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0, invalid7 = () => new FileOperationError("invalid_input", 400), unavailable2 = () => new FileOperationError("unavailable", 503, !0), failures = {
|
|
1274
1465
|
400: ["invalid_input", "unsupported_context"],
|
|
1275
1466
|
401: ["unauthenticated"],
|
|
1276
1467
|
403: ["access_denied"],
|
|
@@ -1290,9 +1481,9 @@ async function boundedBytes(stream, limit, signal) {
|
|
|
1290
1481
|
try {
|
|
1291
1482
|
for (; ; ) {
|
|
1292
1483
|
let { done, value } = await reader.read();
|
|
1293
|
-
if (signal?.aborted) throw
|
|
1484
|
+
if (signal?.aborted) throw unavailable2();
|
|
1294
1485
|
if (done) break;
|
|
1295
|
-
if (!(value instanceof Uint8Array)) throw
|
|
1486
|
+
if (!(value instanceof Uint8Array)) throw invalid7();
|
|
1296
1487
|
if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
|
|
1297
1488
|
bytes.set(value, size - value.byteLength);
|
|
1298
1489
|
}
|
|
@@ -1306,7 +1497,7 @@ async function boundedBytes(stream, limit, signal) {
|
|
|
1306
1497
|
async function timed(work, parent, timeout = TIMEOUT_MS) {
|
|
1307
1498
|
let controller = new AbortController(), timer, abort, expiry = new Promise((_, reject) => {
|
|
1308
1499
|
abort = () => {
|
|
1309
|
-
controller.abort(), reject(
|
|
1500
|
+
controller.abort(), reject(unavailable2());
|
|
1310
1501
|
}, timer = setTimeout(abort, timeout), parent?.addEventListener("abort", abort, { once: !0 }), parent?.aborted && abort();
|
|
1311
1502
|
});
|
|
1312
1503
|
try {
|
|
@@ -1320,12 +1511,12 @@ async function result(response2, maximum = RESULT_BYTES) {
|
|
|
1320
1511
|
let bytes = await boundedBytes(response2.body, maximum);
|
|
1321
1512
|
return JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes));
|
|
1322
1513
|
} catch {
|
|
1323
|
-
throw
|
|
1514
|
+
throw unavailable2();
|
|
1324
1515
|
}
|
|
1325
1516
|
}
|
|
1326
1517
|
async function send(suffix, init2, descriptor, initial, parent) {
|
|
1327
1518
|
let original = initial, checkCurrent = (context2 = original) => {
|
|
1328
|
-
if (parent?.aborted) throw
|
|
1519
|
+
if (parent?.aborted) throw unavailable2();
|
|
1329
1520
|
if (!original.isCurrent() || context2.url !== original.url) throw new FileOperationError("unsupported_context", 400);
|
|
1330
1521
|
};
|
|
1331
1522
|
for (let attempt = 0; attempt < ATTEMPTS; attempt++) {
|
|
@@ -1345,11 +1536,11 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1345
1536
|
})();
|
|
1346
1537
|
if (!response2.ok) {
|
|
1347
1538
|
let value2 = await result(response2), error = value2 && typeof value2 == "object" && "error" in value2 ? value2.error : void 0, received = error && typeof error == "object" && "code" in error ? error.code : void 0, code = failures[response2.status]?.find((code2) => code2 === received);
|
|
1348
|
-
throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") :
|
|
1539
|
+
throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") : unavailable2();
|
|
1349
1540
|
}
|
|
1350
1541
|
if (response2.status !== (descriptor === 204 ? 204 : 200) || descriptor === 204 && response2.body !== null)
|
|
1351
1542
|
throw response2.body?.cancel().catch(() => {
|
|
1352
|
-
}),
|
|
1543
|
+
}), unavailable2();
|
|
1353
1544
|
try {
|
|
1354
1545
|
checkCurrent();
|
|
1355
1546
|
} catch (error) {
|
|
@@ -1363,21 +1554,21 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1363
1554
|
return checkCurrent(), value;
|
|
1364
1555
|
let parsed;
|
|
1365
1556
|
if (descriptor === "enrichment") {
|
|
1366
|
-
if (!value || typeof value != "object" || Array.isArray(value)) throw
|
|
1557
|
+
if (!value || typeof value != "object" || Array.isArray(value)) throw unavailable2();
|
|
1367
1558
|
let { name, ...metadata } = value;
|
|
1368
|
-
if (!safeEnrichmentName(name)) throw
|
|
1559
|
+
if (!safeEnrichmentName(name)) throw unavailable2();
|
|
1369
1560
|
parsed = { name, ...parseEnrichmentDescriptor(metadata) };
|
|
1370
1561
|
} else parsed = parseFileDescriptor(value);
|
|
1371
1562
|
return checkCurrent(), parsed;
|
|
1372
1563
|
} catch (error) {
|
|
1373
|
-
let failure = error instanceof FileOperationError ? error :
|
|
1564
|
+
let failure = error instanceof FileOperationError ? error : unavailable2();
|
|
1374
1565
|
if (init2.body instanceof ReadableStream || !failure.retryable || attempt + 1 === ATTEMPTS) throw failure;
|
|
1375
1566
|
}
|
|
1376
1567
|
}
|
|
1377
|
-
throw
|
|
1568
|
+
throw unavailable2();
|
|
1378
1569
|
}
|
|
1379
1570
|
function idPath(id3) {
|
|
1380
|
-
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw
|
|
1571
|
+
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid7();
|
|
1381
1572
|
return `/${id3}`;
|
|
1382
1573
|
}
|
|
1383
1574
|
async function multipartCreate(input, metadata, exchange, release = () => {
|
|
@@ -1388,18 +1579,18 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1388
1579
|
return pending.add(task), task.then(() => pending.delete(task), () => pending.delete(task)), task;
|
|
1389
1580
|
}, void 0, timeout), control = (body) => ({
|
|
1390
1581
|
method: "POST",
|
|
1391
|
-
headers: { "content-type": "application/json", ...ticket ? { "x-
|
|
1582
|
+
headers: { "content-type": "application/json", ...ticket ? { "x-os-transfer": ticket } : {} },
|
|
1392
1583
|
body: JSON.stringify(body)
|
|
1393
1584
|
});
|
|
1394
1585
|
try {
|
|
1395
1586
|
let start = await request2((signal) => exchange(`${route}/start`, control(upload?.file ?? metadata), "control", signal));
|
|
1396
|
-
if (!start || typeof start != "object" || Array.isArray(start)) throw
|
|
1587
|
+
if (!start || typeof start != "object" || Array.isArray(start)) throw unavailable2();
|
|
1397
1588
|
let session = start;
|
|
1398
|
-
if (Object.keys(session).sort().join(",") !== "partBytes,ticket" || session.partBytes !== PART_BYTES || typeof session.ticket != "string" || !session.ticket || session.ticket.length > 64 * 1024) throw
|
|
1589
|
+
if (Object.keys(session).sort().join(",") !== "partBytes,ticket" || session.partBytes !== PART_BYTES || typeof session.ticket != "string" || !session.ticket || session.ticket.length > 64 * 1024) throw unavailable2();
|
|
1399
1590
|
ticket = session.ticket, input.file instanceof ReadableStream && (reader = input.file.getReader());
|
|
1400
1591
|
let lastProgress = Date.now(), next = async () => {
|
|
1401
1592
|
try {
|
|
1402
|
-
if (Date.now() - lastProgress >= TIMEOUT_MS) throw
|
|
1593
|
+
if (Date.now() - lastProgress >= TIMEOUT_MS) throw unavailable2();
|
|
1403
1594
|
let value = await request2(() => reader.read(), Math.max(1, TIMEOUT_MS - (Date.now() - lastProgress)));
|
|
1404
1595
|
return value.value?.byteLength && (lastProgress = Date.now()), value;
|
|
1405
1596
|
} catch (error) {
|
|
@@ -1420,41 +1611,41 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1420
1611
|
if (!chunk || offset === chunk.byteLength) {
|
|
1421
1612
|
chunk = void 0, offset = 0;
|
|
1422
1613
|
let value2 = await next();
|
|
1423
|
-
if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw
|
|
1614
|
+
if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid7();
|
|
1424
1615
|
}
|
|
1425
1616
|
let take = Math.min(length - filled, chunk.byteLength - offset);
|
|
1426
1617
|
part.set(chunk.subarray(offset, offset + take), filled), filled += take, offset += take, offset === chunk.byteLength && (chunk = void 0, offset = 0);
|
|
1427
1618
|
}
|
|
1428
1619
|
}
|
|
1429
|
-
if (part.byteLength !== length) throw
|
|
1620
|
+
if (part.byteLength !== length) throw invalid7();
|
|
1430
1621
|
if (reader && sent + length === metadata.size)
|
|
1431
1622
|
for (lastProgress = Date.now(); ; ) {
|
|
1432
1623
|
let value2 = await next();
|
|
1433
1624
|
if (value2.done) break;
|
|
1434
|
-
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw
|
|
1625
|
+
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid7();
|
|
1435
1626
|
}
|
|
1436
1627
|
let value = await request2((signal) => exchange(`${route}/part`, {
|
|
1437
1628
|
method: "POST",
|
|
1438
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1629
|
+
headers: { "content-type": "application/octet-stream", "x-os-transfer": ticket, "x-os-part": String(partNumber) },
|
|
1439
1630
|
body: part.buffer
|
|
1440
1631
|
}, "control", signal));
|
|
1441
1632
|
part = void 0;
|
|
1442
1633
|
let receipt = value;
|
|
1443
|
-
if (!receipt || typeof receipt != "object" || Object.keys(receipt).sort().join(",") !== "etag,partNumber" || receipt.partNumber !== partNumber || typeof receipt.etag != "string" || !receipt.etag || receipt.etag.length > 256 || /[\u0000-\u001f\u007f]/.test(receipt.etag)) throw
|
|
1634
|
+
if (!receipt || typeof receipt != "object" || Object.keys(receipt).sort().join(",") !== "etag,partNumber" || receipt.partNumber !== partNumber || typeof receipt.etag != "string" || !receipt.etag || receipt.etag.length > 256 || /[\u0000-\u001f\u007f]/.test(receipt.etag)) throw unavailable2();
|
|
1444
1635
|
receipts.push({ partNumber, etag: receipt.etag }), sent += length, lastProgress = Date.now();
|
|
1445
1636
|
}
|
|
1446
1637
|
if (upload) for (let name of Object.keys(upload.file.enrichments)) {
|
|
1447
1638
|
let bytes = await request2(() => upload.enrichment(name));
|
|
1448
|
-
if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw
|
|
1639
|
+
if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid7();
|
|
1449
1640
|
await request2((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
|
|
1450
1641
|
method: "POST",
|
|
1451
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1642
|
+
headers: { "content-type": "application/octet-stream", "x-os-transfer": ticket },
|
|
1452
1643
|
body: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
|
|
1453
1644
|
}, "control", signal));
|
|
1454
1645
|
}
|
|
1455
1646
|
await upload?.beforeComplete();
|
|
1456
1647
|
let completion = control({ parts: receipts });
|
|
1457
|
-
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw
|
|
1648
|
+
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw unavailable2();
|
|
1458
1649
|
return parseFileDescriptor(await request2(
|
|
1459
1650
|
(signal) => exchange(`${route}/complete`, completion, !0, signal),
|
|
1460
1651
|
TIMEOUT_MS + Math.ceil(metadata.size / (1024 * 1024)) * 1e3
|
|
@@ -1462,7 +1653,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1462
1653
|
} catch (error) {
|
|
1463
1654
|
throw reader && await reader.cancel(error).catch(() => {
|
|
1464
1655
|
}), ticket && await request2((signal) => exchange(`${route}/abort`, control({}), "control", signal)).catch(() => {
|
|
1465
|
-
}), error instanceof FileOperationError ? error :
|
|
1656
|
+
}), error instanceof FileOperationError ? error : unavailable2();
|
|
1466
1657
|
} finally {
|
|
1467
1658
|
chunk = void 0, reader?.releaseLock(), pending.size ? Promise.allSettled([...pending]).then(release) : release();
|
|
1468
1659
|
}
|
|
@@ -1479,13 +1670,13 @@ async function operation(work, initial, parent) {
|
|
|
1479
1670
|
}
|
|
1480
1671
|
}, signal = context2.signal && parent ? AbortSignal.any([context2.signal, parent]) : context2.signal ?? parent;
|
|
1481
1672
|
return context2.localFiles ? execute(signal ?? new AbortController().signal) : timed(execute, signal).catch((error) => {
|
|
1482
|
-
throw error instanceof FileOperationError ? error :
|
|
1673
|
+
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1483
1674
|
});
|
|
1484
1675
|
}
|
|
1485
1676
|
function contentPath(id3, name) {
|
|
1486
1677
|
let path = idPath(id3);
|
|
1487
1678
|
if (name === void 0) return `${path}/content`;
|
|
1488
|
-
if (!safeEnrichmentName(name)) throw
|
|
1679
|
+
if (!safeEnrichmentName(name)) throw invalid7();
|
|
1489
1680
|
return `${path}/enrichments/${encodeURIComponent(name)}/content`;
|
|
1490
1681
|
}
|
|
1491
1682
|
async function read(id3, names) {
|
|
@@ -1494,12 +1685,12 @@ async function read(id3, names) {
|
|
|
1494
1685
|
let path = contentPath(id3, names);
|
|
1495
1686
|
return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
|
|
1496
1687
|
}
|
|
1497
|
-
if (!Array.isArray(names)) throw
|
|
1688
|
+
if (!Array.isArray(names)) throw invalid7();
|
|
1498
1689
|
let distinct = [], seen = /* @__PURE__ */ new Set();
|
|
1499
1690
|
for (let name of names) {
|
|
1500
|
-
if (typeof name != "string" || !safeEnrichmentName(name)) throw
|
|
1691
|
+
if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid7();
|
|
1501
1692
|
if (!seen.has(name)) {
|
|
1502
|
-
if (seen.size === 16) throw
|
|
1693
|
+
if (seen.size === 16) throw invalid7();
|
|
1503
1694
|
seen.add(name), distinct.push(name);
|
|
1504
1695
|
}
|
|
1505
1696
|
}
|
|
@@ -1527,32 +1718,32 @@ var files = {
|
|
|
1527
1718
|
async upload(id3) {
|
|
1528
1719
|
return operation(async (context2, signal) => {
|
|
1529
1720
|
let file2 = await send(`${idPath(id3)}/upload`, { method: "POST" }, !0, context2, signal);
|
|
1530
|
-
if (file2.id !== id3) throw
|
|
1721
|
+
if (file2.id !== id3) throw unavailable2();
|
|
1531
1722
|
return file2;
|
|
1532
1723
|
});
|
|
1533
1724
|
},
|
|
1534
1725
|
async create(input, options) {
|
|
1535
1726
|
let context2 = await resolveFilesContext();
|
|
1536
1727
|
if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "size", "path", "name", "storage", "csv"].includes(key)) || options !== void 0 && (!options || typeof options != "object" || Array.isArray(options) || Object.keys(options).some((key) => key !== "requestKey")))
|
|
1537
|
-
throw
|
|
1728
|
+
throw invalid7();
|
|
1538
1729
|
let blob = input.file instanceof Blob, array3 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
|
|
1539
|
-
if (!blob && !array3 && !stream) throw
|
|
1730
|
+
if (!blob && !array3 && !stream) throw invalid7();
|
|
1540
1731
|
let intrinsic = blob ? input.file.size : array3 ? input.file.byteLength : void 0;
|
|
1541
|
-
if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw
|
|
1732
|
+
if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid7();
|
|
1542
1733
|
let name = input.name;
|
|
1543
1734
|
name === void 0 && blob && "name" in input.file && typeof input.file.name == "string" && (name = typeof globalThis.File < "u" && input.file instanceof globalThis.File ? input.file.name : input.file.name.split(/[\\/]/).at(-1));
|
|
1544
|
-
let metadata = parseFileCreateMetadata({
|
|
1735
|
+
let inputMediaType = blob ? declaredOriginalMediaType(input.file.type) : void 0, metadata = parseFileCreateMetadata({
|
|
1545
1736
|
name,
|
|
1546
1737
|
size: intrinsic ?? input.size,
|
|
1547
1738
|
path: input.path,
|
|
1548
1739
|
storage: input.storage,
|
|
1549
1740
|
csv: input.csv,
|
|
1550
|
-
...
|
|
1741
|
+
...inputMediaType === void 0 ? {} : { inputMediaType },
|
|
1551
1742
|
requestKey: options?.requestKey === void 0 ? routineTransport()?.key("files") ?? crypto.randomUUID() : options.requestKey
|
|
1552
1743
|
}, FILE_ORIGINAL_MAX_BYTES);
|
|
1553
1744
|
if (!context2.local && !context2.localFiles && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
1554
1745
|
let header = encodeURIComponent(JSON.stringify(metadata));
|
|
1555
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1746
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1556
1747
|
if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
|
|
1557
1748
|
if (active++, context2.localFiles && !routineTransport() && metadata.size > MAX_BYTES) {
|
|
1558
1749
|
let signal = context2.signal ?? new AbortController().signal, file2 = input.file, offset = 0, body = file2 instanceof Blob ? context2.signal ? file2 : file2.stream() : file2 instanceof ReadableStream ? file2 : new ReadableStream({
|
|
@@ -1568,7 +1759,7 @@ var files = {
|
|
|
1568
1759
|
try {
|
|
1569
1760
|
return await send("", { method: "POST", headers: {
|
|
1570
1761
|
"content-type": "application/octet-stream",
|
|
1571
|
-
"x-
|
|
1762
|
+
"x-os-file": header
|
|
1572
1763
|
}, body }, !0, context2, signal);
|
|
1573
1764
|
} finally {
|
|
1574
1765
|
active--;
|
|
@@ -1581,23 +1772,23 @@ var files = {
|
|
|
1581
1772
|
metadata.size,
|
|
1582
1773
|
signal
|
|
1583
1774
|
);
|
|
1584
|
-
if (bytes.byteLength !== metadata.size) throw
|
|
1585
|
-
if (signal.aborted) throw
|
|
1775
|
+
if (bytes.byteLength !== metadata.size) throw invalid7();
|
|
1776
|
+
if (signal.aborted) throw unavailable2();
|
|
1586
1777
|
return await send("", {
|
|
1587
1778
|
method: "POST",
|
|
1588
|
-
headers: { "content-type": "application/octet-stream", "x-
|
|
1779
|
+
headers: { "content-type": "application/octet-stream", "x-os-file": header },
|
|
1589
1780
|
body: bytes.buffer
|
|
1590
1781
|
}, !0, context2, signal);
|
|
1591
1782
|
} finally {
|
|
1592
1783
|
active--;
|
|
1593
1784
|
}
|
|
1594
1785
|
}, context2.signal).catch((error) => {
|
|
1595
|
-
throw error instanceof FileOperationError ? error :
|
|
1786
|
+
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1596
1787
|
});
|
|
1597
1788
|
},
|
|
1598
1789
|
async enrich(input) {
|
|
1599
1790
|
let context2 = await resolveFilesContext();
|
|
1600
|
-
if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw
|
|
1791
|
+
if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw invalid7();
|
|
1601
1792
|
let path = `${idPath(input.file)}/enrichments`;
|
|
1602
1793
|
if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
|
|
1603
1794
|
throw new FileOperationError("request_too_large", 413);
|
|
@@ -1614,12 +1805,12 @@ var files = {
|
|
|
1614
1805
|
...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
|
|
1615
1806
|
...input.replace === void 0 ? {} : { replace: input.replace }
|
|
1616
1807
|
}, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
|
|
1617
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1808
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1618
1809
|
let result2 = await send(path, { method: "POST", headers: {
|
|
1619
1810
|
"content-type": "application/octet-stream",
|
|
1620
|
-
"x-
|
|
1811
|
+
"x-os-enrichment": header
|
|
1621
1812
|
}, body: bytes.buffer }, "enrichment", context3, signal);
|
|
1622
|
-
if (result2.name !== metadata.name) throw
|
|
1813
|
+
if (result2.name !== metadata.name) throw unavailable2();
|
|
1623
1814
|
return result2;
|
|
1624
1815
|
}, context2);
|
|
1625
1816
|
},
|
|
@@ -1629,29 +1820,58 @@ var files = {
|
|
|
1629
1820
|
read
|
|
1630
1821
|
};
|
|
1631
1822
|
|
|
1823
|
+
function validDropboxRootPath(value) {
|
|
1824
|
+
return typeof value == "string" && value.length <= 2048 && value.startsWith("/") && !/[\\\x00-\x1f\x7f]/.test(value) && value.slice(1).split("/").every((segment) => segment.length > 0 && segment.trim() === segment && segment !== "." && segment !== "..");
|
|
1825
|
+
}
|
|
1632
1826
|
function validGoogleScopes(value) {
|
|
1633
1827
|
return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every((scope) => typeof scope == "string" && scope.length <= 256 && /^(https:\/\/www\.googleapis\.com\/auth\/[A-Za-z0-9._-]+|https:\/\/mail\.google\.com\/|openid|email|profile)$/.test(scope)) && new Set(value).size === value.length;
|
|
1634
1828
|
}
|
|
1829
|
+
var DROPBOX_FILE_SCOPES = ["account_info.read", "files.metadata.read", "files.content.read", "files.content.write"];
|
|
1830
|
+
function validDropboxFileScopes(value) {
|
|
1831
|
+
return Array.isArray(value) && value.length === DROPBOX_FILE_SCOPES.length && new Set(value).size === value.length && DROPBOX_FILE_SCOPES.every((scope) => value.includes(scope));
|
|
1832
|
+
}
|
|
1635
1833
|
|
|
1636
|
-
var ROUTINE_CONNECTION_CREDENTIALS_ENV = "
|
|
1834
|
+
var ROUTINE_CONNECTION_CREDENTIALS_ENV = "OS_ROUTINE_CONNECTION_CREDENTIALS";
|
|
1835
|
+
function parseRoutineConnectionNames(value) {
|
|
1836
|
+
if (!Array.isArray(value) || value.some((name) => typeof name != "string" || !/^(gmail|airtable|dropbox)\/[a-z0-9][a-z0-9-]{0,62}$/.test(name)) || new Set(value).size !== value.length)
|
|
1837
|
+
throw new Error("Invalid routine connections");
|
|
1838
|
+
return value;
|
|
1839
|
+
}
|
|
1637
1840
|
var connectionUuid = (v) => typeof v == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(v);
|
|
1638
1841
|
function runtimeConnection(lease) {
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1842
|
+
switch (lease.provider) {
|
|
1843
|
+
case "gmail":
|
|
1844
|
+
return {
|
|
1845
|
+
id: `gmail/${lease.name}`,
|
|
1846
|
+
provider: lease.provider,
|
|
1847
|
+
name: lease.name,
|
|
1848
|
+
accountEmail: lease.accountEmail,
|
|
1849
|
+
scopes: [...lease.scopes],
|
|
1850
|
+
accessToken: lease.accessToken,
|
|
1851
|
+
expiresAt: lease.expiresAt
|
|
1852
|
+
};
|
|
1853
|
+
case "airtable":
|
|
1854
|
+
return {
|
|
1855
|
+
id: `airtable/${lease.name}`,
|
|
1856
|
+
provider: lease.provider,
|
|
1857
|
+
name: lease.name,
|
|
1858
|
+
baseId: lease.baseId,
|
|
1859
|
+
accessToken: lease.accessToken,
|
|
1860
|
+
runExpiresAt: lease.runExpiresAt
|
|
1861
|
+
};
|
|
1862
|
+
case "dropbox":
|
|
1863
|
+
return {
|
|
1864
|
+
id: `dropbox/${lease.name}`,
|
|
1865
|
+
provider: lease.provider,
|
|
1866
|
+
name: lease.name,
|
|
1867
|
+
accountId: lease.accountId,
|
|
1868
|
+
access: lease.access,
|
|
1869
|
+
rootPath: lease.rootPath,
|
|
1870
|
+
scopes: [...lease.scopes],
|
|
1871
|
+
accessToken: lease.accessToken,
|
|
1872
|
+
expiresAt: lease.expiresAt
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1655
1875
|
}
|
|
1656
1876
|
function parseConnectionLease(raw, now = Date.now()) {
|
|
1657
1877
|
let v = raw;
|
|
@@ -1662,7 +1882,7 @@ function parseConnectionLease(raw, now = Date.now()) {
|
|
|
1662
1882
|
throw new Error("Invalid connection credential");
|
|
1663
1883
|
return v;
|
|
1664
1884
|
}
|
|
1665
|
-
if (v.provider === "airtable" && Object.keys(v).sort().join(",") === "accessToken,baseId,connectionId,name,provider,runExpiresAt,runId" && typeof v.baseId == "string" && /^app[A-Za-z0-9]+$/.test(v.baseId) && typeof v.runExpiresAt == "string" && Number.isFinite(Date.parse(v.runExpiresAt)) && Date.parse(v.runExpiresAt) > now + 6e4 && Date.parse(v.runExpiresAt) <= now + 15 * 6e4)
|
|
1885
|
+
if (v.provider === "airtable" && Object.keys(v).sort().join(",") === "accessToken,baseId,connectionId,name,provider,runExpiresAt,runId" && typeof v.baseId == "string" && /^app[A-Za-z0-9]+$/.test(v.baseId) && typeof v.runExpiresAt == "string" && Number.isFinite(Date.parse(v.runExpiresAt)) && Date.parse(v.runExpiresAt) > now + 6e4 && Date.parse(v.runExpiresAt) <= now + 15 * 6e4 || v.provider === "dropbox" && Object.keys(v).sort().join(",") === "access,accessToken,accountId,connectionId,expiresAt,name,provider,rootPath,runId,scopes" && typeof v.accountId == "string" && /^dbid:[A-Za-z0-9_-]{1,128}$/.test(v.accountId) && v.access === "full_dropbox" && validDropboxRootPath(v.rootPath) && validDropboxFileScopes(v.scopes) && typeof v.expiresAt == "string" && Number.isFinite(Date.parse(v.expiresAt)) && Date.parse(v.expiresAt) > now + 6e4 && Date.parse(v.expiresAt) <= now + 144e5)
|
|
1666
1886
|
return v;
|
|
1667
1887
|
throw new Error("Invalid connection credential");
|
|
1668
1888
|
}
|
|
@@ -1688,12 +1908,12 @@ function object3(v) {
|
|
|
1688
1908
|
function keys2(v, allowed, required = allowed) {
|
|
1689
1909
|
(Object.keys(v).some((k) => !allowed.includes(k)) || required.some((k) => !Object.hasOwn(v, k))) && fail2("Invalid Airtable input");
|
|
1690
1910
|
}
|
|
1691
|
-
function
|
|
1911
|
+
function text3(v) {
|
|
1692
1912
|
return typeof v == "string" && v.length > 0 && v.length <= 1024;
|
|
1693
1913
|
}
|
|
1694
1914
|
function fields3(v, nonempty = !1) {
|
|
1695
1915
|
let result2 = object3(v);
|
|
1696
|
-
(nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !
|
|
1916
|
+
(nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !text3(k))) && fail2("Invalid Airtable fields");
|
|
1697
1917
|
try {
|
|
1698
1918
|
return serializable(result2);
|
|
1699
1919
|
} catch {
|
|
@@ -1780,10 +2000,10 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1780
2000
|
Array.isArray(page.tables) || fail2("Malformed Airtable tables");
|
|
1781
2001
|
for (let value of page.tables) {
|
|
1782
2002
|
let t = object3(value);
|
|
1783
|
-
(!tableId(t.id) || !
|
|
2003
|
+
(!tableId(t.id) || !text3(t.name) || !text3(t.primaryFieldId) || !Array.isArray(t.fields) || tables.some((existing) => existing.id === t.id)) && fail2("Malformed Airtable table");
|
|
1784
2004
|
let metadata = t.fields.map((value2) => {
|
|
1785
2005
|
let f = object3(value2);
|
|
1786
|
-
return (typeof f.id != "string" || !/^fld[A-Za-z0-9]+$/.test(f.id) || !
|
|
2006
|
+
return (typeof f.id != "string" || !/^fld[A-Za-z0-9]+$/.test(f.id) || !text3(f.name) || !text3(f.type)) && fail2("Malformed Airtable field"), { id: f.id, name: f.name, type: f.type, ...f.options === void 0 ? {} : { options: serializable(f.options) } };
|
|
1787
2007
|
});
|
|
1788
2008
|
(!metadata.some((f) => f.id === t.primaryFieldId) || new Set(metadata.map((f) => f.id)).size !== metadata.length) && fail2("Malformed Airtable fields"), tables.push({ id: t.id, name: t.name, primaryFieldId: t.primaryFieldId, fields: metadata });
|
|
1789
2009
|
}
|
|
@@ -1791,7 +2011,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1791
2011
|
} while (offset);
|
|
1792
2012
|
return tables;
|
|
1793
2013
|
}
|
|
1794
|
-
(!
|
|
2014
|
+
(!text3(input.table) || input.table === "." || input.table === "..") && fail2("Invalid Airtable table"), mutation && !tableId(input.table) && fail2("Airtable writes require a stable table ID");
|
|
1795
2015
|
let path = `${baseId}/${encodeURIComponent(input.table)}`;
|
|
1796
2016
|
if (operation2 === "records.get") {
|
|
1797
2017
|
keys2(input, ["table", "id"]), recordId(input.id) || fail2("Invalid Airtable record ID");
|
|
@@ -1799,7 +2019,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1799
2019
|
return result3.id !== input.id && fail2("Malformed Airtable record"), result3;
|
|
1800
2020
|
}
|
|
1801
2021
|
if (operation2 === "records.list") {
|
|
1802
|
-
keys2(input, ["table", "fields"], ["table"]), input.fields !== void 0 && (!Array.isArray(input.fields) || !input.fields.length || input.fields.some((f) => !
|
|
2022
|
+
keys2(input, ["table", "fields"], ["table"]), input.fields !== void 0 && (!Array.isArray(input.fields) || !input.fields.length || input.fields.some((f) => !text3(f)) || new Set(input.fields).size !== input.fields.length) && fail2("Invalid Airtable field selection");
|
|
1803
2023
|
let records2 = [], ids2 = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set(), offset;
|
|
1804
2024
|
do {
|
|
1805
2025
|
let query2 = new URLSearchParams();
|
|
@@ -1856,10 +2076,10 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1856
2076
|
}
|
|
1857
2077
|
function nextOffset(value, seen) {
|
|
1858
2078
|
if (value !== void 0)
|
|
1859
|
-
return (!
|
|
2079
|
+
return (!text3(value) || seen.has(value)) && fail2("Malformed Airtable pagination"), seen.add(value), value;
|
|
1860
2080
|
}
|
|
1861
2081
|
|
|
1862
|
-
var MANAGED_CONNECTION_CAPABILITY_ENV = "
|
|
2082
|
+
var MANAGED_CONNECTION_CAPABILITY_ENV = "OS_MANAGED_CONNECTION_CAPABILITY";
|
|
1863
2083
|
function managedConnections(capability) {
|
|
1864
2084
|
let endpoint = new URL(capability.endpoint);
|
|
1865
2085
|
if (endpoint.protocol !== "http:" || endpoint.hostname !== "127.0.0.1" || !endpoint.port || endpoint.pathname !== "/" || endpoint.search || endpoint.hash || endpoint.username || endpoint.password || !/^[0-9a-f-]{36}$/.test(capability.token)) throw new AirtableOperationError("Airtable capability unavailable");
|
|
@@ -2015,7 +2235,7 @@ function object4(value) {
|
|
|
2015
2235
|
function keys3(value, allowed, required = allowed) {
|
|
2016
2236
|
assert(Object.keys(value).every((key) => allowed.includes(key)) && required.every((key) => Object.hasOwn(value, key)));
|
|
2017
2237
|
}
|
|
2018
|
-
function
|
|
2238
|
+
function text4(value, empty2 = !1) {
|
|
2019
2239
|
return typeof value == "string" && (empty2 || !!value.trim());
|
|
2020
2240
|
}
|
|
2021
2241
|
function id2(value) {
|
|
@@ -2025,7 +2245,7 @@ function integer(value, minimum = 1) {
|
|
|
2025
2245
|
return Number.isSafeInteger(value) && Number(value) >= minimum;
|
|
2026
2246
|
}
|
|
2027
2247
|
function date(value) {
|
|
2028
|
-
return
|
|
2248
|
+
return text4(value) && Number.isFinite(Date.parse(value));
|
|
2029
2249
|
}
|
|
2030
2250
|
function optionalDate(value) {
|
|
2031
2251
|
return value === null || date(value);
|
|
@@ -2047,7 +2267,7 @@ function json(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
2047
2267
|
}
|
|
2048
2268
|
function recordReference(value) {
|
|
2049
2269
|
let record3 = object4(value);
|
|
2050
|
-
return keys3(record3, ["repository", "ref"]), assert(
|
|
2270
|
+
return keys3(record3, ["repository", "ref"]), assert(text4(record3.repository) && record3.repository === record3.repository.trim() && /^[a-z0-9][a-z0-9._/-]{0,127}$/.test(record3.repository) && !/\.\.|\/\//.test(record3.repository) && text4(record3.ref) && record3.ref === record3.ref.trim() && record3.ref.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)+$/.test(record3.ref)), record3;
|
|
2051
2271
|
}
|
|
2052
2272
|
function responseDefinition(value) {
|
|
2053
2273
|
let definition = object4(value);
|
|
@@ -2059,75 +2279,75 @@ function responseDefinition(value) {
|
|
|
2059
2279
|
assert(options.length > 0);
|
|
2060
2280
|
let values = options.map((value2) => {
|
|
2061
2281
|
let option = object4(value2);
|
|
2062
|
-
if (keys3(option, ["value", "label", "description", "note"], ["value", "label"]), assert(
|
|
2282
|
+
if (keys3(option, ["value", "label", "description", "note"], ["value", "label"]), assert(text4(option.value) && option.value === option.value.trim() && text4(option.label)), "description" in option && assert(text4(option.description)), "note" in option) {
|
|
2063
2283
|
let note = object4(option.note);
|
|
2064
|
-
keys3(note, ["placeholder"]), assert(
|
|
2284
|
+
keys3(note, ["placeholder"]), assert(text4(note.placeholder));
|
|
2065
2285
|
}
|
|
2066
2286
|
return option.value;
|
|
2067
2287
|
});
|
|
2068
2288
|
if (assert(new Set(values).size === values.length), "search" in source || "suggestions" in source) {
|
|
2069
2289
|
let search = object4(source.search);
|
|
2070
|
-
keys3(search, ["triggerLabel", "placeholder", "emptyLabel"]), assert(
|
|
2290
|
+
keys3(search, ["triggerLabel", "placeholder", "emptyLabel"]), assert(text4(search.triggerLabel) && text4(search.placeholder) && text4(search.emptyLabel));
|
|
2071
2291
|
let suggestions2 = array2(source.suggestions);
|
|
2072
|
-
assert(suggestions2.length <= 8 && suggestions2.every((value2) =>
|
|
2292
|
+
assert(suggestions2.length <= 8 && suggestions2.every((value2) => text4(value2) && values.includes(value2)) && new Set(suggestions2).size === suggestions2.length);
|
|
2073
2293
|
} else assert(options.length <= 9);
|
|
2074
2294
|
return;
|
|
2075
2295
|
}
|
|
2076
2296
|
assert(source.type === "records"), keys3(source, ["type", "collection", "refPrefix", "where", "display", "suggestions"], ["type", "collection", "display"]);
|
|
2077
2297
|
let collection = object4(source.collection);
|
|
2078
|
-
keys3(collection, ["repository", "name"]), recordReference({ repository: collection.repository, ref: "records/example" }), assert(
|
|
2298
|
+
keys3(collection, ["repository", "name"]), recordReference({ repository: collection.repository, ref: "records/example" }), assert(text4(collection.name) && /^[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*$/.test(collection.name)), "refPrefix" in source && assert(text4(source.refPrefix) && source.refPrefix.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)*\/$/.test(source.refPrefix));
|
|
2079
2299
|
let where = object4(source.where ?? {});
|
|
2080
2300
|
assert(Object.entries(where).every(([name, value2]) => /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name) && !["constructor", "prototype"].includes(name) && (value2 === null || typeof value2 == "string" || typeof value2 == "boolean" || typeof value2 == "number" && Number.isFinite(value2))));
|
|
2081
2301
|
let display = object4(source.display);
|
|
2082
2302
|
keys3(display, ["labelFields"]);
|
|
2083
2303
|
let labels = array2(display.labelFields);
|
|
2084
|
-
assert(labels.length > 0 && labels.length <= 2 && new Set(labels).size === labels.length && labels.every((value2) =>
|
|
2304
|
+
assert(labels.length > 0 && labels.length <= 2 && new Set(labels).size === labels.length && labels.every((value2) => text4(value2) && /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(value2)));
|
|
2085
2305
|
let suggestions = array2(source.suggestions ?? []), refs = suggestions.map((value2) => {
|
|
2086
2306
|
let suggestion = object4(value2);
|
|
2087
2307
|
keys3(suggestion, ["record", "reason"], ["record"]);
|
|
2088
2308
|
let record3 = recordReference(suggestion.record);
|
|
2089
|
-
return assert(record3.repository === collection.repository), "reason" in suggestion && assert(
|
|
2309
|
+
return assert(record3.repository === collection.repository), "reason" in suggestion && assert(text4(suggestion.reason)), record3.ref;
|
|
2090
2310
|
});
|
|
2091
2311
|
assert(suggestions.length <= 8 && new Set(refs).size === refs.length);
|
|
2092
2312
|
}
|
|
2093
2313
|
function inboxFile(value) {
|
|
2094
2314
|
let file2 = object4(value);
|
|
2095
|
-
keys3(file2, ["id", "name", "mediaType", "size", "sha256", "details"]), assert(id2(file2.id) &&
|
|
2315
|
+
keys3(file2, ["id", "name", "mediaType", "size", "sha256", "details"]), assert(id2(file2.id) && text4(file2.name) && !/[\x00-\x1f\x7f/\\]/.test(file2.name) && text4(file2.mediaType) && /^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(file2.mediaType) && integer(file2.size, 0) && file2.size <= 25 * 1024 * 1024 && typeof file2.sha256 == "string" && /^[0-9a-f]{64}$/.test(file2.sha256));
|
|
2096
2316
|
let details = object4(file2.details);
|
|
2097
2317
|
details.kind === "csv" ? (keys3(details, ["kind", "encoding", "delimiter", "headerRow", "dataRows"]), assert(file2.mediaType === "text/csv" && ["utf-8", "windows-1252"].includes(String(details.encoding)) && [",", ";", " "].includes(String(details.delimiter)) && integer(details.headerRow, 0) && integer(details.dataRows, 0))) : details.kind === "pdf" ? (keys3(details, ["kind", "pages"], ["kind"]), assert(file2.mediaType === "application/pdf" && (!("pages" in details) || integer(details.pages)))) : (keys3(details, ["kind"]), assert(details.kind === "other" && !["text/csv", "application/pdf"].includes(file2.mediaType)));
|
|
2098
2318
|
}
|
|
2099
2319
|
function fields4(value) {
|
|
2100
2320
|
let labels = array2(value).map((value2) => {
|
|
2101
2321
|
let field = object4(value2);
|
|
2102
|
-
return keys3(field, ["label", "value"]), assert(
|
|
2322
|
+
return keys3(field, ["label", "value"]), assert(text4(field.label) && text4(field.value)), field.label;
|
|
2103
2323
|
});
|
|
2104
2324
|
assert(new Set(labels).size === labels.length);
|
|
2105
2325
|
}
|
|
2106
2326
|
function block(value) {
|
|
2107
2327
|
let entry = object4(value);
|
|
2108
2328
|
if (entry.kind === "rich-text") {
|
|
2109
|
-
keys3(entry, ["kind", "markdown"]), assert(
|
|
2329
|
+
keys3(entry, ["kind", "markdown"]), assert(text4(entry.markdown));
|
|
2110
2330
|
return;
|
|
2111
2331
|
}
|
|
2112
2332
|
if (entry.kind === "asks") {
|
|
2113
2333
|
keys3(entry, ["kind", "problem", "asks"]);
|
|
2114
2334
|
let asks = array2(entry.asks);
|
|
2115
|
-
assert(
|
|
2335
|
+
assert(text4(entry.problem) && asks.length > 0 && asks.every(id2) && new Set(asks).size === asks.length);
|
|
2116
2336
|
return;
|
|
2117
2337
|
}
|
|
2118
2338
|
if (assert(["record", "records", "files"].includes(String(entry.kind))), keys3(
|
|
2119
2339
|
entry,
|
|
2120
2340
|
["kind", "label", "initiallyExpanded", ...entry.kind === "record" ? ["record", "view"] : entry.kind === "records" ? ["records", "view"] : ["files"]],
|
|
2121
2341
|
["kind", "label", entry.kind === "record" ? "record" : entry.kind === "records" ? "records" : "files"]
|
|
2122
|
-
), assert(
|
|
2342
|
+
), assert(text4(entry.label) && (!("initiallyExpanded" in entry) || typeof entry.initiallyExpanded == "boolean") && (!("view" in entry) || text4(entry.view) && entry.view === entry.view.trim())), entry.kind === "record") {
|
|
2123
2343
|
let record3 = object4(entry.record);
|
|
2124
|
-
keys3(record3, ["ref", "title", "fields"]), assert(
|
|
2344
|
+
keys3(record3, ["ref", "title", "fields"]), assert(text4(record3.ref) && record3.ref === record3.ref.trim() && text4(record3.title)), fields4(record3.fields);
|
|
2125
2345
|
return;
|
|
2126
2346
|
}
|
|
2127
2347
|
if (entry.kind === "records") {
|
|
2128
2348
|
let records = array2(entry.records), refs = records.map((value2) => {
|
|
2129
2349
|
let record3 = object4(value2);
|
|
2130
|
-
return keys3(record3, ["ref", "title", "description", "facts", "view"], ["ref", "title"]), assert(
|
|
2350
|
+
return keys3(record3, ["ref", "title", "description", "facts", "view"], ["ref", "title"]), assert(text4(record3.ref) && record3.ref === record3.ref.trim() && text4(record3.title)), "description" in record3 && assert(text4(record3.description)), "facts" in record3 && fields4(record3.facts), "view" in record3 && assert(text4(record3.view) && record3.view === record3.view.trim()), record3.ref;
|
|
2131
2351
|
});
|
|
2132
2352
|
assert(records.length > 0 && new Set(refs).size === refs.length);
|
|
2133
2353
|
return;
|
|
@@ -2137,7 +2357,7 @@ function block(value) {
|
|
|
2137
2357
|
}
|
|
2138
2358
|
function response(value) {
|
|
2139
2359
|
let answer = object4(value);
|
|
2140
|
-
return assert(Object.keys(answer).every((key) => ["selection", "note"].includes(key))), typeof answer.selection == "string" ? assert(
|
|
2360
|
+
return assert(Object.keys(answer).every((key) => ["selection", "note"].includes(key))), typeof answer.selection == "string" ? assert(text4(answer.selection) && answer.selection === answer.selection.trim()) : recordReference(answer.selection), Object.hasOwn(answer, "note") && assert(text4(answer.note)), answer;
|
|
2141
2361
|
}
|
|
2142
2362
|
function parseInboxRequest(value) {
|
|
2143
2363
|
try {
|
|
@@ -2146,70 +2366,70 @@ function parseInboxRequest(value) {
|
|
|
2146
2366
|
let operation2 = envelope.operation, input = { ...object4(envelope.input) }, required = operations[operation2];
|
|
2147
2367
|
assert(required.every((key) => Object.hasOwn(input, key)) && Object.keys(input).every((key) => required.includes(key) || operation2 === "questions.searchRecords" && key === "selected" || (operation2 === "items.list" || operation2 === "questions.list") && key === "beforeNumber" || operation2 === "questions.list" && key === "routines")), operation2 === "questions.list" && (assert(Object.hasOwn(input, "routines")), assert(array2(input.routines).every(isAppRoutineName)));
|
|
2148
2368
|
for (let key of ["itemId", "personId", "fileId"]) key in input && assert(id2(input[key]));
|
|
2149
|
-
return "revision" in input && assert(integer(input.revision)), "beforeNumber" in input && assert(integer(input.beforeNumber)), "questionId" in input && assert(
|
|
2369
|
+
return "revision" in input && assert(integer(input.revision)), "beforeNumber" in input && assert(integer(input.beforeNumber)), "questionId" in input && assert(text4(input.questionId) && input.questionId === input.questionId.trim()), "title" in input && assert(text4(input.title)), "lifecycle" in input && assert(input.lifecycle === "open" || input.lifecycle === "closed"), "query" in input && assert(text4(input.query, !0) && input.query.length <= 256), "selected" in input && recordReference(input.selected), "response" in input && response(input.response), assert(new TextEncoder().encode(JSON.stringify(envelope)).byteLength <= INBOX_INPUT_BYTES), "routines" in input && (input.routines = [...new Set(input.routines)]), { operation: operation2, input };
|
|
2150
2370
|
} catch {
|
|
2151
2371
|
throw new InboxOperationError(400, "invalid_input");
|
|
2152
2372
|
}
|
|
2153
2373
|
}
|
|
2154
2374
|
function parseInboxCurrent(value) {
|
|
2155
2375
|
let current2 = object4(value), workspace = object4(current2.workspace), viewer = object4(current2.viewer);
|
|
2156
|
-
return assert(id2(workspace.id) &&
|
|
2376
|
+
return assert(id2(workspace.id) && text4(workspace.slug) && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(workspace.slug) && text4(workspace.name) && text4(workspace.locale) && text4(workspace.timezone)), assert(id2(viewer.id) && text4(viewer.name) && text4(viewer.email)), {
|
|
2157
2377
|
workspace: { id: workspace.id, slug: workspace.slug, name: workspace.name, locale: workspace.locale, timezone: workspace.timezone },
|
|
2158
2378
|
viewer: { id: viewer.id, name: viewer.name, email: viewer.email }
|
|
2159
2379
|
};
|
|
2160
2380
|
}
|
|
2161
2381
|
function parseInboxItem(value) {
|
|
2162
2382
|
let item = object4(json(value));
|
|
2163
|
-
return assert(id2(item.id) && id2(item.workspaceId) && integer(item.number) && integer(item.revision) && integer(item.activityVersion, 0) && ["ask", "digest"].includes(String(item.kind)) && ["open", "closed"].includes(String(item.lifecycle)) &&
|
|
2383
|
+
return assert(id2(item.id) && id2(item.workspaceId) && integer(item.number) && integer(item.revision) && integer(item.activityVersion, 0) && ["ask", "digest"].includes(String(item.kind)) && ["open", "closed"].includes(String(item.lifecycle)) && text4(item.title) && text4(item.description, !0) && text4(item.author) && date(item.publishedAt) && optionalDate(item.seenAt) && optionalDate(item.digestReadAt)), item.outcome !== null && assert(text4(object4(item.outcome).outcome)), "canonicalRoutineId" in item && assert(item.canonicalRoutineId === null || isAppRoutineName(item.canonicalRoutineId)), item.kind === "ask" ? askMetadata(item) : assert(!("tags" in item) && !("recordRefs" in item)), array2(item.body).forEach(block), array2(item.views).forEach((value2) => {
|
|
2164
2384
|
let view = object4(value2);
|
|
2165
|
-
assert(
|
|
2385
|
+
assert(text4(view.id) && text4(view.view) && text4(view.implementation)), json(view.input);
|
|
2166
2386
|
}), array2(item.people).forEach((value2) => {
|
|
2167
2387
|
let person = object4(value2);
|
|
2168
|
-
assert(id2(person.id) &&
|
|
2388
|
+
assert(id2(person.id) && text4(person.name));
|
|
2169
2389
|
}), array2(item.questions).forEach((value2) => {
|
|
2170
2390
|
let question2 = object4(value2);
|
|
2171
|
-
if (assert(
|
|
2391
|
+
if (assert(text4(question2.id) && id2(question2.to) && text4(question2.prompt) && (question2.instructions === null || text4(question2.instructions, !0)) && typeof question2.available == "boolean"), responseDefinition(question2.response), assert(array2(question2.allowedResponders).every(id2)), question2.acceptedResponse !== null) {
|
|
2172
2392
|
let accepted = object4(question2.acceptedResponse);
|
|
2173
|
-
assert(id2(accepted.id) && id2(accepted.userId) && date(accepted.acceptedAt)), response(accepted.response), accepted.label === null ? delete accepted.label : "label" in accepted && assert(
|
|
2393
|
+
assert(id2(accepted.id) && id2(accepted.userId) && date(accepted.acceptedAt)), response(accepted.response), accepted.label === null ? delete accepted.label : "label" in accepted && assert(text4(accepted.label)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder));
|
|
2174
2394
|
}
|
|
2175
2395
|
if (question2.execution !== null) {
|
|
2176
2396
|
let execution = object4(question2.execution);
|
|
2177
2397
|
if (assert(id2(execution.id) && ["pending", "running", "completed", "failed"].includes(String(execution.state)) && integer(execution.attempt, 0)), "consequence" in execution) {
|
|
2178
2398
|
let consequence = object4(execution.consequence);
|
|
2179
|
-
assert(["pending", "running", "applied", "no-write", "stopped", "partial", "uncertain"].includes(String(consequence.state)) && (consequence.phase === null || ["loading", "invoking", "committing"].includes(String(consequence.phase))) && date(consequence.updatedAt) && typeof consequence.needsReconciliation == "boolean" && (consequence.reason === null ||
|
|
2399
|
+
assert(["pending", "running", "applied", "no-write", "stopped", "partial", "uncertain"].includes(String(consequence.state)) && (consequence.phase === null || ["loading", "invoking", "committing"].includes(String(consequence.phase))) && date(consequence.updatedAt) && typeof consequence.needsReconciliation == "boolean" && (consequence.reason === null || text4(consequence.reason, !0))), array2(consequence.evidence).forEach((value3) => {
|
|
2180
2400
|
let receipt = object4(value3);
|
|
2181
|
-
assert(
|
|
2401
|
+
assert(text4(receipt.repository) && text4(receipt.commit) && text4(receipt.diff, !0));
|
|
2182
2402
|
});
|
|
2183
2403
|
}
|
|
2184
2404
|
}
|
|
2185
2405
|
}), array2(item.linkedAsks).forEach((value2) => {
|
|
2186
2406
|
let linked = object4(value2);
|
|
2187
2407
|
if (assert(id2(linked.id)), linked.state === "unavailable") assert(typeof linked.done == "boolean");
|
|
2188
|
-
else if (assert(["yours", "done", "open", "theirs"].includes(String(linked.state)) &&
|
|
2408
|
+
else if (assert(["yours", "done", "open", "theirs"].includes(String(linked.state)) && text4(linked.title)), linked.state === "theirs") {
|
|
2189
2409
|
let assignee = object4(linked.assignee);
|
|
2190
|
-
assert(id2(assignee.id) &&
|
|
2410
|
+
assert(id2(assignee.id) && text4(assignee.name));
|
|
2191
2411
|
}
|
|
2192
2412
|
}), array2(item.activity).forEach((value2) => {
|
|
2193
2413
|
let event = object4(value2);
|
|
2194
|
-
assert(integer(event.id) &&
|
|
2414
|
+
assert(integer(event.id) && text4(event.type) && (event.actorId === null || id2(event.actorId)) && (event.questionId === null || text4(event.questionId)) && integer(event.revision) && date(event.createdAt)), object4(event.data);
|
|
2195
2415
|
}), array2(item.work).forEach((value2) => {
|
|
2196
2416
|
let work = object4(value2);
|
|
2197
|
-
assert(id2(work.id) &&
|
|
2417
|
+
assert(id2(work.id) && text4(work.questionId) && text4(work.reason) && optionalDate(work.settledAt));
|
|
2198
2418
|
}), item;
|
|
2199
2419
|
}
|
|
2200
2420
|
function parseAnswerableQuestion(value) {
|
|
2201
2421
|
let entry = object4(json(value));
|
|
2202
2422
|
keys3(
|
|
2203
2423
|
entry,
|
|
2204
|
-
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
|
|
2205
|
-
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
|
|
2206
|
-
), assert(id2(entry.itemId) && integer(entry.revision) &&
|
|
2424
|
+
["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
|
|
2425
|
+
["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
|
|
2426
|
+
), assert(id2(entry.itemId) && integer(entry.number) && integer(entry.revision) && text4(entry.title) && text4(entry.inboxUrl));
|
|
2207
2427
|
let link = new URL(entry.inboxUrl), slug = link.hostname.slice(0, -13);
|
|
2208
|
-
return assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && entry.inboxUrl === `https://${slug}.oddington.ai/inbox/${entry.itemId}`), assert(isAppRoutineName(entry.routine) &&
|
|
2428
|
+
return assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && entry.inboxUrl === `https://${slug}.oddington.ai/inbox/${entry.itemId}`), assert(isAppRoutineName(entry.routine) && text4(entry.questionId) && entry.questionId === entry.questionId.trim() && text4(entry.prompt) && (!("instructions" in entry) || text4(entry.instructions, !0)) && typeof entry.answerable == "boolean"), responseDefinition(entry.response), askMetadata(entry), entry;
|
|
2209
2429
|
}
|
|
2210
2430
|
function askMetadata(entry) {
|
|
2211
2431
|
let tags = array2(entry.tags === void 0 ? [] : entry.tags);
|
|
2212
|
-
assert(tags.length <= 32 && tags.every((tag) =>
|
|
2432
|
+
assert(tags.length <= 32 && tags.every((tag) => text4(tag) && new TextEncoder().encode(tag).byteLength <= 64)), assert(new Set(tags).size === tags.length);
|
|
2213
2433
|
let refs = array2(entry.recordRefs === void 0 ? [] : entry.recordRefs);
|
|
2214
2434
|
refs.forEach((value) => {
|
|
2215
2435
|
let ref = object4(value);
|
|
@@ -2221,7 +2441,7 @@ function askMetadata(entry) {
|
|
|
2221
2441
|
}
|
|
2222
2442
|
function parseInboxAcceptance(value) {
|
|
2223
2443
|
let accepted = object4(value);
|
|
2224
|
-
return assert(id2(accepted.responseId) && date(accepted.acceptedAt)), "executionId" in accepted && assert(id2(accepted.executionId)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder)), "label" in accepted && assert(
|
|
2444
|
+
return assert(id2(accepted.responseId) && date(accepted.acceptedAt)), "executionId" in accepted && assert(id2(accepted.executionId)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder)), "label" in accepted && assert(text4(accepted.label)), accepted;
|
|
2225
2445
|
}
|
|
2226
2446
|
function parseInboxResult(operation2, value) {
|
|
2227
2447
|
if (operation2 === "current") return parseInboxCurrent(value);
|
|
@@ -2252,7 +2472,7 @@ function parseInboxResult(operation2, value) {
|
|
|
2252
2472
|
let candidates = array2(value);
|
|
2253
2473
|
return candidates.forEach((value2) => {
|
|
2254
2474
|
let person = object4(value2);
|
|
2255
|
-
assert(id2(person.id) &&
|
|
2475
|
+
assert(id2(person.id) && text4(person.name) && text4(person.email));
|
|
2256
2476
|
}), assert(new Set(candidates.map((value2) => object4(value2).id)).size === candidates.length), candidates;
|
|
2257
2477
|
}
|
|
2258
2478
|
if (operation2 === "items.addRecipient") {
|
|
@@ -2262,10 +2482,10 @@ function parseInboxResult(operation2, value) {
|
|
|
2262
2482
|
if (operation2 === "questions.answer") return parseInboxAcceptance(value);
|
|
2263
2483
|
if (operation2 === "questions.searchRecords") {
|
|
2264
2484
|
let result2 = object4(value);
|
|
2265
|
-
assert(
|
|
2485
|
+
assert(text4(result2.recordType) && integer(result2.eligibleCount, 0) && integer(result2.matchCount, 0) && Number(result2.matchCount) <= Number(result2.eligibleCount));
|
|
2266
2486
|
let labeled = (value2) => {
|
|
2267
2487
|
let record3 = object4(value2);
|
|
2268
|
-
recordReference({ repository: record3.repository, ref: record3.ref }), assert(
|
|
2488
|
+
recordReference({ repository: record3.repository, ref: record3.ref }), assert(text4(record3.label)), "reason" in record3 && assert(text4(record3.reason));
|
|
2269
2489
|
};
|
|
2270
2490
|
return array2(result2.matches).forEach(labeled), array2(result2.suggestions).forEach(labeled), "selected" in result2 && labeled(result2.selected), result2;
|
|
2271
2491
|
}
|
|
@@ -2379,7 +2599,7 @@ async function appResponse(response2, maximum, signal) {
|
|
|
2379
2599
|
});
|
|
2380
2600
|
};
|
|
2381
2601
|
signal.addEventListener("abort", abort, { once: !0 });
|
|
2382
|
-
let bytes = 0,
|
|
2602
|
+
let bytes = 0, text5 = "", decoder = new TextDecoder("utf-8", { fatal: !0 });
|
|
2383
2603
|
try {
|
|
2384
2604
|
for (; ; ) {
|
|
2385
2605
|
let chunk;
|
|
@@ -2390,13 +2610,13 @@ async function appResponse(response2, maximum, signal) {
|
|
|
2390
2610
|
}
|
|
2391
2611
|
if (signal.aborted) throw new Error();
|
|
2392
2612
|
if (chunk.done) {
|
|
2393
|
-
let value = JSON.parse(
|
|
2613
|
+
let value = JSON.parse(text5 + decoder.decode());
|
|
2394
2614
|
if (await responseChecks.get(response2)?.(value), signal.aborted) throw new Error();
|
|
2395
2615
|
return value;
|
|
2396
2616
|
}
|
|
2397
2617
|
if (bytes += chunk.value.byteLength, bytes > maximum)
|
|
2398
2618
|
throw abort(), new Error();
|
|
2399
|
-
|
|
2619
|
+
text5 += decoder.decode(chunk.value, { stream: !0 });
|
|
2400
2620
|
}
|
|
2401
2621
|
} finally {
|
|
2402
2622
|
signal.removeEventListener("abort", abort), reader.releaseLock();
|
|
@@ -2622,16 +2842,16 @@ function appContext(origin, active2) {
|
|
|
2622
2842
|
return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, {}, !1, !0);
|
|
2623
2843
|
}
|
|
2624
2844
|
async function requestFiles(suffix, init2, parent) {
|
|
2625
|
-
let
|
|
2845
|
+
let unavailable4 = () => new FileOperationError("unsupported_context", 400);
|
|
2626
2846
|
if (!current2() || !/^(?:|\/[0-9a-f-]{36}(?:\/(?:content|upload|enrichments(?:\/[^/?#]+\/content)?))?)$/i.test(suffix))
|
|
2627
|
-
throw
|
|
2628
|
-
let admitted = credential, signal = parent ? AbortSignal.any([access.signal, parent]) : access.signal, failure = () => current2() && !signal.aborted ? new FileOperationError("unavailable", 503, !0) :
|
|
2847
|
+
throw unavailable4();
|
|
2848
|
+
let admitted = credential, signal = parent ? AbortSignal.any([access.signal, parent]) : access.signal, failure = () => current2() && !signal.aborted ? new FileOperationError("unavailable", 503, !0) : unavailable4();
|
|
2629
2849
|
try {
|
|
2630
2850
|
return await hostedContent("", init2, signal, (_url, request2) => untilAborted(
|
|
2631
2851
|
send3(`files${suffix}`, admitted, signal, request2).then((value) => {
|
|
2632
2852
|
if (signal.aborted)
|
|
2633
2853
|
throw value.body?.cancel().catch(() => {
|
|
2634
|
-
}),
|
|
2854
|
+
}), unavailable4();
|
|
2635
2855
|
return value;
|
|
2636
2856
|
}),
|
|
2637
2857
|
signal
|
|
@@ -2733,9 +2953,9 @@ function validPair(value) {
|
|
|
2733
2953
|
return validProof(pair.credential) && validProof(pair.renewalCredential) && pair.credential !== pair.renewalCredential && validBinding(pair.context);
|
|
2734
2954
|
}
|
|
2735
2955
|
|
|
2736
|
-
var
|
|
2956
|
+
var unavailable3 = () => new InboxOperationError(503, "unavailable"), stale = () => new InboxOperationError(401, "authority_unavailable");
|
|
2737
2957
|
function hostFailure(error, context2) {
|
|
2738
|
-
return !context2.isCurrent() || context2.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") :
|
|
2958
|
+
return !context2.isCurrent() || context2.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") : unavailable3();
|
|
2739
2959
|
}
|
|
2740
2960
|
async function send2(operation2, input) {
|
|
2741
2961
|
let envelope = parseInboxRequest({ operation: operation2, input }), context2;
|
|
@@ -2755,12 +2975,12 @@ async function send2(operation2, input) {
|
|
|
2755
2975
|
[400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
|
|
2756
2976
|
response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
|
|
2757
2977
|
);
|
|
2758
|
-
if (response2.status !== 200) throw
|
|
2978
|
+
if (response2.status !== 200) throw unavailable3();
|
|
2759
2979
|
let parsed = parseInboxResult(operation2, value);
|
|
2760
|
-
if (check2(), operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw
|
|
2980
|
+
if (check2(), operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw unavailable3();
|
|
2761
2981
|
return parsed;
|
|
2762
2982
|
} catch (error) {
|
|
2763
|
-
throw check2(), error instanceof InboxOperationError ? error :
|
|
2983
|
+
throw check2(), error instanceof InboxOperationError ? error : unavailable3();
|
|
2764
2984
|
}
|
|
2765
2985
|
}
|
|
2766
2986
|
if (context2.endpoint !== `https://${context2.workspace}.oddington.ai` || ["auth", "www", "api", "os"].includes(context2.workspace)) throw stale();
|
|
@@ -2771,7 +2991,7 @@ async function send2(operation2, input) {
|
|
|
2771
2991
|
} catch (error) {
|
|
2772
2992
|
throw hostFailure(error, context2);
|
|
2773
2993
|
}
|
|
2774
|
-
if (!host) throw
|
|
2994
|
+
if (!host) throw unavailable3();
|
|
2775
2995
|
}
|
|
2776
2996
|
let check = () => {
|
|
2777
2997
|
if (!context2.isCurrent() || host && !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
|
|
@@ -2801,9 +3021,9 @@ async function send2(operation2, input) {
|
|
|
2801
3021
|
);
|
|
2802
3022
|
if (response2.status !== 200)
|
|
2803
3023
|
throw response2.body?.cancel().catch(() => {
|
|
2804
|
-
}),
|
|
3024
|
+
}), unavailable3();
|
|
2805
3025
|
if (operation2 === "files.read") {
|
|
2806
|
-
if (!response2.body) throw
|
|
3026
|
+
if (!response2.body) throw unavailable3();
|
|
2807
3027
|
let source = response2.body, reader, size = 0, cancel = async (reason) => {
|
|
2808
3028
|
try {
|
|
2809
3029
|
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
@@ -2819,7 +3039,7 @@ async function send2(operation2, input) {
|
|
|
2819
3039
|
reader.releaseLock(), controller.close();
|
|
2820
3040
|
return;
|
|
2821
3041
|
}
|
|
2822
|
-
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw
|
|
3042
|
+
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw unavailable3();
|
|
2823
3043
|
controller.enqueue(next.value);
|
|
2824
3044
|
} catch (error) {
|
|
2825
3045
|
controller.error(error), await cancel(error).catch(() => {
|
|
@@ -2831,16 +3051,16 @@ async function send2(operation2, input) {
|
|
|
2831
3051
|
return new Response(body, { status: response2.status, headers: response2.headers });
|
|
2832
3052
|
}
|
|
2833
3053
|
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
2834
|
-
if (check(), !bytes) throw
|
|
3054
|
+
if (check(), !bytes) throw unavailable3();
|
|
2835
3055
|
let value = JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)), parsed = parseInboxResult(operation2, value);
|
|
2836
|
-
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw
|
|
3056
|
+
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw unavailable3();
|
|
2837
3057
|
if ("itemId" in envelope.input) {
|
|
2838
3058
|
let item = operation2 === "items.read" ? parsed : operation2 === "items.rename" || operation2 === "items.setLifecycle" || operation2 === "items.addRecipient" ? parsed.item : void 0;
|
|
2839
|
-
if (item && (item.id !== envelope.input.itemId || "revision" in envelope.input && item.revision !== envelope.input.revision) || operation2 === "items.addRecipient" && parsed.addedPersonId !== envelope.input.personId || operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw
|
|
3059
|
+
if (item && (item.id !== envelope.input.itemId || "revision" in envelope.input && item.revision !== envelope.input.revision) || operation2 === "items.addRecipient" && parsed.addedPersonId !== envelope.input.personId || operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw unavailable3();
|
|
2840
3060
|
}
|
|
2841
3061
|
return parsed;
|
|
2842
3062
|
} catch (error) {
|
|
2843
|
-
throw check(), error instanceof InboxOperationError ? error :
|
|
3063
|
+
throw check(), error instanceof InboxOperationError ? error : unavailable3();
|
|
2844
3064
|
}
|
|
2845
3065
|
}
|
|
2846
3066
|
var inbox = {
|
|
@@ -2860,14 +3080,14 @@ var inbox = {
|
|
|
2860
3080
|
throw hostFailure(error, initial);
|
|
2861
3081
|
}
|
|
2862
3082
|
if (initial.kind === "local") throw new InboxOperationError(403, "access_denied");
|
|
2863
|
-
if (!host) throw
|
|
3083
|
+
if (!host) throw unavailable3();
|
|
2864
3084
|
let check = () => {
|
|
2865
3085
|
if (!initial.isCurrent() || !host.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
|
|
2866
3086
|
};
|
|
2867
3087
|
do {
|
|
2868
3088
|
check();
|
|
2869
3089
|
let page = await send2("items.list", beforeNumber === void 0 ? {} : { beforeNumber });
|
|
2870
|
-
if (check(), beforeNumber !== void 0 && (page.items.some((item) => item.number >= beforeNumber) || page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber)) throw
|
|
3090
|
+
if (check(), beforeNumber !== void 0 && (page.items.some((item) => item.number >= beforeNumber) || page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber)) throw unavailable3();
|
|
2871
3091
|
if (items.push(...page.items), page.nextBeforeNumber === null) return items;
|
|
2872
3092
|
beforeNumber = page.nextBeforeNumber;
|
|
2873
3093
|
} while (!0);
|
|
@@ -2901,7 +3121,7 @@ var inbox = {
|
|
|
2901
3121
|
routines,
|
|
2902
3122
|
...beforeNumber === void 0 ? {} : { beforeNumber }
|
|
2903
3123
|
});
|
|
2904
|
-
if (check(), page.questions.some((question2) => question2.inboxUrl !== `https://${initial.workspace}.oddington.ai/inbox/${question2.itemId}` || !routines.includes(question2.routine)) || beforeNumber !== void 0 && page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber) throw
|
|
3124
|
+
if (check(), page.questions.some((question2) => question2.inboxUrl !== `https://${initial.workspace}.oddington.ai/inbox/${question2.itemId}` || !routines.includes(question2.routine)) || beforeNumber !== void 0 && page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber) throw unavailable3();
|
|
2905
3125
|
if (questions.push(...page.questions), page.nextBeforeNumber === null) return questions;
|
|
2906
3126
|
beforeNumber = page.nextBeforeNumber;
|
|
2907
3127
|
} while (!0);
|
|
@@ -3483,7 +3703,7 @@ function handle(key, id3, context2) {
|
|
|
3483
3703
|
async function describeAppRoutine(key) {
|
|
3484
3704
|
let descriptor = appDescriptors().find((item) => item.id === key);
|
|
3485
3705
|
if (!descriptor) return fail3("authority_unavailable");
|
|
3486
|
-
let
|
|
3706
|
+
let unavailable4 = () => ({
|
|
3487
3707
|
...structuredClone(descriptor),
|
|
3488
3708
|
connections: descriptor.connections.map((connection) => ({ ...connection, available: !1 })),
|
|
3489
3709
|
readiness: { state: "unavailable", reason: "capability_unavailable", message: "Routine capability unavailable." }
|
|
@@ -3492,11 +3712,11 @@ async function describeAppRoutine(key) {
|
|
|
3492
3712
|
let value = await request(key, "describe", void 0, 1048576);
|
|
3493
3713
|
return (!only(value, "id,title,input,connections,steps,readiness") || !value.readiness || !Array.isArray(value.connections) || structure({ ...value, readiness: void 0, connections: value.connections.map(({ available, ...item }) => item) }) !== structure(descriptor) || value.connections.some((item) => typeof item.available != "boolean") || !(value.readiness.state === "ready" && only(value.readiness, "state,placement") && value.readiness.placement === "local" || value.readiness.state === "unavailable" && only(value.readiness, "state,reason,message") && ["not_deployed", "definition_invalid", "capability_unavailable"].includes(value.readiness.reason) && message(value.readiness.message))) && fail3("execution_unavailable"), value;
|
|
3494
3714
|
} catch {
|
|
3495
|
-
return
|
|
3715
|
+
return unavailable4();
|
|
3496
3716
|
}
|
|
3497
3717
|
}
|
|
3498
3718
|
function appRoutineBinding(key) {
|
|
3499
|
-
return Object.freeze({
|
|
3719
|
+
return (typeof key != "string" || !identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable"), Object.freeze({
|
|
3500
3720
|
describe: () => describeAppRoutine(key),
|
|
3501
3721
|
async run(...args) {
|
|
3502
3722
|
args.length > 1 && fail3("invalid_input");
|
|
@@ -3530,6 +3750,7 @@ function appRoutineBinding(key) {
|
|
|
3530
3750
|
|
|
3531
3751
|
var app = Object.freeze({
|
|
3532
3752
|
listRoutines: () => Promise.all(appDescriptors().map(({ id: id3 }) => describeAppRoutine(id3))),
|
|
3753
|
+
routine: appRoutineBinding,
|
|
3533
3754
|
routines: new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
3534
3755
|
get(_target, key) {
|
|
3535
3756
|
if (!(typeof key != "string" || !appDescriptors().some((item) => item.id === key)))
|
|
@@ -3569,10 +3790,10 @@ function routineDataEnvelope(command) {
|
|
|
3569
3790
|
}
|
|
3570
3791
|
|
|
3571
3792
|
function routinePublicationClient2(options = {}) {
|
|
3572
|
-
let environment = {}, installed2 = routineTransport(), local3 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.
|
|
3793
|
+
let environment = {}, installed2 = routineTransport(), local3 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.OS_ROUTINE_WORKSPACE, capability = options.capability ?? environment.OS_ROUTINE_RUN;
|
|
3573
3794
|
if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
|
|
3574
3795
|
throw new Error("A workspace and valid optional routine capability are required");
|
|
3575
|
-
let workingRoot = options.workingRoot ?? environment.
|
|
3796
|
+
let workingRoot = options.workingRoot ?? environment.OS_INBOX_WORKING_ROOT ?? void 0, headers = capability ? { "x-os-run": capability } : {}, request2 = options.request ?? (capability ? async (path, init2) => {
|
|
3576
3797
|
if (path === "/api/data") return fetch(`https://${workspace}.oddington.ai/api/data`, { ...init2, redirect: "error" });
|
|
3577
3798
|
let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
|
|
3578
3799
|
if (workspace.length > 63 || ["auth", "www", "api", "os"].includes(workspace) || target.origin !== origin || target.search || target.hash || target.username || target.password || !/^\/api\/inbox\/(check|publish|resolve|files)$/.test(path) || init2?.method !== "POST")
|
|
@@ -3588,7 +3809,7 @@ function routinePublicationClient2(options = {}) {
|
|
|
3588
3809
|
headers: {
|
|
3589
3810
|
"content-type": "application/json",
|
|
3590
3811
|
...headers,
|
|
3591
|
-
...writing || reading ? { "x-
|
|
3812
|
+
...writing || reading ? { "x-os-workspace": workspace, "x-os-captured-records": "1" } : {}
|
|
3592
3813
|
},
|
|
3593
3814
|
body: JSON.stringify(writing ? routineDataEnvelope(validateRoutineRecordWrite(body)) : reading ? { operation: "records.select", request: validateRecordRead(body) } : body)
|
|
3594
3815
|
}), result2 = await response2.json();
|