@oddington/sdk 0.1.24 → 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/dist/browser.js +156 -40
- package/dist/index.js +2 -2
- package/dist/types/packages/sdk/src/public.d.ts +2 -2
- package/dist/types/packages/sdk/src/routine-definition-types.d.ts +17 -0
- package/dist/types/shared/connection-runtime.d.ts +13 -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 +1 -1
package/dist/browser.js
CHANGED
|
@@ -413,7 +413,14 @@ function parseFileDescriptor(value) {
|
|
|
413
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
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") {
|
|
@@ -452,6 +459,11 @@ 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
468
|
let invalid8 = () => {
|
|
457
469
|
throw new FileOperationError("invalid_input", 400);
|
|
@@ -460,7 +472,7 @@ function parseFileCreateMetadata(value, maxBytes) {
|
|
|
460
472
|
let input = value;
|
|
461
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
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;
|
|
@@ -476,7 +488,7 @@ function parseFileCreateMetadata(value, maxBytes) {
|
|
|
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
|
|
|
@@ -1133,19 +1220,19 @@ var invalid6 = () => {
|
|
|
1133
1220
|
}, unavailable = () => {
|
|
1134
1221
|
throw new DataOperationError("unavailable");
|
|
1135
1222
|
}, text2 = (value) => typeof value == "string" && value.length > 0;
|
|
1136
|
-
function
|
|
1223
|
+
function capture3(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
|
|
1137
1224
|
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return value;
|
|
1138
1225
|
if (!value || typeof value != "object" || ancestors.has(value) || depth > 32) return invalid6();
|
|
1139
1226
|
ancestors.add(value);
|
|
1140
1227
|
try {
|
|
1141
|
-
return Array.isArray(value) ? historyArray(value).map((item) =>
|
|
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)]));
|
|
1142
1229
|
} finally {
|
|
1143
1230
|
ancestors.delete(value);
|
|
1144
1231
|
}
|
|
1145
1232
|
}
|
|
1146
1233
|
function recordPagination(select) {
|
|
1147
1234
|
function pages(query) {
|
|
1148
|
-
let captured =
|
|
1235
|
+
let captured = capture3(query), names = Object.keys(historyProperties(captured));
|
|
1149
1236
|
for (let name of names) {
|
|
1150
1237
|
let selection2 = historyProperties(captured[name]);
|
|
1151
1238
|
if (Object.hasOwn(selection2, "$")) {
|
|
@@ -1167,7 +1254,7 @@ function recordPagination(select) {
|
|
|
1167
1254
|
return [name, next === void 0 ? selection2 : { ...selection2, $: { ...selection2.$, after: next } }];
|
|
1168
1255
|
})), response2 = await select(request2), page;
|
|
1169
1256
|
try {
|
|
1170
|
-
page =
|
|
1257
|
+
page = capture3(response2);
|
|
1171
1258
|
let keys4 = Object.keys(historyProperties(page));
|
|
1172
1259
|
(keys4.length !== active2.length + 1 || keys4.some((key) => key !== "$meta" && !active2.includes(key))) && unavailable();
|
|
1173
1260
|
let meta = page.$meta;
|
|
@@ -1645,13 +1732,13 @@ var files = {
|
|
|
1645
1732
|
if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid7();
|
|
1646
1733
|
let name = input.name;
|
|
1647
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));
|
|
1648
|
-
let metadata = parseFileCreateMetadata({
|
|
1735
|
+
let inputMediaType = blob ? declaredOriginalMediaType(input.file.type) : void 0, metadata = parseFileCreateMetadata({
|
|
1649
1736
|
name,
|
|
1650
1737
|
size: intrinsic ?? input.size,
|
|
1651
1738
|
path: input.path,
|
|
1652
1739
|
storage: input.storage,
|
|
1653
1740
|
csv: input.csv,
|
|
1654
|
-
...
|
|
1741
|
+
...inputMediaType === void 0 ? {} : { inputMediaType },
|
|
1655
1742
|
requestKey: options?.requestKey === void 0 ? routineTransport()?.key("files") ?? crypto.randomUUID() : options.requestKey
|
|
1656
1743
|
}, FILE_ORIGINAL_MAX_BYTES);
|
|
1657
1744
|
if (!context2.local && !context2.localFiles && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
@@ -1733,29 +1820,58 @@ var files = {
|
|
|
1733
1820
|
read
|
|
1734
1821
|
};
|
|
1735
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
|
+
}
|
|
1736
1826
|
function validGoogleScopes(value) {
|
|
1737
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;
|
|
1738
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
|
+
}
|
|
1739
1833
|
|
|
1740
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
|
+
}
|
|
1741
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);
|
|
1742
1841
|
function runtimeConnection(lease) {
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
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
|
+
}
|
|
1759
1875
|
}
|
|
1760
1876
|
function parseConnectionLease(raw, now = Date.now()) {
|
|
1761
1877
|
let v = raw;
|
|
@@ -1766,7 +1882,7 @@ function parseConnectionLease(raw, now = Date.now()) {
|
|
|
1766
1882
|
throw new Error("Invalid connection credential");
|
|
1767
1883
|
return v;
|
|
1768
1884
|
}
|
|
1769
|
-
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)
|
|
1770
1886
|
return v;
|
|
1771
1887
|
throw new Error("Invalid connection credential");
|
|
1772
1888
|
}
|
|
@@ -2305,9 +2421,9 @@ function parseAnswerableQuestion(value) {
|
|
|
2305
2421
|
let entry = object4(json(value));
|
|
2306
2422
|
keys3(
|
|
2307
2423
|
entry,
|
|
2308
|
-
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
|
|
2309
|
-
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
|
|
2310
|
-
), assert(id2(entry.itemId) && integer(entry.revision) && text4(entry.title) && text4(entry.inboxUrl));
|
|
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));
|
|
2311
2427
|
let link = new URL(entry.inboxUrl), slug = link.hostname.slice(0, -13);
|
|
2312
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;
|
|
2313
2429
|
}
|