@oddington/sdk 0.1.25 → 0.1.26
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
CHANGED
|
@@ -40,7 +40,7 @@ import { defineRoutine, file, schema } from '@oddington/sdk';
|
|
|
40
40
|
|
|
41
41
|
export default defineRoutine({
|
|
42
42
|
id: 'invoice-import',
|
|
43
|
-
input: schema.object({ document: file() }),
|
|
43
|
+
input: schema.object({ document: file({ storage: 'local', path: 'Statements' }) }),
|
|
44
44
|
access: { files: 'read' },
|
|
45
45
|
steps: {
|
|
46
46
|
read: {
|
|
@@ -67,8 +67,10 @@ skipped. Omitted input normalizes to `{}`. A top-level schema can supply a valid
|
|
|
67
67
|
immutable default with `.default(value)`, such as
|
|
68
68
|
`schema.object({ files: schema.array(file(), { maxItems: 32 }) }).default({ files: [] })`.
|
|
69
69
|
Nested defaults are unsupported and rejected. Omitted steps permit no step call;
|
|
70
|
-
omitted result permits no returned value. `file()` declares a complete OS File descriptor
|
|
71
|
-
|
|
70
|
+
omitted result permits no returned value. `file()` declares a complete OS File descriptor.
|
|
71
|
+
Its optional `storage` selects local or remote placement and its optional `path`
|
|
72
|
+
selects a managed OS parent such as `Statements`; it is never a machine or provider
|
|
73
|
+
path. The trusted launcher separately verifies current File-use authority. The supplied
|
|
72
74
|
runtime contains `run.id`, `data`, `files`, `connections`, `inbox`, and `step`.
|
|
73
75
|
Accepted input and saved values are immutable snapshots. Access declarations set
|
|
74
76
|
maximum named capabilities and grant no authority; the trusted host checks current
|
package/dist/browser.js
CHANGED
|
@@ -459,6 +459,9 @@ function safeFileName(value) {
|
|
|
459
459
|
function safeFilePath(value) {
|
|
460
460
|
return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
|
|
461
461
|
}
|
|
462
|
+
function safeManagedFilePath(value) {
|
|
463
|
+
return safeFilePath(value) && value.split("/")[0].toLowerCase() !== ".os";
|
|
464
|
+
}
|
|
462
465
|
var ORIGINAL_MEDIA_TYPES = ["application/pdf", "text/plain", "text/markdown", "application/json", "image/png", "image/jpeg"];
|
|
463
466
|
function declaredOriginalMediaType(value) {
|
|
464
467
|
let normalized = value.split(";", 1)[0].trim().toLowerCase();
|
|
@@ -472,7 +475,7 @@ function parseFileCreateMetadata(value, maxBytes) {
|
|
|
472
475
|
let input = value;
|
|
473
476
|
if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return invalid8();
|
|
474
477
|
let path = input.path === void 0 ? "Files" : input.path;
|
|
475
|
-
if (!safeFileName(input.name) || !
|
|
478
|
+
if (!safeFileName(input.name) || !safeManagedFilePath(path) || 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();
|
|
476
479
|
if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
477
480
|
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();
|
|
478
481
|
let csv;
|
|
@@ -545,7 +548,11 @@ function parseAppRoutineContract(value) {
|
|
|
545
548
|
case "boolean":
|
|
546
549
|
return fields2(value2, ["type"]) ? { type: value2.type } : invalidContract();
|
|
547
550
|
case "file":
|
|
548
|
-
return !fields2(value2, ["type"], ["storage"]) || owns(value2, "storage") && value2.storage !== "local" && value2.storage !== "remote"
|
|
551
|
+
return !fields2(value2, ["type"], ["storage", "path"]) || owns(value2, "storage") && value2.storage !== "local" && value2.storage !== "remote" || owns(value2, "path") && !safeManagedFilePath(value2.path) ? invalidContract() : {
|
|
552
|
+
type: "file",
|
|
553
|
+
...owns(value2, "storage") ? { storage: value2.storage } : {},
|
|
554
|
+
...owns(value2, "path") ? { path: value2.path } : {}
|
|
555
|
+
};
|
|
549
556
|
case "string":
|
|
550
557
|
return !fields2(value2, ["type"], ["maxLength"]) || owns(value2, "maxLength") && (!Number.isSafeInteger(value2.maxLength) || value2.maxLength < 0 || value2.maxLength > 4096) ? invalidContract() : { type: "string", ...owns(value2, "maxLength") ? { maxLength: value2.maxLength } : {} };
|
|
551
558
|
case "integer":
|
|
@@ -592,7 +599,9 @@ function validateRoutineSchemaValue(schema2, value) {
|
|
|
592
599
|
return typeof value != "number" || !(schema2.type === "integer" ? Number.isSafeInteger(value) : Number.isFinite(value)) || schema2.minimum !== void 0 && value < schema2.minimum || schema2.maximum !== void 0 && value > schema2.maximum ? invalidValue() : void 0;
|
|
593
600
|
case "file":
|
|
594
601
|
try {
|
|
595
|
-
jsonData(value)
|
|
602
|
+
jsonData(value);
|
|
603
|
+
let file2 = parseFileDescriptor(value);
|
|
604
|
+
if (schema2.path !== void 0 && file2.path !== schema2.path) return invalidValue();
|
|
596
605
|
} catch {
|
|
597
606
|
return invalidValue();
|
|
598
607
|
}
|
|
@@ -791,7 +800,7 @@ var schema = {
|
|
|
791
800
|
boolean() {
|
|
792
801
|
return declaration({ type: "boolean" });
|
|
793
802
|
}
|
|
794
|
-
}, file = (options = {}) => (assertRoutineFields(options, ["storage"]), declaration({ type: "file", ...options })), definitions = /* @__PURE__ */ new WeakMap(), defineRoutine = (definition) => {
|
|
803
|
+
}, file = (options = {}) => (assertRoutineFields(options, ["storage", "path"]), declaration({ type: "file", ...options })), definitions = /* @__PURE__ */ new WeakMap(), defineRoutine = (definition) => {
|
|
795
804
|
if (assertRoutineFields(definition, ["id", "title", "input", "steps", "result", "access", "responses", "run"]), !isAppRoutineName(definition.id) || definition.title !== void 0 && !routineTitle(definition.title) || typeof definition.run != "function") return invalidContract3();
|
|
796
805
|
let input = definition.input === void 0 ? { schema: empty, default: {} } : schemaMetadata(definition.input), result2 = definition.result === void 0 ? void 0 : schemaMetadata(definition.result).schema, access = parseRoutineAccess(definition.access);
|
|
797
806
|
assertRoutineFields(definition.steps ?? {});
|
|
@@ -2957,10 +2966,10 @@ var unavailable3 = () => new InboxOperationError(503, "unavailable"), stale = ()
|
|
|
2957
2966
|
function hostFailure(error, context2) {
|
|
2958
2967
|
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();
|
|
2959
2968
|
}
|
|
2960
|
-
async function send2(operation2, input) {
|
|
2969
|
+
async function send2(operation2, input, admitted) {
|
|
2961
2970
|
let envelope = parseInboxRequest({ operation: operation2, input }), context2;
|
|
2962
2971
|
try {
|
|
2963
|
-
context2 = await resolveAppContext();
|
|
2972
|
+
context2 = admitted ?? await resolveAppContext();
|
|
2964
2973
|
} catch {
|
|
2965
2974
|
throw stale();
|
|
2966
2975
|
}
|
|
@@ -3120,7 +3129,7 @@ var inbox = {
|
|
|
3120
3129
|
let page = await send2("questions.list", {
|
|
3121
3130
|
routines,
|
|
3122
3131
|
...beforeNumber === void 0 ? {} : { beforeNumber }
|
|
3123
|
-
});
|
|
3132
|
+
}, initial);
|
|
3124
3133
|
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();
|
|
3125
3134
|
if (questions.push(...page.questions), page.nextBeforeNumber === null) return questions;
|
|
3126
3135
|
beforeNumber = page.nextBeforeNumber;
|