@oddington/sdk 0.1.20 → 0.1.22
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 +89 -65
- package/dist/browser.js +604 -498
- package/dist/index.js +8 -8
- package/dist/types/packages/sdk/src/public.d.ts +87 -35
- package/dist/types/packages/sdk/src/routine-definition-types.d.ts +48 -20
- package/dist/types/shared/app-descriptor.d.ts +21 -0
- package/dist/types/shared/inbox-contract.d.ts +5 -1
- package/dist/types/shared/inbox-member-contract.d.ts +2 -2
- package/dist/types/shared/inbox-member-types.d.ts +15 -17
- package/dist/types/shared/routine-definition-contract.d.ts +33 -0
- package/dist/types/shared/routine-deployment-contract.d.ts +47 -0
- package/dist/types/shared/routine-deployment-path.d.ts +6 -0
- package/dist/types/shared/routine-source-provenance.d.ts +7 -0
- package/package.json +1 -1
package/dist/browser.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
var InboxContractError = class extends Error {
|
|
2
|
-
constructor(
|
|
3
|
-
super(
|
|
2
|
+
constructor(message2) {
|
|
3
|
+
super(message2), this.name = "InboxContractError";
|
|
4
4
|
}
|
|
5
5
|
};
|
|
6
|
-
function fail(
|
|
7
|
-
throw new InboxContractError(
|
|
6
|
+
function fail(message2) {
|
|
7
|
+
throw new InboxContractError(message2);
|
|
8
8
|
}
|
|
9
9
|
function object(value, label) {
|
|
10
10
|
return (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) && fail(`${label} must be a plain object`), value;
|
|
@@ -12,8 +12,8 @@ function object(value, label) {
|
|
|
12
12
|
function keys(value, allowed, label) {
|
|
13
13
|
for (let key of Reflect.ownKeys(value)) {
|
|
14
14
|
(typeof key != "string" || !allowed.includes(key)) && fail(`${label} does not support ${String(key)}`);
|
|
15
|
-
let
|
|
16
|
-
(!
|
|
15
|
+
let descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
16
|
+
(!descriptor.enumerable || !("value" in descriptor)) && fail(`${label} must contain only JSON data`);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
function text(value, label) {
|
|
@@ -26,8 +26,8 @@ function id(value, label) {
|
|
|
26
26
|
function array(value, label) {
|
|
27
27
|
(!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || Reflect.ownKeys(value).length !== value.length + 1) && fail(`${label} must be a dense array`);
|
|
28
28
|
for (let index = 0; index < value.length; index += 1) {
|
|
29
|
-
let
|
|
30
|
-
(!
|
|
29
|
+
let descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
30
|
+
(!descriptor?.enumerable || !("value" in descriptor)) && fail(`${label} must contain only JSON data`);
|
|
31
31
|
}
|
|
32
32
|
return value;
|
|
33
33
|
}
|
|
@@ -268,12 +268,12 @@ function presentation(source) {
|
|
|
268
268
|
return keys(view, ["id", "view", "input"], "view"), { id: id(view.id, "view ID"), view: id(view.view, "view name"), input: serializable(view.input) };
|
|
269
269
|
});
|
|
270
270
|
new Set(views.map((view) => view.id)).size !== views.length && fail("Duplicate view ID");
|
|
271
|
-
let
|
|
272
|
-
for (let block2 of
|
|
271
|
+
let body = source.body === void 0 ? [] : array(source.body, "body").map(validateBlock);
|
|
272
|
+
for (let block2 of body) {
|
|
273
273
|
let targets = block2.kind === "record" ? [block2.view] : block2.kind === "records" ? [block2.view, ...block2.records.map((record3) => record3.view)] : [];
|
|
274
274
|
for (let target of targets) target !== void 0 && !views.some((view) => view.id === target) && fail(`Unknown Block View target: ${target}`);
|
|
275
275
|
}
|
|
276
|
-
return { title: text(source.title, "title"), description: text(source.description, "description"), views, body
|
|
276
|
+
return { title: text(source.title, "title"), description: text(source.description, "description"), views, body };
|
|
277
277
|
}
|
|
278
278
|
function validatePublication(value) {
|
|
279
279
|
let source = object(value, "publication");
|
|
@@ -391,44 +391,44 @@ var FileOperationError = class extends Error {
|
|
|
391
391
|
retryable;
|
|
392
392
|
}, FILE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/, FILE_ORIGINAL_MAX_BYTES = 5 * 1024 ** 3;
|
|
393
393
|
function parseFileDescriptor(value) {
|
|
394
|
-
let
|
|
394
|
+
let invalid7 = () => {
|
|
395
395
|
throw new FileOperationError("unavailable", 503, !0);
|
|
396
396
|
};
|
|
397
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
397
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
|
|
398
398
|
let f = value;
|
|
399
|
-
if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return
|
|
399
|
+
if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return invalid7();
|
|
400
400
|
let d = f.details;
|
|
401
401
|
if (d.kind === "other") {
|
|
402
|
-
if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return
|
|
402
|
+
if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid7();
|
|
403
403
|
} else if (d.kind === "csv") {
|
|
404
|
-
if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return
|
|
404
|
+
if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return invalid7();
|
|
405
405
|
} else if (d.kind === "pdf") {
|
|
406
|
-
if (f.mediaType !== "application/pdf" || Object.keys(d).some((key) => !["kind", "pages"].includes(key)) || "pages" in d && (!Number.isSafeInteger(d.pages) || d.pages < 1)) return
|
|
407
|
-
} else return
|
|
408
|
-
for (let [name,
|
|
409
|
-
if (!safeEnrichmentName(name)) return
|
|
410
|
-
parseEnrichmentDescriptor(
|
|
406
|
+
if (f.mediaType !== "application/pdf" || Object.keys(d).some((key) => !["kind", "pages"].includes(key)) || "pages" in d && (!Number.isSafeInteger(d.pages) || d.pages < 1)) return invalid7();
|
|
407
|
+
} else return invalid7();
|
|
408
|
+
for (let [name, descriptor] of Object.entries(f.enrichments)) {
|
|
409
|
+
if (!safeEnrichmentName(name)) return invalid7();
|
|
410
|
+
parseEnrichmentDescriptor(descriptor);
|
|
411
411
|
}
|
|
412
|
-
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ?
|
|
412
|
+
return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid7() : f;
|
|
413
413
|
}
|
|
414
414
|
function parseEnrichmentDescriptor(value) {
|
|
415
|
-
let
|
|
415
|
+
let invalid7 = () => {
|
|
416
416
|
throw new FileOperationError("unavailable", 503, !0);
|
|
417
417
|
};
|
|
418
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
418
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
|
|
419
419
|
let d = value;
|
|
420
|
-
return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ?
|
|
420
|
+
return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ? invalid7() : d;
|
|
421
421
|
}
|
|
422
422
|
function safeEnrichmentName(value) {
|
|
423
423
|
return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
|
|
424
424
|
}
|
|
425
425
|
function parseFileEnrichMetadata(value, maxBytes) {
|
|
426
|
-
let
|
|
426
|
+
let invalid7 = () => {
|
|
427
427
|
throw new FileOperationError("invalid_input", 400);
|
|
428
428
|
};
|
|
429
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
429
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
|
|
430
430
|
let d = value;
|
|
431
|
-
if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return
|
|
431
|
+
if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid7();
|
|
432
432
|
if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
433
433
|
return d;
|
|
434
434
|
}
|
|
@@ -439,23 +439,23 @@ function safeFilePath(value) {
|
|
|
439
439
|
return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
|
|
440
440
|
}
|
|
441
441
|
function parseFileCreateMetadata(value, maxBytes) {
|
|
442
|
-
let
|
|
442
|
+
let invalid7 = () => {
|
|
443
443
|
throw new FileOperationError("invalid_input", 400);
|
|
444
444
|
};
|
|
445
|
-
if (!value || typeof value != "object" || Array.isArray(value)) return
|
|
445
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
|
|
446
446
|
let input = value;
|
|
447
|
-
if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return
|
|
447
|
+
if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return invalid7();
|
|
448
448
|
let path = input.path === void 0 ? "Files" : input.path;
|
|
449
|
-
if (!safeFileName(input.name) || !safeFilePath(path) || path.split("/")[0].toLowerCase() === ".os" || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || input.inputMediaType !== void 0 && input.inputMediaType !== "application/pdf" || !Number.isSafeInteger(input.size) || input.size < 0) return
|
|
449
|
+
if (!safeFileName(input.name) || !safeFilePath(path) || path.split("/")[0].toLowerCase() === ".os" || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || input.inputMediaType !== void 0 && input.inputMediaType !== "application/pdf" || !Number.isSafeInteger(input.size) || input.size < 0) return invalid7();
|
|
450
450
|
if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
|
|
451
|
-
if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return
|
|
451
|
+
if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return invalid7();
|
|
452
452
|
let csv;
|
|
453
453
|
if (input.csv !== void 0) {
|
|
454
|
-
if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return
|
|
454
|
+
if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid7();
|
|
455
455
|
let hints = input.csv;
|
|
456
|
-
if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return
|
|
456
|
+
if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid7();
|
|
457
457
|
let encoding = hints.encoding === void 0 ? "utf-8" : hints.encoding, delimiter = hints.delimiter === void 0 ? "," : hints.delimiter, headerRow = hints.headerRow === void 0 ? 1 : hints.headerRow;
|
|
458
|
-
if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return
|
|
458
|
+
if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid7();
|
|
459
459
|
csv = { encoding, delimiter, headerRow };
|
|
460
460
|
}
|
|
461
461
|
return {
|
|
@@ -572,54 +572,137 @@ function validateRoutineSchemaValue(schema2, value) {
|
|
|
572
572
|
}
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
-
var
|
|
575
|
+
var ROUTINE_DECLARATION_SCHEMA = "https://schemas.oddington.ai/routine/v1.json", ROUTINE_SOURCE_LIMITS = { files: 2e4, bytes: 256 * 1024 * 1024, declarationBytes: 64 * 1024 };
|
|
576
|
+
var invalid = (field) => {
|
|
577
|
+
throw new Error(`Invalid routine declaration: ${field}`);
|
|
578
|
+
}, object2 = (value, fields5, field) => ((!value || typeof value != "object" || Array.isArray(value) || Object.keys(value).some((key) => !fields5.includes(key))) && 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());
|
|
579
|
+
function routineAssetPattern(value) {
|
|
580
|
+
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));
|
|
581
|
+
}
|
|
582
|
+
function parseRoutineDeclaration(value) {
|
|
583
|
+
let v = object2(value, ["$schema", "access", "runtime", "retry", "assets"], "fields");
|
|
584
|
+
v.$schema !== ROUTINE_DECLARATION_SCHEMA && invalid("$schema");
|
|
585
|
+
let access = object2(v.access === void 0 ? {} : v.access, ["repositories", "connections", "models", "files", "publish"], "access"), rawRepositories = access.repositories === void 0 ? {} : access.repositories, repositories = object2(rawRepositories, rawRepositories && typeof rawRepositories == "object" ? Object.keys(rawRepositories) : [], "access.repositories");
|
|
586
|
+
Object.keys(repositories).length > 64 && invalid("access.repositories");
|
|
587
|
+
let grants = {};
|
|
588
|
+
for (let key of Object.keys(repositories).sort())
|
|
589
|
+
(!routineAlias(key) || !["read", "write"].includes(repositories[key])) && invalid(`access.repositories.${key}`), grants[key] = repositories[key];
|
|
590
|
+
access.files !== void 0 && !["read", "read-write"].includes(access.files) && invalid("access.files");
|
|
591
|
+
let runtime = object2(v.runtime === void 0 ? {} : v.runtime, ["features", "resources", "maxDuration"], "runtime");
|
|
592
|
+
runtime.resources !== void 0 && !["standard", "large"].includes(runtime.resources) && invalid("runtime.resources");
|
|
593
|
+
let duration = runtime.maxDuration === void 0 ? "15m" : runtime.maxDuration;
|
|
594
|
+
(typeof duration != "string" || !/^(?:[1-5][0-9]|60)m$/.test(duration) || Number(duration.slice(0, -1)) < 15) && invalid("runtime.maxDuration");
|
|
595
|
+
let retry = object2(v.retry === void 0 ? {} : v.retry, ["maxAttempts"], "retry"), maxAttempts = retry.maxAttempts === void 0 ? 1 : retry.maxAttempts;
|
|
596
|
+
(!Number.isInteger(maxAttempts) || maxAttempts < 1 || maxAttempts > 3) && invalid("retry.maxAttempts");
|
|
597
|
+
let assets = v.assets === void 0 ? [] : v.assets;
|
|
598
|
+
return (!Array.isArray(assets) || assets.length > 64 || assets.some((item) => !routineAssetPattern(item)) || new Set(assets).size !== assets.length) && invalid("assets"), {
|
|
599
|
+
$schema: ROUTINE_DECLARATION_SCHEMA,
|
|
600
|
+
access: {
|
|
601
|
+
repositories: grants,
|
|
602
|
+
connections: list(access.connections, "access.connections", void 0, !0),
|
|
603
|
+
models: list(access.models, "access.models"),
|
|
604
|
+
...access.files === void 0 ? {} : { files: access.files },
|
|
605
|
+
publish: list(access.publish, "access.publish", ["asks", "digests"])
|
|
606
|
+
},
|
|
607
|
+
runtime: {
|
|
608
|
+
features: list(runtime.features, "runtime.features", ["python", "documents", "browser"]),
|
|
609
|
+
resources: runtime.resources ?? "standard",
|
|
610
|
+
maxDuration: duration
|
|
611
|
+
},
|
|
612
|
+
retry: { maxAttempts },
|
|
613
|
+
assets: [...assets].sort()
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
var invalid2 = () => {
|
|
576
618
|
throw new AppRoutineContractError("invalid_value");
|
|
577
619
|
}, invalidContract2 = () => {
|
|
578
620
|
throw new AppRoutineContractError("invalid_contract");
|
|
579
|
-
},
|
|
580
|
-
function
|
|
621
|
+
}, routineTitle = (value) => typeof value == "string" && value.trim().length > 0 && value.length <= 256;
|
|
622
|
+
function freezeRoutineMetadata(value) {
|
|
581
623
|
if (value !== null && typeof value == "object") {
|
|
582
|
-
for (let child of Object.values(value))
|
|
624
|
+
for (let child of Object.values(value)) freezeRoutineMetadata(child);
|
|
583
625
|
Object.freeze(value);
|
|
584
626
|
}
|
|
585
627
|
return value;
|
|
586
628
|
}
|
|
587
|
-
function
|
|
629
|
+
function assertRoutineJson(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
588
630
|
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return;
|
|
589
|
-
if (!value || typeof value != "object" || ancestors.has(value)) return
|
|
631
|
+
if (!value || typeof value != "object" || ancestors.has(value)) return invalid2();
|
|
590
632
|
let array3 = Array.isArray(value);
|
|
591
|
-
if (!array3 && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return
|
|
592
|
-
let
|
|
593
|
-
if (array3 && (
|
|
633
|
+
if (!array3 && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return invalid2();
|
|
634
|
+
let keys4 = Reflect.ownKeys(value);
|
|
635
|
+
if (array3 && (keys4.length !== value.length + 1 || !Array.from({ length: value.length }, (_, index) => Object.hasOwn(value, index)).every(Boolean))) return invalid2();
|
|
594
636
|
ancestors.add(value);
|
|
595
|
-
for (let key of
|
|
637
|
+
for (let key of keys4) {
|
|
596
638
|
if (array3 && key === "length") continue;
|
|
597
|
-
if (typeof key != "string") return
|
|
598
|
-
let
|
|
599
|
-
if (!
|
|
600
|
-
|
|
639
|
+
if (typeof key != "string") return invalid2();
|
|
640
|
+
let descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
641
|
+
if (!descriptor.enumerable || !Object.hasOwn(descriptor, "value")) return invalid2();
|
|
642
|
+
assertRoutineJson(descriptor.value, ancestors);
|
|
601
643
|
}
|
|
602
644
|
ancestors.delete(value);
|
|
603
645
|
}
|
|
604
|
-
function
|
|
605
|
-
|
|
606
|
-
let encoded = JSON.stringify(value);
|
|
607
|
-
return new TextEncoder().encode(encoded).byteLength > LIMIT ? invalid() : freeze(JSON.parse(encoded));
|
|
646
|
+
function assertRoutineFields(value, allowed) {
|
|
647
|
+
if (!value || typeof value != "object" || Object.getPrototypeOf(value) !== Object.prototype || Reflect.ownKeys(value).some((key) => typeof key != "string" || allowed && !allowed.includes(key) || !Object.getOwnPropertyDescriptor(value, key).enumerable || !Object.hasOwn(Object.getOwnPropertyDescriptor(value, key), "value"))) return invalidContract2();
|
|
608
648
|
}
|
|
609
|
-
function
|
|
649
|
+
function parseRoutineAccess(value) {
|
|
610
650
|
try {
|
|
611
|
-
|
|
651
|
+
value !== void 0 && assertRoutineJson(value), assertRoutineFields(value ?? {}, ["repositories", "connections", "models", "files", "publish"]);
|
|
652
|
+
let access = value, names = access?.connections ?? [];
|
|
653
|
+
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();
|
|
654
|
+
let parsed = parseRoutineDeclaration({ $schema: ROUTINE_DECLARATION_SCHEMA, access: { ...access, connections: [] } }).access;
|
|
655
|
+
return freezeRoutineMetadata({ ...parsed, connections: [...names] });
|
|
612
656
|
} catch {
|
|
613
657
|
return invalidContract2();
|
|
614
658
|
}
|
|
615
|
-
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
var LIMIT = 256 * 1024, invalid3 = () => {
|
|
662
|
+
throw new AppRoutineContractError("invalid_value");
|
|
663
|
+
}, invalidContract3 = () => {
|
|
664
|
+
throw new AppRoutineContractError("invalid_contract");
|
|
665
|
+
}, empty = { type: "object", properties: {}, required: [], additionalProperties: !1 };
|
|
666
|
+
function captureJson(value) {
|
|
667
|
+
assertRoutineJson(value);
|
|
668
|
+
let encoded = JSON.stringify(value);
|
|
669
|
+
return new TextEncoder().encode(encoded).byteLength > LIMIT ? invalid3() : freezeRoutineMetadata(JSON.parse(encoded));
|
|
670
|
+
}
|
|
671
|
+
function capture(schema2, value) {
|
|
672
|
+
let captured = captureJson(value);
|
|
673
|
+
return validateRoutineSchemaValue(schema2, captured), captured;
|
|
674
|
+
}
|
|
675
|
+
var schemas = /* @__PURE__ */ new WeakMap();
|
|
676
|
+
function nestedSchema(value) {
|
|
677
|
+
let metadata = schemaMetadata(value);
|
|
678
|
+
return Object.hasOwn(metadata, "default") ? invalidContract3() : metadata.schema;
|
|
679
|
+
}
|
|
680
|
+
function schemaMetadata(value) {
|
|
681
|
+
if (!value || typeof value != "object") return invalidContract3();
|
|
682
|
+
let registered = schemas.get(value);
|
|
683
|
+
if (registered) return registered;
|
|
684
|
+
try {
|
|
685
|
+
assertRoutineJson(value);
|
|
686
|
+
} catch {
|
|
687
|
+
return invalidContract3();
|
|
688
|
+
}
|
|
689
|
+
return { schema: parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input };
|
|
690
|
+
}
|
|
691
|
+
function declaration(value, defaults) {
|
|
692
|
+
try {
|
|
693
|
+
assertRoutineJson(value);
|
|
694
|
+
} catch {
|
|
695
|
+
return invalidContract3();
|
|
696
|
+
}
|
|
697
|
+
let parsed = freezeRoutineMetadata(parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input), captured = defaults ? capture(parsed, defaults.value) : void 0, builder = Object.defineProperty({ ...parsed }, "default", { value: (value2) => declaration(parsed, { value: value2 }) });
|
|
698
|
+
return schemas.set(builder, { schema: parsed, ...defaults ? { default: captured } : {} }), Object.freeze(builder);
|
|
616
699
|
}
|
|
617
700
|
var schema = {
|
|
618
701
|
object(properties) {
|
|
619
|
-
return declaration({ type: "object", properties, required: Object.keys(properties), additionalProperties: !1 });
|
|
702
|
+
return declaration({ type: "object", properties: Object.fromEntries(Object.entries(properties).map(([key, value]) => [key, nestedSchema(value)])), required: Object.keys(properties), additionalProperties: !1 });
|
|
620
703
|
},
|
|
621
704
|
array(items, options) {
|
|
622
|
-
return declaration({ type: "array", items, maxItems: options.maxItems });
|
|
705
|
+
return declaration({ type: "array", items: nestedSchema(items), maxItems: options.maxItems });
|
|
623
706
|
},
|
|
624
707
|
string(options = {}) {
|
|
625
708
|
return declaration({ type: "string", ...options });
|
|
@@ -634,75 +717,123 @@ var schema = {
|
|
|
634
717
|
return declaration({ type: "boolean" });
|
|
635
718
|
}
|
|
636
719
|
}, file = () => declaration({ type: "file" }), definitions = /* @__PURE__ */ new WeakMap(), defineRoutine = (definition) => {
|
|
637
|
-
if (
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
720
|
+
if (assertRoutineFields(definition, ["id", "title", "input", "steps", "result", "access", "responses", "run"]), !isAppRoutineName(definition.id) || definition.title !== void 0 && !routineTitle(definition.title) || typeof definition.run != "function") return invalidContract3();
|
|
721
|
+
let input = definition.input === void 0 ? { schema: empty, default: {} } : schemaMetadata(definition.input), result2 = definition.result === void 0 ? void 0 : schemaMetadata(definition.result).schema, access = parseRoutineAccess(definition.access);
|
|
722
|
+
assertRoutineFields(definition.steps ?? {});
|
|
723
|
+
let executable = Object.fromEntries(Object.entries(definition.steps ?? {}).map(([id3, step]) => (assertRoutineFields(step, ["title", "run"]), !routineTitle(step.title) || typeof step.run != "function" ? invalidContract3() : [id3, Object.freeze({ title: step.title, run: step.run })]))), steps = Object.entries(executable).map(([id3, step]) => ({ id: id3, title: step.title }));
|
|
724
|
+
parseAppRoutineContract({
|
|
725
|
+
routine: definition.id,
|
|
726
|
+
input: input.schema,
|
|
727
|
+
steps: steps.length ? steps.map(({ id: id3 }) => ({ id: id3 })) : [{ id: "inspect" }],
|
|
728
|
+
...result2 ? { result: result2 } : {}
|
|
729
|
+
});
|
|
730
|
+
let responses = [], ids = /* @__PURE__ */ new Set();
|
|
731
|
+
if (definition.responses !== void 0) {
|
|
732
|
+
if (!Array.isArray(definition.responses) || definition.responses.length > 64 || Reflect.ownKeys(definition.responses).length !== definition.responses.length + 1) return invalidContract3();
|
|
733
|
+
for (let index = 0; index < definition.responses.length; index++) {
|
|
734
|
+
let descriptor = Object.getOwnPropertyDescriptor(definition.responses, String(index));
|
|
735
|
+
if (!descriptor || !Object.hasOwn(descriptor, "value")) return invalidContract3();
|
|
736
|
+
let response2 = descriptor.value;
|
|
737
|
+
if (assertRoutineFields(response2, ["id", "results", "run"]), !isAppRoutineName(response2.id) || ids.has(response2.id)) return invalidContract3();
|
|
738
|
+
if (ids.add(response2.id), response2.results !== void 0)
|
|
739
|
+
try {
|
|
740
|
+
assertRoutineJson(response2.results);
|
|
741
|
+
} catch {
|
|
742
|
+
return invalidContract3();
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
responses.push(defineHandler(response2));
|
|
746
|
+
} catch {
|
|
747
|
+
return invalidContract3();
|
|
748
|
+
}
|
|
749
|
+
}
|
|
643
750
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
input:
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
...parsed.result === void 0 ? {} : { result: parsed.result }
|
|
751
|
+
let contract = freezeRoutineMetadata({
|
|
752
|
+
id: definition.id,
|
|
753
|
+
...definition.title === void 0 ? {} : { title: definition.title },
|
|
754
|
+
input: input.schema,
|
|
755
|
+
...Object.hasOwn(input, "default") ? { inputDefault: input.default } : {},
|
|
756
|
+
access,
|
|
757
|
+
responses: responses.map(({ id: id3 }) => ({ id: id3 })),
|
|
758
|
+
steps,
|
|
759
|
+
...result2 ? { result: result2 } : {}
|
|
654
760
|
}), captured = Object.freeze({
|
|
655
761
|
...definition,
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
762
|
+
access,
|
|
763
|
+
steps: Object.freeze(executable),
|
|
764
|
+
responses: Object.freeze(responses),
|
|
765
|
+
...definition.input === void 0 ? {} : { input: declaration(
|
|
766
|
+
input.schema,
|
|
767
|
+
Object.hasOwn(input, "default") ? { value: input.default } : void 0
|
|
768
|
+
) },
|
|
769
|
+
...result2 === void 0 ? {} : { result: declaration(result2) },
|
|
659
770
|
// Only this authored definition is callable; no generic runner is exported.
|
|
660
|
-
run: (
|
|
771
|
+
run: (input2, os2) => executeRoutineDefinition(captured, input2, os2)
|
|
661
772
|
});
|
|
662
|
-
return definitions.set(captured, { contract, run: definition.run }), captured;
|
|
773
|
+
return definitions.set(captured, { contract, steps: executable, run: definition.run }), captured;
|
|
663
774
|
};
|
|
664
775
|
function inspectRoutineDefinition(definition) {
|
|
665
|
-
if (!definition || typeof definition != "object") return
|
|
776
|
+
if (!definition || typeof definition != "object") return invalidContract3();
|
|
666
777
|
let registered = definitions.get(definition);
|
|
667
|
-
return registered ? registered.contract :
|
|
778
|
+
return registered ? registered.contract : invalidContract3();
|
|
668
779
|
}
|
|
669
780
|
function captureRoutineInput(definition, input) {
|
|
670
|
-
|
|
781
|
+
let contract = inspectRoutineDefinition(definition);
|
|
782
|
+
return capture(contract.input, input === void 0 && Object.hasOwn(contract, "inputDefault") ? contract.inputDefault : input);
|
|
671
783
|
}
|
|
672
784
|
async function executeRoutineDefinition(definition, input, runtime) {
|
|
673
|
-
let captured = captureRoutineInput(definition, input), { contract, run } = definitions.get(definition), active2 = !0, broken = !1,
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
785
|
+
let captured = captureRoutineInput(definition, input), { contract, steps, run } = definitions.get(definition), active2 = !0, accepting = !0, broken = !1, work = Promise.resolve(), called = /* @__PURE__ */ new Set(), reached = /* @__PURE__ */ new Set(), guarded = (value, receiver) => typeof value == "function" ? (...args) => {
|
|
786
|
+
if (!active2 || broken) throw new Error("Run authority ended");
|
|
787
|
+
return guarded(Reflect.apply(value, receiver, args));
|
|
788
|
+
} : value && typeof value == "object" && !(value instanceof Promise) ? new Proxy({ ...value }, {
|
|
789
|
+
// Copy the surface so wrapping a frozen host capability does not violate
|
|
790
|
+
// Proxy invariants; methods still receive their original host receiver.
|
|
791
|
+
get(_target, key) {
|
|
792
|
+
return guarded(Reflect.get(value, key, value), value);
|
|
793
|
+
}
|
|
794
|
+
}) : value, qualify = (value) => value.questions === void 0 ? value : { ...value, questions: value.questions.map((question2) => question2.handler ? contract.responses.some((handler) => handler.id === question2.handler.id) ? { ...question2, handler: { ...question2.handler, id: `${contract.id}/${question2.handler.id}` } } : invalid3() : question2) }, os2 = Object.freeze({
|
|
795
|
+
...guarded({
|
|
796
|
+
...runtime,
|
|
797
|
+
run: freezeRoutineMetadata({ ...runtime.run }),
|
|
798
|
+
inbox: { ...runtime.inbox, publishAsk: (value, options) => runtime.inbox.publishAsk(qualify(value), options) }
|
|
799
|
+
}),
|
|
800
|
+
step(id3, ...input2) {
|
|
801
|
+
let saved;
|
|
685
802
|
try {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (step.summary === void 0) {
|
|
689
|
-
if (summary.length) return invalid();
|
|
690
|
-
} else value = capture(step.summary, summary[0]);
|
|
803
|
+
if (!active2 || !accepting || broken || !Object.hasOwn(steps, id3) || called.has(id3) || input2.length > 1) return invalid3();
|
|
804
|
+
input2.length && (saved = captureJson(input2[0])), called.add(id3);
|
|
691
805
|
} catch (error) {
|
|
692
806
|
return broken = !0, Promise.reject(error);
|
|
693
807
|
}
|
|
694
|
-
let
|
|
695
|
-
|
|
808
|
+
let next = work.then(async () => {
|
|
809
|
+
if (broken) return invalid3();
|
|
810
|
+
reached.add(id3);
|
|
811
|
+
try {
|
|
812
|
+
await runtime.step(id3, { status: "running" });
|
|
813
|
+
let output = await steps[id3].run(saved, os2);
|
|
814
|
+
if (assertRoutineFields(output, ["summary", "data"]), !Object.hasOwn(output, "summary") || !Object.hasOwn(output, "data")) return invalid3();
|
|
815
|
+
let summary2 = captureJson(output.summary), data3 = captureJson(output.data);
|
|
816
|
+
return await runtime.step(id3, { status: "completed", summary: summary2, data: data3 }), freezeRoutineMetadata({ summary: summary2, data: data3 });
|
|
817
|
+
} catch (error) {
|
|
818
|
+
throw broken = !0, await runtime.step(id3, { status: "failed" }), error;
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
return work = next.then(() => {
|
|
822
|
+
}, () => {
|
|
696
823
|
broken = !0;
|
|
697
|
-
}),
|
|
824
|
+
}), next;
|
|
698
825
|
}
|
|
699
|
-
});
|
|
826
|
+
}), result2, failure;
|
|
700
827
|
try {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
active2 = !1;
|
|
828
|
+
result2 = await run(captured, os2);
|
|
829
|
+
} catch (error) {
|
|
830
|
+
failure = error, broken = !0;
|
|
705
831
|
}
|
|
832
|
+
accepting = !1, await work, active2 = !1;
|
|
833
|
+
for (let step of contract.steps) reached.has(step.id) || await runtime.step(step.id, { status: "skipped" });
|
|
834
|
+
if (broken) throw failure ?? new AppRoutineContractError("invalid_value");
|
|
835
|
+
if (contract.result !== void 0) return capture(contract.result, result2);
|
|
836
|
+
if (result2 !== void 0) return invalid3();
|
|
706
837
|
}
|
|
707
838
|
|
|
708
839
|
var DataOperationError = class extends Error {
|
|
@@ -720,46 +851,46 @@ var DataOperationError = class extends Error {
|
|
|
720
851
|
component;
|
|
721
852
|
};
|
|
722
853
|
|
|
723
|
-
var
|
|
854
|
+
var invalid4 = () => {
|
|
724
855
|
throw new DataOperationError("invalid_query");
|
|
725
856
|
}, historyText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
|
|
726
857
|
function historyVersion(value) {
|
|
727
858
|
return historyText(value) && value.length > 0 && new TextEncoder().encode(value).length <= 1024 && !/[\u0000-\u001f\u007f-\u009f]/.test(value) && !/^[0-9a-f]{40}$/i.test(value);
|
|
728
859
|
}
|
|
729
860
|
function historyProperties(value) {
|
|
730
|
-
if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return
|
|
861
|
+
if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return invalid4();
|
|
731
862
|
let descriptors = Object.getOwnPropertyDescriptors(value);
|
|
732
|
-
return Reflect.ownKeys(value).some((key) => typeof key != "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")) ?
|
|
863
|
+
return Reflect.ownKeys(value).some((key) => typeof key != "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")) ? invalid4() : descriptors;
|
|
733
864
|
}
|
|
734
865
|
var historyCollection = (value) => typeof value == "string" && value.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(value), historyCursor = (value) => typeof value == "string" && value.length <= 128 * 1024 && /^history-cursor-v1\.[A-Za-z0-9_-]{1,64}\.[A-Za-z0-9_-]{16}\.[A-Za-z0-9_-]+$/.test(value);
|
|
735
866
|
function historyArray(value) {
|
|
736
|
-
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return
|
|
867
|
+
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return invalid4();
|
|
737
868
|
let descriptors = Object.getOwnPropertyDescriptors(value);
|
|
738
|
-
if (Reflect.ownKeys(value).length !== value.length + 1) return
|
|
869
|
+
if (Reflect.ownKeys(value).length !== value.length + 1) return invalid4();
|
|
739
870
|
let result2 = [];
|
|
740
871
|
for (let i = 0; i < value.length; i++) {
|
|
741
|
-
let
|
|
742
|
-
if (!
|
|
743
|
-
result2.push(
|
|
872
|
+
let descriptor = descriptors[i];
|
|
873
|
+
if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value")) return invalid4();
|
|
874
|
+
result2.push(descriptor.value);
|
|
744
875
|
}
|
|
745
876
|
return result2;
|
|
746
877
|
}
|
|
747
878
|
function captureOptions(value, changes) {
|
|
748
879
|
if (value === void 0) return {};
|
|
749
880
|
let descriptors = historyProperties(value), result2 = {}, allowed = changes ? ["collections", "refs", "from", "through", "limit", "after"] : ["limit", "before"];
|
|
750
|
-
if (Object.keys(descriptors).some((key) => !allowed.includes(key))) return
|
|
881
|
+
if (Object.keys(descriptors).some((key) => !allowed.includes(key))) return invalid4();
|
|
751
882
|
for (let key of allowed) {
|
|
752
883
|
if (!Object.hasOwn(descriptors, key)) continue;
|
|
753
884
|
let scalar = descriptors[key].value;
|
|
754
885
|
if (key === "collections" || key === "refs") {
|
|
755
886
|
let values = historyArray(scalar);
|
|
756
|
-
if (!values.length || values.length > (key === "collections" ? 16 : 100) || !values.every(key === "collections" ? historyCollection : validRecordRef) || new Set(values).size !== values.length) return
|
|
887
|
+
if (!values.length || values.length > (key === "collections" ? 16 : 100) || !values.every(key === "collections" ? historyCollection : validRecordRef) || new Set(values).size !== values.length) return invalid4();
|
|
757
888
|
result2[key] = values;
|
|
758
889
|
} else if (key === "limit") {
|
|
759
|
-
if (!Number.isInteger(scalar) || scalar < 1 || scalar > (changes ? 500 : 100)) return
|
|
890
|
+
if (!Number.isInteger(scalar) || scalar < 1 || scalar > (changes ? 500 : 100)) return invalid4();
|
|
760
891
|
result2.limit = scalar;
|
|
761
892
|
} else {
|
|
762
|
-
if (!(key === "after" ? historyCursor(scalar) : historyVersion(scalar))) return
|
|
893
|
+
if (!(key === "after" ? historyCursor(scalar) : historyVersion(scalar))) return invalid4();
|
|
763
894
|
result2[key] = scalar;
|
|
764
895
|
}
|
|
765
896
|
}
|
|
@@ -767,39 +898,39 @@ function captureOptions(value, changes) {
|
|
|
767
898
|
}
|
|
768
899
|
var captureHistoryListOptions = (value) => captureOptions(value, !1), captureHistoryChangesOptions = (value) => captureOptions(value, !0);
|
|
769
900
|
function captureHistoryInstant(value) {
|
|
770
|
-
if (!historyText(value) || value.length > 1024) return
|
|
901
|
+
if (!historyText(value) || value.length > 1024) return invalid4();
|
|
771
902
|
let match = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?([Zz]|([+-])(\d{2}):(\d{2}))$/.exec(value);
|
|
772
|
-
if (!match) return
|
|
903
|
+
if (!match) return invalid4();
|
|
773
904
|
let [year, month, day, hour, minute, second] = match.slice(1, 7).map(Number), days = new Date(Date.UTC(year, month, 0));
|
|
774
|
-
return days.setUTCFullYear(year), year < 1 || month < 1 || month > 12 || day < 1 || day > days.getUTCDate() || hour > 23 || minute > 59 || second > 59 || Number(match[9] ?? 0) > 23 || Number(match[10] ?? 0) > 59 ?
|
|
905
|
+
return days.setUTCFullYear(year), year < 1 || month < 1 || month > 12 || day < 1 || day > days.getUTCDate() || hour > 23 || minute > 59 || second > 59 || Number(match[9] ?? 0) > 23 || Number(match[10] ?? 0) > 59 ? invalid4() : value;
|
|
775
906
|
}
|
|
776
907
|
|
|
777
|
-
var
|
|
908
|
+
var invalid5 = () => {
|
|
778
909
|
throw new DataOperationError("invalid_query");
|
|
779
910
|
};
|
|
780
911
|
function captureRecordsSearchInput(query, options) {
|
|
781
|
-
if (!historyText(query)) return
|
|
912
|
+
if (!historyText(query)) return invalid5();
|
|
782
913
|
let length = [...query.trim()].length;
|
|
783
|
-
if (length < 1 || length > 256) return
|
|
914
|
+
if (length < 1 || length > 256) return invalid5();
|
|
784
915
|
if (options === void 0) return { query };
|
|
785
916
|
let descriptors = historyProperties(options);
|
|
786
|
-
if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key))) return
|
|
917
|
+
if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key))) return invalid5();
|
|
787
918
|
let captured = {};
|
|
788
919
|
if (Object.hasOwn(descriptors, "collections")) {
|
|
789
920
|
let supplied = descriptors.collections.value;
|
|
790
|
-
if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return
|
|
921
|
+
if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return invalid5();
|
|
791
922
|
let collections = [];
|
|
792
923
|
for (let index = 0; index < supplied.length; index++) {
|
|
793
|
-
let
|
|
794
|
-
if (!
|
|
795
|
-
collections.push(
|
|
924
|
+
let descriptor = Object.getOwnPropertyDescriptor(supplied, String(index));
|
|
925
|
+
if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value") || !historyText(descriptor.value)) return invalid5();
|
|
926
|
+
collections.push(descriptor.value);
|
|
796
927
|
}
|
|
797
|
-
if (new Set(collections).size !== collections.length) return
|
|
928
|
+
if (new Set(collections).size !== collections.length) return invalid5();
|
|
798
929
|
captured.collections = collections;
|
|
799
930
|
}
|
|
800
931
|
if (Object.hasOwn(descriptors, "limit")) {
|
|
801
932
|
let supplied = descriptors.limit.value;
|
|
802
|
-
if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return
|
|
933
|
+
if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return invalid5();
|
|
803
934
|
captured.limit = supplied;
|
|
804
935
|
}
|
|
805
936
|
return { query, options: captured };
|
|
@@ -1051,7 +1182,7 @@ var data = {
|
|
|
1051
1182
|
}
|
|
1052
1183
|
};
|
|
1053
1184
|
|
|
1054
|
-
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,
|
|
1185
|
+
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, invalid6 = () => new FileOperationError("invalid_input", 400), unavailable = () => new FileOperationError("unavailable", 503, !0), failures = {
|
|
1055
1186
|
400: ["invalid_input", "unsupported_context"],
|
|
1056
1187
|
401: ["unauthenticated"],
|
|
1057
1188
|
403: ["access_denied"],
|
|
@@ -1068,7 +1199,7 @@ async function boundedBytes(stream, limit) {
|
|
|
1068
1199
|
for (; ; ) {
|
|
1069
1200
|
let { done, value } = await reader.read();
|
|
1070
1201
|
if (done) break;
|
|
1071
|
-
if (!(value instanceof Uint8Array)) throw
|
|
1202
|
+
if (!(value instanceof Uint8Array)) throw invalid6();
|
|
1072
1203
|
if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
|
|
1073
1204
|
bytes.set(value, size - value.byteLength);
|
|
1074
1205
|
}
|
|
@@ -1119,7 +1250,7 @@ async function hostedContent(url, init2, parent, upstream = fetch) {
|
|
|
1119
1250
|
reader?.releaseLock();
|
|
1120
1251
|
}
|
|
1121
1252
|
}
|
|
1122
|
-
},
|
|
1253
|
+
}, body = new ReadableStream({
|
|
1123
1254
|
async pull(controller) {
|
|
1124
1255
|
try {
|
|
1125
1256
|
reader ??= source.getReader();
|
|
@@ -1133,7 +1264,7 @@ async function hostedContent(url, init2, parent, upstream = fetch) {
|
|
|
1133
1264
|
}
|
|
1134
1265
|
},
|
|
1135
1266
|
cancel
|
|
1136
|
-
}, { highWaterMark: 0 }), wrapped = new Response(
|
|
1267
|
+
}, { highWaterMark: 0 }), wrapped = new Response(body, { status: response2.status, statusText: response2.statusText, headers: response2.headers });
|
|
1137
1268
|
for (let key of ["url", "redirected", "type"])
|
|
1138
1269
|
Object.defineProperty(wrapped, key, { value: response2[key] });
|
|
1139
1270
|
return wrapped;
|
|
@@ -1141,7 +1272,7 @@ async function hostedContent(url, init2, parent, upstream = fetch) {
|
|
|
1141
1272
|
throw detach(), delivery.abort(error), error;
|
|
1142
1273
|
}
|
|
1143
1274
|
}
|
|
1144
|
-
async function send(suffix, init2,
|
|
1275
|
+
async function send(suffix, init2, descriptor, initial, parent) {
|
|
1145
1276
|
let original = initial, checkCurrent = (context2 = original) => {
|
|
1146
1277
|
if (parent?.aborted) throw unavailable();
|
|
1147
1278
|
if (!original.isCurrent() || context2.url !== original.url) throw new FileOperationError("unsupported_context", 400);
|
|
@@ -1152,20 +1283,20 @@ async function send(suffix, init2, descriptor2, initial, parent) {
|
|
|
1152
1283
|
checkCurrent(context2);
|
|
1153
1284
|
try {
|
|
1154
1285
|
let response2 = await (async () => {
|
|
1155
|
-
let url = `${context2.url}${suffix}`,
|
|
1286
|
+
let url = `${context2.url}${suffix}`, request2 = {
|
|
1156
1287
|
...init2,
|
|
1157
1288
|
signal: parent,
|
|
1158
1289
|
headers: { ...context2.headers, ...init2.headers },
|
|
1159
1290
|
redirect: "error",
|
|
1160
1291
|
cache: "no-store"
|
|
1161
1292
|
};
|
|
1162
|
-
return
|
|
1293
|
+
return descriptor ? fetch(url, request2) : hostedContent(url, request2, parent);
|
|
1163
1294
|
})();
|
|
1164
1295
|
if (!response2.ok) {
|
|
1165
1296
|
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);
|
|
1166
1297
|
throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") : unavailable();
|
|
1167
1298
|
}
|
|
1168
|
-
if (response2.status !== (
|
|
1299
|
+
if (response2.status !== (descriptor === 204 ? 204 : 200) || descriptor === 204 && response2.body !== null)
|
|
1169
1300
|
throw response2.body?.cancel().catch(() => {
|
|
1170
1301
|
}), unavailable();
|
|
1171
1302
|
try {
|
|
@@ -1174,13 +1305,13 @@ async function send(suffix, init2, descriptor2, initial, parent) {
|
|
|
1174
1305
|
throw response2.body?.cancel().catch(() => {
|
|
1175
1306
|
}), error;
|
|
1176
1307
|
}
|
|
1177
|
-
if (
|
|
1178
|
-
if (!
|
|
1179
|
-
let value = await result(response2,
|
|
1180
|
-
if (
|
|
1308
|
+
if (descriptor === 204) return;
|
|
1309
|
+
if (!descriptor) return response2;
|
|
1310
|
+
let value = await result(response2, descriptor === "control" ? CONTROL_RESULT_BYTES : RESULT_BYTES);
|
|
1311
|
+
if (descriptor === "control")
|
|
1181
1312
|
return checkCurrent(), value;
|
|
1182
1313
|
let parsed;
|
|
1183
|
-
if (
|
|
1314
|
+
if (descriptor === "enrichment") {
|
|
1184
1315
|
if (!value || typeof value != "object" || Array.isArray(value)) throw unavailable();
|
|
1185
1316
|
let { name, ...metadata } = value;
|
|
1186
1317
|
if (!safeEnrichmentName(name)) throw unavailable();
|
|
@@ -1195,22 +1326,22 @@ async function send(suffix, init2, descriptor2, initial, parent) {
|
|
|
1195
1326
|
throw unavailable();
|
|
1196
1327
|
}
|
|
1197
1328
|
function idPath(id3) {
|
|
1198
|
-
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw
|
|
1329
|
+
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid6();
|
|
1199
1330
|
return `/${id3}`;
|
|
1200
1331
|
}
|
|
1201
1332
|
async function multipartCreate(input, metadata, exchange, release = () => {
|
|
1202
1333
|
active--;
|
|
1203
1334
|
}, upload) {
|
|
1204
|
-
let route = upload ? `${idPath(upload.file.id)}/upload/multipart` : "/multipart", ticket, reader, chunk, offset = 0, receipts = [], pending = /* @__PURE__ */ new Set(),
|
|
1335
|
+
let route = upload ? `${idPath(upload.file.id)}/upload/multipart` : "/multipart", ticket, reader, chunk, offset = 0, receipts = [], pending = /* @__PURE__ */ new Set(), request2 = (work, timeout = TIMEOUT_MS) => timed((signal) => {
|
|
1205
1336
|
let task = work(signal);
|
|
1206
1337
|
return pending.add(task), task.then(() => pending.delete(task), () => pending.delete(task)), task;
|
|
1207
|
-
}, void 0, timeout), control = (
|
|
1338
|
+
}, void 0, timeout), control = (body) => ({
|
|
1208
1339
|
method: "POST",
|
|
1209
1340
|
headers: { "content-type": "application/json", ...ticket ? { "x-oddington-transfer": ticket } : {} },
|
|
1210
|
-
body: JSON.stringify(
|
|
1341
|
+
body: JSON.stringify(body)
|
|
1211
1342
|
});
|
|
1212
1343
|
try {
|
|
1213
|
-
let start = await
|
|
1344
|
+
let start = await request2((signal) => exchange(`${route}/start`, control(upload?.file ?? metadata), "control", signal));
|
|
1214
1345
|
if (!start || typeof start != "object" || Array.isArray(start)) throw unavailable();
|
|
1215
1346
|
let session = start;
|
|
1216
1347
|
if (Object.keys(session).sort().join(",") !== "partBytes,ticket" || session.partBytes !== PART_BYTES || typeof session.ticket != "string" || !session.ticket || session.ticket.length > 64 * 1024) throw unavailable();
|
|
@@ -1218,7 +1349,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1218
1349
|
let lastProgress = Date.now(), next = async () => {
|
|
1219
1350
|
try {
|
|
1220
1351
|
if (Date.now() - lastProgress >= TIMEOUT_MS) throw unavailable();
|
|
1221
|
-
let value = await
|
|
1352
|
+
let value = await request2(() => reader.read(), Math.max(1, TIMEOUT_MS - (Date.now() - lastProgress)));
|
|
1222
1353
|
return value.value?.byteLength && (lastProgress = Date.now()), value;
|
|
1223
1354
|
} catch (error) {
|
|
1224
1355
|
throw await reader.cancel(error).catch(() => {
|
|
@@ -1230,7 +1361,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1230
1361
|
if (input.file instanceof Uint8Array) part = input.file.subarray(sent, sent + length).slice();
|
|
1231
1362
|
else if (input.file instanceof Blob) {
|
|
1232
1363
|
let slice = input.file.slice(sent, sent + length);
|
|
1233
|
-
part = new Uint8Array(await
|
|
1364
|
+
part = new Uint8Array(await request2(() => slice.arrayBuffer()));
|
|
1234
1365
|
} else {
|
|
1235
1366
|
part = new Uint8Array(length);
|
|
1236
1367
|
let filled = 0;
|
|
@@ -1238,20 +1369,20 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1238
1369
|
if (!chunk || offset === chunk.byteLength) {
|
|
1239
1370
|
chunk = void 0, offset = 0;
|
|
1240
1371
|
let value2 = await next();
|
|
1241
|
-
if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw
|
|
1372
|
+
if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid6();
|
|
1242
1373
|
}
|
|
1243
1374
|
let take = Math.min(length - filled, chunk.byteLength - offset);
|
|
1244
1375
|
part.set(chunk.subarray(offset, offset + take), filled), filled += take, offset += take, offset === chunk.byteLength && (chunk = void 0, offset = 0);
|
|
1245
1376
|
}
|
|
1246
1377
|
}
|
|
1247
|
-
if (part.byteLength !== length) throw
|
|
1378
|
+
if (part.byteLength !== length) throw invalid6();
|
|
1248
1379
|
if (reader && sent + length === metadata.size)
|
|
1249
1380
|
for (lastProgress = Date.now(); ; ) {
|
|
1250
1381
|
let value2 = await next();
|
|
1251
1382
|
if (value2.done) break;
|
|
1252
|
-
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw
|
|
1383
|
+
if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid6();
|
|
1253
1384
|
}
|
|
1254
|
-
let value = await
|
|
1385
|
+
let value = await request2((signal) => exchange(`${route}/part`, {
|
|
1255
1386
|
method: "POST",
|
|
1256
1387
|
headers: { "content-type": "application/octet-stream", "x-oddington-transfer": ticket, "x-oddington-part": String(partNumber) },
|
|
1257
1388
|
body: part.buffer
|
|
@@ -1262,9 +1393,9 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1262
1393
|
receipts.push({ partNumber, etag: receipt.etag }), sent += length, lastProgress = Date.now();
|
|
1263
1394
|
}
|
|
1264
1395
|
if (upload) for (let name of Object.keys(upload.file.enrichments)) {
|
|
1265
|
-
let bytes = await
|
|
1266
|
-
if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw
|
|
1267
|
-
await
|
|
1396
|
+
let bytes = await request2(() => upload.enrichment(name));
|
|
1397
|
+
if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid6();
|
|
1398
|
+
await request2((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
|
|
1268
1399
|
method: "POST",
|
|
1269
1400
|
headers: { "content-type": "application/octet-stream", "x-oddington-transfer": ticket },
|
|
1270
1401
|
body: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
|
|
@@ -1273,13 +1404,13 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1273
1404
|
await upload?.beforeComplete();
|
|
1274
1405
|
let completion = control({ parts: receipts });
|
|
1275
1406
|
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw unavailable();
|
|
1276
|
-
return parseFileDescriptor(await
|
|
1407
|
+
return parseFileDescriptor(await request2(
|
|
1277
1408
|
(signal) => exchange(`${route}/complete`, completion, !0, signal),
|
|
1278
1409
|
TIMEOUT_MS + Math.ceil(metadata.size / (1024 * 1024)) * 1e3
|
|
1279
1410
|
));
|
|
1280
1411
|
} catch (error) {
|
|
1281
1412
|
throw reader && await reader.cancel(error).catch(() => {
|
|
1282
|
-
}), ticket && await
|
|
1413
|
+
}), ticket && await request2((signal) => exchange(`${route}/abort`, control({}), "control", signal)).catch(() => {
|
|
1283
1414
|
}), error instanceof FileOperationError ? error : unavailable();
|
|
1284
1415
|
} finally {
|
|
1285
1416
|
chunk = void 0, reader?.releaseLock(), pending.size ? Promise.allSettled([...pending]).then(release) : release();
|
|
@@ -1301,7 +1432,7 @@ async function operation(work, initial, parent) {
|
|
|
1301
1432
|
function contentPath(id3, name) {
|
|
1302
1433
|
let path = idPath(id3);
|
|
1303
1434
|
if (name === void 0) return `${path}/content`;
|
|
1304
|
-
if (!safeEnrichmentName(name)) throw
|
|
1435
|
+
if (!safeEnrichmentName(name)) throw invalid6();
|
|
1305
1436
|
return `${path}/enrichments/${encodeURIComponent(name)}/content`;
|
|
1306
1437
|
}
|
|
1307
1438
|
async function read(id3, names) {
|
|
@@ -1310,12 +1441,12 @@ async function read(id3, names) {
|
|
|
1310
1441
|
let path = contentPath(id3, names);
|
|
1311
1442
|
return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
|
|
1312
1443
|
}
|
|
1313
|
-
if (!Array.isArray(names)) throw
|
|
1444
|
+
if (!Array.isArray(names)) throw invalid6();
|
|
1314
1445
|
let distinct = [], seen = /* @__PURE__ */ new Set();
|
|
1315
1446
|
for (let name of names) {
|
|
1316
|
-
if (typeof name != "string" || !safeEnrichmentName(name)) throw
|
|
1447
|
+
if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid6();
|
|
1317
1448
|
if (!seen.has(name)) {
|
|
1318
|
-
if (seen.size === 16) throw
|
|
1449
|
+
if (seen.size === 16) throw invalid6();
|
|
1319
1450
|
seen.add(name), distinct.push(name);
|
|
1320
1451
|
}
|
|
1321
1452
|
}
|
|
@@ -1350,11 +1481,11 @@ var files = {
|
|
|
1350
1481
|
async create(input, options) {
|
|
1351
1482
|
let context2 = await resolveFilesContext();
|
|
1352
1483
|
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")))
|
|
1353
|
-
throw
|
|
1484
|
+
throw invalid6();
|
|
1354
1485
|
let blob = input.file instanceof Blob, array3 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
|
|
1355
|
-
if (!blob && !array3 && !stream) throw
|
|
1486
|
+
if (!blob && !array3 && !stream) throw invalid6();
|
|
1356
1487
|
let intrinsic = blob ? input.file.size : array3 ? input.file.byteLength : void 0;
|
|
1357
|
-
if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw
|
|
1488
|
+
if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid6();
|
|
1358
1489
|
let name = input.name;
|
|
1359
1490
|
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));
|
|
1360
1491
|
let metadata = parseFileCreateMetadata({
|
|
@@ -1368,7 +1499,7 @@ var files = {
|
|
|
1368
1499
|
}, FILE_ORIGINAL_MAX_BYTES);
|
|
1369
1500
|
if (!context2.local && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
1370
1501
|
let header = encodeURIComponent(JSON.stringify(metadata));
|
|
1371
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1502
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid6();
|
|
1372
1503
|
if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
|
|
1373
1504
|
return active++, metadata.size > MAX_BYTES ? multipartCreate(input, metadata, (suffix, init2, kind, signal) => kind === !0 ? send(suffix, init2, !0, context2, signal) : send(suffix, init2, "control", context2, signal)) : timed(async (signal) => {
|
|
1374
1505
|
try {
|
|
@@ -1376,7 +1507,7 @@ var files = {
|
|
|
1376
1507
|
blob ? input.file.stream() : input.file,
|
|
1377
1508
|
metadata.size
|
|
1378
1509
|
);
|
|
1379
|
-
if (bytes.byteLength !== metadata.size) throw
|
|
1510
|
+
if (bytes.byteLength !== metadata.size) throw invalid6();
|
|
1380
1511
|
if (signal.aborted) throw unavailable();
|
|
1381
1512
|
return await send("", {
|
|
1382
1513
|
method: "POST",
|
|
@@ -1392,7 +1523,7 @@ var files = {
|
|
|
1392
1523
|
},
|
|
1393
1524
|
async enrich(input) {
|
|
1394
1525
|
let context2 = await resolveFilesContext();
|
|
1395
|
-
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
|
|
1526
|
+
if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw invalid6();
|
|
1396
1527
|
let path = `${idPath(input.file)}/enrichments`;
|
|
1397
1528
|
if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
|
|
1398
1529
|
throw new FileOperationError("request_too_large", 413);
|
|
@@ -1409,7 +1540,7 @@ var files = {
|
|
|
1409
1540
|
...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
|
|
1410
1541
|
...input.replace === void 0 ? {} : { replace: input.replace }
|
|
1411
1542
|
}, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
|
|
1412
|
-
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw
|
|
1543
|
+
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid6();
|
|
1413
1544
|
let result2 = await send(path, { method: "POST", headers: {
|
|
1414
1545
|
"content-type": "application/octet-stream",
|
|
1415
1546
|
"x-oddington-enrichment": header
|
|
@@ -1445,8 +1576,8 @@ function parseConnectionLease(raw, now = Date.now()) {
|
|
|
1445
1576
|
}
|
|
1446
1577
|
|
|
1447
1578
|
var AirtableOperationError = class extends Error {
|
|
1448
|
-
constructor(
|
|
1449
|
-
super(
|
|
1579
|
+
constructor(message2, effect = "unapplied", receipts = []) {
|
|
1580
|
+
super(message2);
|
|
1450
1581
|
this.effect = effect;
|
|
1451
1582
|
this.receipts = receipts;
|
|
1452
1583
|
this.name = "AirtableOperationError";
|
|
@@ -1456,10 +1587,10 @@ var AirtableOperationError = class extends Error {
|
|
|
1456
1587
|
};
|
|
1457
1588
|
|
|
1458
1589
|
var recordId = (v) => typeof v == "string" && /^rec[A-Za-z0-9]+$/.test(v), tableId = (v) => typeof v == "string" && /^tbl[A-Za-z0-9]+$/.test(v);
|
|
1459
|
-
function fail2(
|
|
1460
|
-
throw new AirtableOperationError(
|
|
1590
|
+
function fail2(message2) {
|
|
1591
|
+
throw new AirtableOperationError(message2);
|
|
1461
1592
|
}
|
|
1462
|
-
function
|
|
1593
|
+
function object3(v) {
|
|
1463
1594
|
return (!v || typeof v != "object" || Array.isArray(v) || ![null, Object.prototype].includes(Object.getPrototypeOf(v))) && fail2("Invalid Airtable data"), v;
|
|
1464
1595
|
}
|
|
1465
1596
|
function keys2(v, allowed, required = allowed) {
|
|
@@ -1469,7 +1600,7 @@ function text2(v) {
|
|
|
1469
1600
|
return typeof v == "string" && v.length > 0 && v.length <= 1024;
|
|
1470
1601
|
}
|
|
1471
1602
|
function fields3(v, nonempty = !1) {
|
|
1472
|
-
let result2 =
|
|
1603
|
+
let result2 = object3(v);
|
|
1473
1604
|
(nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !text2(k))) && fail2("Invalid Airtable fields");
|
|
1474
1605
|
try {
|
|
1475
1606
|
return serializable(result2);
|
|
@@ -1478,7 +1609,7 @@ function fields3(v, nonempty = !1) {
|
|
|
1478
1609
|
}
|
|
1479
1610
|
}
|
|
1480
1611
|
function record2(v) {
|
|
1481
|
-
let r =
|
|
1612
|
+
let r = object3(v);
|
|
1482
1613
|
return (!recordId(r.id) || r.createdTime !== void 0 && (typeof r.createdTime != "string" || !Number.isFinite(Date.parse(r.createdTime)))) && fail2("Malformed Airtable record"), { id: r.id, ...r.createdTime === void 0 ? {} : { createdTime: r.createdTime }, fields: fields3(r.fields) };
|
|
1483
1614
|
}
|
|
1484
1615
|
function equal(a, b) {
|
|
@@ -1511,7 +1642,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1511
1642
|
(!/^[a-z0-9][a-z0-9-]{0,62}$/.test(name) || !/^app[A-Za-z0-9]+$/.test(baseId) || !/^[A-Za-z0-9._~+/-]{1,8192}={0,2}$/.test(accessToken)) && fail2("Airtable connection unavailable");
|
|
1512
1643
|
let input;
|
|
1513
1644
|
try {
|
|
1514
|
-
input =
|
|
1645
|
+
input = object3(serializable(raw));
|
|
1515
1646
|
} catch {
|
|
1516
1647
|
return fail2("Invalid Airtable input");
|
|
1517
1648
|
}
|
|
@@ -1523,7 +1654,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1523
1654
|
operation: operation2.slice(8),
|
|
1524
1655
|
records: ids2.map((id3) => ({ id: id3 }))
|
|
1525
1656
|
});
|
|
1526
|
-
async function
|
|
1657
|
+
async function request2(path2, init2 = {}, write = !1) {
|
|
1527
1658
|
let response2;
|
|
1528
1659
|
try {
|
|
1529
1660
|
response2 = await (options.fetch ?? fetch)(`https://api.airtable.com/v0/${path2}`, {
|
|
@@ -1540,7 +1671,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1540
1671
|
}), new AirtableOperationError("Airtable request rejected", write && (response2.status >= 500 || response2.status === 408 || response2.status < 400) ? "uncertain" : "unapplied");
|
|
1541
1672
|
try {
|
|
1542
1673
|
if (!response2.headers.get("content-type")?.toLowerCase().includes("application/json")) throw new Error();
|
|
1543
|
-
let value =
|
|
1674
|
+
let value = object3(await response2.json()), safe = serializable(value);
|
|
1544
1675
|
if (Object.hasOwn(value, "error") || JSON.stringify(safe).includes(accessToken)) throw new Error();
|
|
1545
1676
|
return value;
|
|
1546
1677
|
} catch {
|
|
@@ -1551,13 +1682,13 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1551
1682
|
keys2(input, []);
|
|
1552
1683
|
let tables = [], seen = /* @__PURE__ */ new Set(), offset;
|
|
1553
1684
|
do {
|
|
1554
|
-
let query2 = new URLSearchParams(offset ? { offset } : {}), page = await
|
|
1685
|
+
let query2 = new URLSearchParams(offset ? { offset } : {}), page = await request2(`meta/bases/${baseId}/tables?${query2}`);
|
|
1555
1686
|
Array.isArray(page.tables) || fail2("Malformed Airtable tables");
|
|
1556
1687
|
for (let value of page.tables) {
|
|
1557
|
-
let t =
|
|
1688
|
+
let t = object3(value);
|
|
1558
1689
|
(!tableId(t.id) || !text2(t.name) || !text2(t.primaryFieldId) || !Array.isArray(t.fields) || tables.some((existing) => existing.id === t.id)) && fail2("Malformed Airtable table");
|
|
1559
1690
|
let metadata = t.fields.map((value2) => {
|
|
1560
|
-
let f =
|
|
1691
|
+
let f = object3(value2);
|
|
1561
1692
|
return (typeof f.id != "string" || !/^fld[A-Za-z0-9]+$/.test(f.id) || !text2(f.name) || !text2(f.type)) && fail2("Malformed Airtable field"), { id: f.id, name: f.name, type: f.type, ...f.options === void 0 ? {} : { options: serializable(f.options) } };
|
|
1562
1693
|
});
|
|
1563
1694
|
(!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 });
|
|
@@ -1570,7 +1701,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1570
1701
|
let path = `${baseId}/${encodeURIComponent(input.table)}`;
|
|
1571
1702
|
if (operation2 === "records.get") {
|
|
1572
1703
|
keys2(input, ["table", "id"]), recordId(input.id) || fail2("Invalid Airtable record ID");
|
|
1573
|
-
let result3 = record2(await
|
|
1704
|
+
let result3 = record2(await request2(`${path}/${input.id}`));
|
|
1574
1705
|
return result3.id !== input.id && fail2("Malformed Airtable record"), result3;
|
|
1575
1706
|
}
|
|
1576
1707
|
if (operation2 === "records.list") {
|
|
@@ -1580,7 +1711,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1580
1711
|
let query2 = new URLSearchParams();
|
|
1581
1712
|
for (let field of input.fields ?? []) query2.append("fields[]", field);
|
|
1582
1713
|
offset && query2.set("offset", offset);
|
|
1583
|
-
let page = await
|
|
1714
|
+
let page = await request2(`${path}?${query2}`);
|
|
1584
1715
|
Array.isArray(page.records) || fail2("Malformed Airtable records");
|
|
1585
1716
|
for (let value of page.records) {
|
|
1586
1717
|
let r = record2(value);
|
|
@@ -1592,7 +1723,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1592
1723
|
}
|
|
1593
1724
|
mutation || fail2("Unsupported Airtable operation"), keys2(input, ["table", "records"]), (!Array.isArray(input.records) || !input.records.length || input.records.length > 10) && fail2("Invalid Airtable batch");
|
|
1594
1725
|
let kind = operation2.slice(8), ids = /* @__PURE__ */ new Set(), records = input.records.map((value) => {
|
|
1595
|
-
let r =
|
|
1726
|
+
let r = object3(value);
|
|
1596
1727
|
if (keys2(r, kind === "create" ? ["fields"] : kind === "update" ? ["id", "expected", "set"] : ["id", "expected"]), kind === "create") return { fields: fields3(r.fields, !0) };
|
|
1597
1728
|
(!recordId(r.id) || ids.has(r.id)) && fail2("Invalid Airtable batch record ID"), ids.add(r.id);
|
|
1598
1729
|
let set = kind === "update" ? fields3(r.set, !0) : void 0;
|
|
@@ -1600,7 +1731,7 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1600
1731
|
});
|
|
1601
1732
|
for (let r of records) {
|
|
1602
1733
|
if (!("id" in r)) continue;
|
|
1603
|
-
let current2 = record2(await
|
|
1734
|
+
let current2 = record2(await request2(`${path}/${r.id}`));
|
|
1604
1735
|
current2.id !== r.id && fail2("Malformed Airtable record");
|
|
1605
1736
|
for (let [key, value] of Object.entries(r.expected))
|
|
1606
1737
|
(value === null ? Object.hasOwn(current2.fields, key) : !Object.hasOwn(current2.fields, key) || !equal(current2.fields[key], value)) && fail2("Airtable reviewed values are stale");
|
|
@@ -1608,14 +1739,14 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
|
|
|
1608
1739
|
await options.beforeMutation?.();
|
|
1609
1740
|
let query = new URLSearchParams();
|
|
1610
1741
|
if (kind === "delete") for (let id3 of ids) query.append("records[]", id3);
|
|
1611
|
-
let result2 = await
|
|
1742
|
+
let result2 = await request2(`${path}${kind === "delete" ? `?${query}` : ""}`, {
|
|
1612
1743
|
method: kind === "create" ? "POST" : kind === "update" ? "PATCH" : "DELETE",
|
|
1613
1744
|
...kind === "delete" ? {} : { body: JSON.stringify({ records: records.map((r) => "id" in r ? { id: r.id, fields: r.set } : r) }) }
|
|
1614
1745
|
}, !0), acknowledged = [], returned = [];
|
|
1615
1746
|
try {
|
|
1616
1747
|
if (!Array.isArray(result2.records)) throw new Error();
|
|
1617
1748
|
for (let value of result2.records) {
|
|
1618
|
-
let r =
|
|
1749
|
+
let r = object3(value);
|
|
1619
1750
|
if (!recordId(r.id) || acknowledged.includes(r.id) || kind !== "create" && !ids.has(r.id) || kind === "delete" && r.deleted !== !0) throw new Error();
|
|
1620
1751
|
acknowledged.push(r.id), kind !== "delete" && returned.push(record2(r));
|
|
1621
1752
|
}
|
|
@@ -1717,8 +1848,8 @@ var connections = /* @__PURE__ */ createConnections(async (name, operation2, inp
|
|
|
1717
1848
|
var LOCAL_ROUTINE_VALUE_BYTES = 256 * 1024;
|
|
1718
1849
|
|
|
1719
1850
|
var RECORD_WRITE_INPUT_LIMIT = 8 * 1024 * 1024, RoutineRecordWriteError = class extends Error {
|
|
1720
|
-
constructor(
|
|
1721
|
-
super(
|
|
1851
|
+
constructor(message2, effect) {
|
|
1852
|
+
super(message2);
|
|
1722
1853
|
this.effect = effect;
|
|
1723
1854
|
this.name = "RoutineRecordWriteError";
|
|
1724
1855
|
}
|
|
@@ -1769,10 +1900,10 @@ function validateRecordChange(value) {
|
|
|
1769
1900
|
return writes.length && validateRecordWrite({ repository: input.repository, records: writes }), deletes.length && validateRecordDelete({ repository: input.repository, records: deletes }), structuredClone(input);
|
|
1770
1901
|
}
|
|
1771
1902
|
function validateRoutineRecordWrite(value) {
|
|
1772
|
-
let
|
|
1773
|
-
if (!
|
|
1903
|
+
let body = serializable(value);
|
|
1904
|
+
if (!body || typeof body != "object" || Array.isArray(body) || Object.keys(body).sort().join(",") !== "input,requestKey" || typeof body.requestKey != "string" || !body.requestKey.trim() || body.requestKey !== body.requestKey.trim() || body.requestKey.length > 512)
|
|
1774
1905
|
throw new InboxContractError("A stable routine request key is required");
|
|
1775
|
-
return { input: validateRecordChange(
|
|
1906
|
+
return { input: validateRecordChange(body.input), requestKey: body.requestKey };
|
|
1776
1907
|
}
|
|
1777
1908
|
function validCreatePath(value) {
|
|
1778
1909
|
return value === value.trim() && value.endsWith(".md") && !value.startsWith("/") && value.split("/").every((segment) => !!segment && ![".", ".."].includes(segment) && /^[a-zA-Z0-9_.-]+$/.test(segment));
|
|
@@ -1808,10 +1939,10 @@ var operations = {
|
|
|
1808
1939
|
function assert(value) {
|
|
1809
1940
|
if (!value) throw new Error("Invalid Inbox result");
|
|
1810
1941
|
}
|
|
1811
|
-
function
|
|
1942
|
+
function object4(value) {
|
|
1812
1943
|
return assert(value && typeof value == "object" && !Array.isArray(value) && [Object.prototype, null].includes(Object.getPrototypeOf(value)) && Reflect.ownKeys(value).every((key) => {
|
|
1813
|
-
let
|
|
1814
|
-
return !!
|
|
1944
|
+
let descriptor = typeof key == "string" ? Object.getOwnPropertyDescriptor(value, key) : void 0;
|
|
1945
|
+
return !!descriptor?.enumerable && "value" in descriptor;
|
|
1815
1946
|
})), value;
|
|
1816
1947
|
}
|
|
1817
1948
|
function keys3(value, allowed, required = allowed) {
|
|
@@ -1834,41 +1965,41 @@ function optionalDate(value) {
|
|
|
1834
1965
|
}
|
|
1835
1966
|
function array2(value) {
|
|
1836
1967
|
return assert(Array.isArray(value) && Object.getPrototypeOf(value) === Array.prototype && Reflect.ownKeys(value).length === value.length + 1 && value.every((_entry, index) => {
|
|
1837
|
-
let
|
|
1838
|
-
return !!
|
|
1968
|
+
let descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
1969
|
+
return !!descriptor?.enumerable && "value" in descriptor;
|
|
1839
1970
|
})), value;
|
|
1840
1971
|
}
|
|
1841
|
-
function
|
|
1972
|
+
function json(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
1842
1973
|
if (value === null || typeof value == "boolean" || typeof value == "string" || typeof value == "number" && Number.isFinite(value)) return value;
|
|
1843
1974
|
assert(value && typeof value == "object" && !ancestors.has(value)), ancestors.add(value);
|
|
1844
1975
|
try {
|
|
1845
|
-
return Array.isArray(value) ? array2(value).map((entry) =>
|
|
1976
|
+
return Array.isArray(value) ? array2(value).map((entry) => json(entry, ancestors)) : Object.fromEntries(Object.entries(object4(value)).map(([key, entry]) => [key, json(entry, ancestors)]));
|
|
1846
1977
|
} finally {
|
|
1847
1978
|
ancestors.delete(value);
|
|
1848
1979
|
}
|
|
1849
1980
|
}
|
|
1850
1981
|
function recordReference(value) {
|
|
1851
|
-
let record3 =
|
|
1982
|
+
let record3 = object4(value);
|
|
1852
1983
|
return keys3(record3, ["repository", "ref"]), assert(text3(record3.repository) && record3.repository === record3.repository.trim() && /^[a-z0-9][a-z0-9._/-]{0,127}$/.test(record3.repository) && !/\.\.|\/\//.test(record3.repository) && text3(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;
|
|
1853
1984
|
}
|
|
1854
1985
|
function responseDefinition(value) {
|
|
1855
|
-
let definition =
|
|
1986
|
+
let definition = object4(value);
|
|
1856
1987
|
keys3(definition, ["type", "source"]), assert(definition.type === "selection");
|
|
1857
|
-
let source =
|
|
1988
|
+
let source = object4(definition.source);
|
|
1858
1989
|
if (source.type === "authored") {
|
|
1859
1990
|
keys3(source, ["type", "options", "suggestions", "search"], ["type", "options"]);
|
|
1860
1991
|
let options = array2(source.options);
|
|
1861
1992
|
assert(options.length > 0);
|
|
1862
1993
|
let values = options.map((value2) => {
|
|
1863
|
-
let option =
|
|
1994
|
+
let option = object4(value2);
|
|
1864
1995
|
if (keys3(option, ["value", "label", "description", "note"], ["value", "label"]), assert(text3(option.value) && option.value === option.value.trim() && text3(option.label)), "description" in option && assert(text3(option.description)), "note" in option) {
|
|
1865
|
-
let note =
|
|
1996
|
+
let note = object4(option.note);
|
|
1866
1997
|
keys3(note, ["placeholder"]), assert(text3(note.placeholder));
|
|
1867
1998
|
}
|
|
1868
1999
|
return option.value;
|
|
1869
2000
|
});
|
|
1870
2001
|
if (assert(new Set(values).size === values.length), "search" in source || "suggestions" in source) {
|
|
1871
|
-
let search =
|
|
2002
|
+
let search = object4(source.search);
|
|
1872
2003
|
keys3(search, ["triggerLabel", "placeholder", "emptyLabel"]), assert(text3(search.triggerLabel) && text3(search.placeholder) && text3(search.emptyLabel));
|
|
1873
2004
|
let suggestions2 = array2(source.suggestions);
|
|
1874
2005
|
assert(suggestions2.length <= 8 && suggestions2.every((value2) => text3(value2) && values.includes(value2)) && new Set(suggestions2).size === suggestions2.length);
|
|
@@ -1876,16 +2007,16 @@ function responseDefinition(value) {
|
|
|
1876
2007
|
return;
|
|
1877
2008
|
}
|
|
1878
2009
|
assert(source.type === "records"), keys3(source, ["type", "collection", "refPrefix", "where", "display", "suggestions"], ["type", "collection", "display"]);
|
|
1879
|
-
let collection =
|
|
2010
|
+
let collection = object4(source.collection);
|
|
1880
2011
|
keys3(collection, ["repository", "name"]), recordReference({ repository: collection.repository, ref: "records/example" }), assert(text3(collection.name) && /^[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*$/.test(collection.name)), "refPrefix" in source && assert(text3(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));
|
|
1881
|
-
let where =
|
|
2012
|
+
let where = object4(source.where ?? {});
|
|
1882
2013
|
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))));
|
|
1883
|
-
let display =
|
|
2014
|
+
let display = object4(source.display);
|
|
1884
2015
|
keys3(display, ["labelFields"]);
|
|
1885
2016
|
let labels = array2(display.labelFields);
|
|
1886
2017
|
assert(labels.length > 0 && labels.length <= 2 && new Set(labels).size === labels.length && labels.every((value2) => text3(value2) && /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(value2)));
|
|
1887
2018
|
let suggestions = array2(source.suggestions ?? []), refs = suggestions.map((value2) => {
|
|
1888
|
-
let suggestion =
|
|
2019
|
+
let suggestion = object4(value2);
|
|
1889
2020
|
keys3(suggestion, ["record", "reason"], ["record"]);
|
|
1890
2021
|
let record3 = recordReference(suggestion.record);
|
|
1891
2022
|
return assert(record3.repository === collection.repository), "reason" in suggestion && assert(text3(suggestion.reason)), record3.ref;
|
|
@@ -1893,20 +2024,20 @@ function responseDefinition(value) {
|
|
|
1893
2024
|
assert(suggestions.length <= 8 && new Set(refs).size === refs.length);
|
|
1894
2025
|
}
|
|
1895
2026
|
function inboxFile(value) {
|
|
1896
|
-
let file2 =
|
|
2027
|
+
let file2 = object4(value);
|
|
1897
2028
|
keys3(file2, ["id", "name", "mediaType", "size", "sha256", "details"]), assert(id2(file2.id) && text3(file2.name) && !/[\x00-\x1f\x7f/\\]/.test(file2.name) && text3(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));
|
|
1898
|
-
let details =
|
|
2029
|
+
let details = object4(file2.details);
|
|
1899
2030
|
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)));
|
|
1900
2031
|
}
|
|
1901
2032
|
function fields4(value) {
|
|
1902
2033
|
let labels = array2(value).map((value2) => {
|
|
1903
|
-
let field =
|
|
2034
|
+
let field = object4(value2);
|
|
1904
2035
|
return keys3(field, ["label", "value"]), assert(text3(field.label) && text3(field.value)), field.label;
|
|
1905
2036
|
});
|
|
1906
2037
|
assert(new Set(labels).size === labels.length);
|
|
1907
2038
|
}
|
|
1908
2039
|
function block(value) {
|
|
1909
|
-
let entry =
|
|
2040
|
+
let entry = object4(value);
|
|
1910
2041
|
if (entry.kind === "rich-text") {
|
|
1911
2042
|
keys3(entry, ["kind", "markdown"]), assert(text3(entry.markdown));
|
|
1912
2043
|
return;
|
|
@@ -1922,31 +2053,31 @@ function block(value) {
|
|
|
1922
2053
|
["kind", "label", "initiallyExpanded", ...entry.kind === "record" ? ["record", "view"] : entry.kind === "records" ? ["records", "view"] : ["files"]],
|
|
1923
2054
|
["kind", "label", entry.kind === "record" ? "record" : entry.kind === "records" ? "records" : "files"]
|
|
1924
2055
|
), assert(text3(entry.label) && (!("initiallyExpanded" in entry) || typeof entry.initiallyExpanded == "boolean") && (!("view" in entry) || text3(entry.view) && entry.view === entry.view.trim())), entry.kind === "record") {
|
|
1925
|
-
let record3 =
|
|
2056
|
+
let record3 = object4(entry.record);
|
|
1926
2057
|
keys3(record3, ["ref", "title", "fields"]), assert(text3(record3.ref) && record3.ref === record3.ref.trim() && text3(record3.title)), fields4(record3.fields);
|
|
1927
2058
|
return;
|
|
1928
2059
|
}
|
|
1929
2060
|
if (entry.kind === "records") {
|
|
1930
2061
|
let records = array2(entry.records), refs = records.map((value2) => {
|
|
1931
|
-
let record3 =
|
|
2062
|
+
let record3 = object4(value2);
|
|
1932
2063
|
return keys3(record3, ["ref", "title", "description", "facts", "view"], ["ref", "title"]), assert(text3(record3.ref) && record3.ref === record3.ref.trim() && text3(record3.title)), "description" in record3 && assert(text3(record3.description)), "facts" in record3 && fields4(record3.facts), "view" in record3 && assert(text3(record3.view) && record3.view === record3.view.trim()), record3.ref;
|
|
1933
2064
|
});
|
|
1934
2065
|
assert(records.length > 0 && new Set(refs).size === refs.length);
|
|
1935
2066
|
return;
|
|
1936
2067
|
}
|
|
1937
2068
|
let files3 = array2(entry.files);
|
|
1938
|
-
files3.forEach(inboxFile), assert(files3.length > 0 && new Set(files3.map((value2) =>
|
|
2069
|
+
files3.forEach(inboxFile), assert(files3.length > 0 && new Set(files3.map((value2) => object4(value2).id)).size === files3.length);
|
|
1939
2070
|
}
|
|
1940
2071
|
function response(value) {
|
|
1941
|
-
let answer =
|
|
2072
|
+
let answer = object4(value);
|
|
1942
2073
|
return assert(Object.keys(answer).every((key) => ["selection", "note"].includes(key))), typeof answer.selection == "string" ? assert(text3(answer.selection) && answer.selection === answer.selection.trim()) : recordReference(answer.selection), Object.hasOwn(answer, "note") && assert(text3(answer.note)), answer;
|
|
1943
2074
|
}
|
|
1944
|
-
function parseInboxRequest(value
|
|
2075
|
+
function parseInboxRequest(value) {
|
|
1945
2076
|
try {
|
|
1946
|
-
let envelope =
|
|
2077
|
+
let envelope = object4(value);
|
|
1947
2078
|
assert(Object.keys(envelope).sort().join(",") === "input,operation"), assert(typeof envelope.operation == "string" && Object.hasOwn(operations, envelope.operation));
|
|
1948
|
-
let operation2 = envelope.operation, input = { ...
|
|
1949
|
-
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" &&
|
|
2079
|
+
let operation2 = envelope.operation, input = { ...object4(envelope.input) }, required = operations[operation2];
|
|
2080
|
+
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)));
|
|
1950
2081
|
for (let key of ["itemId", "personId", "fileId"]) key in input && assert(id2(input[key]));
|
|
1951
2082
|
return "revision" in input && assert(integer(input.revision)), "beforeNumber" in input && assert(integer(input.beforeNumber)), "questionId" in input && assert(text3(input.questionId) && input.questionId === input.questionId.trim()), "title" in input && assert(text3(input.title)), "lifecycle" in input && assert(input.lifecycle === "open" || input.lifecycle === "closed"), "query" in input && assert(text3(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 };
|
|
1952
2083
|
} catch {
|
|
@@ -1954,80 +2085,84 @@ function parseInboxRequest(value, questionListContext = "local") {
|
|
|
1954
2085
|
}
|
|
1955
2086
|
}
|
|
1956
2087
|
function parseInboxCurrent(value) {
|
|
1957
|
-
let current2 =
|
|
2088
|
+
let current2 = object4(value), workspace = object4(current2.workspace), viewer = object4(current2.viewer);
|
|
1958
2089
|
return assert(id2(workspace.id) && text3(workspace.slug) && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(workspace.slug) && text3(workspace.name) && text3(workspace.locale) && text3(workspace.timezone)), assert(id2(viewer.id) && text3(viewer.name) && text3(viewer.email)), {
|
|
1959
2090
|
workspace: { id: workspace.id, slug: workspace.slug, name: workspace.name, locale: workspace.locale, timezone: workspace.timezone },
|
|
1960
2091
|
viewer: { id: viewer.id, name: viewer.name, email: viewer.email }
|
|
1961
2092
|
};
|
|
1962
2093
|
}
|
|
1963
2094
|
function parseInboxItem(value) {
|
|
1964
|
-
let item =
|
|
1965
|
-
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)) && text3(item.title) && text3(item.description, !0) && text3(item.author) && date(item.publishedAt) && optionalDate(item.seenAt) && optionalDate(item.digestReadAt)), item.outcome !== null && assert(text3(
|
|
1966
|
-
let view =
|
|
1967
|
-
assert(text3(view.id) && text3(view.view) && text3(view.implementation)),
|
|
2095
|
+
let item = object4(json(value));
|
|
2096
|
+
return assert(id2(item.id) && id2(item.workspaceId) && integer(item.number) && integer(item.revision) && integer(item.activityVersion, 0) && ["ask", "digest"].includes(String(item.kind)) && ["open", "closed"].includes(String(item.lifecycle)) && text3(item.title) && text3(item.description, !0) && text3(item.author) && date(item.publishedAt) && optionalDate(item.seenAt) && optionalDate(item.digestReadAt)), item.outcome !== null && assert(text3(object4(item.outcome).outcome)), "canonicalRoutineId" in item && assert(item.canonicalRoutineId === null || isAppRoutineName(item.canonicalRoutineId)), array2(item.body).forEach(block), array2(item.views).forEach((value2) => {
|
|
2097
|
+
let view = object4(value2);
|
|
2098
|
+
assert(text3(view.id) && text3(view.view) && text3(view.implementation)), json(view.input);
|
|
1968
2099
|
}), array2(item.people).forEach((value2) => {
|
|
1969
|
-
let person =
|
|
2100
|
+
let person = object4(value2);
|
|
1970
2101
|
assert(id2(person.id) && text3(person.name));
|
|
1971
2102
|
}), array2(item.questions).forEach((value2) => {
|
|
1972
|
-
let question2 =
|
|
2103
|
+
let question2 = object4(value2);
|
|
1973
2104
|
if (assert(text3(question2.id) && id2(question2.to) && text3(question2.prompt) && (question2.instructions === null || text3(question2.instructions, !0)) && typeof question2.available == "boolean"), responseDefinition(question2.response), assert(array2(question2.allowedResponders).every(id2)), question2.acceptedResponse !== null) {
|
|
1974
|
-
let accepted =
|
|
2105
|
+
let accepted = object4(question2.acceptedResponse);
|
|
1975
2106
|
assert(id2(accepted.id) && id2(accepted.userId) && date(accepted.acceptedAt)), response(accepted.response), accepted.label === null ? delete accepted.label : "label" in accepted && assert(text3(accepted.label)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder));
|
|
1976
2107
|
}
|
|
1977
2108
|
if (question2.execution !== null) {
|
|
1978
|
-
let execution =
|
|
2109
|
+
let execution = object4(question2.execution);
|
|
1979
2110
|
if (assert(id2(execution.id) && ["pending", "running", "completed", "failed"].includes(String(execution.state)) && integer(execution.attempt, 0)), "consequence" in execution) {
|
|
1980
|
-
let consequence =
|
|
2111
|
+
let consequence = object4(execution.consequence);
|
|
1981
2112
|
assert(["pending", "running", "applied", "no-write", "stopped", "partial", "uncertain"].includes(String(consequence.state)) && (consequence.phase === null || ["loading", "invoking", "committing"].includes(String(consequence.phase))) && date(consequence.updatedAt) && typeof consequence.needsReconciliation == "boolean" && (consequence.reason === null || text3(consequence.reason, !0))), array2(consequence.evidence).forEach((value3) => {
|
|
1982
|
-
let receipt =
|
|
2113
|
+
let receipt = object4(value3);
|
|
1983
2114
|
assert(text3(receipt.repository) && text3(receipt.commit) && text3(receipt.diff, !0));
|
|
1984
2115
|
});
|
|
1985
2116
|
}
|
|
1986
2117
|
}
|
|
1987
2118
|
}), array2(item.linkedAsks).forEach((value2) => {
|
|
1988
|
-
let linked =
|
|
2119
|
+
let linked = object4(value2);
|
|
1989
2120
|
if (assert(id2(linked.id)), linked.state === "unavailable") assert(typeof linked.done == "boolean");
|
|
1990
2121
|
else if (assert(["yours", "done", "open", "theirs"].includes(String(linked.state)) && text3(linked.title)), linked.state === "theirs") {
|
|
1991
|
-
let assignee =
|
|
2122
|
+
let assignee = object4(linked.assignee);
|
|
1992
2123
|
assert(id2(assignee.id) && text3(assignee.name));
|
|
1993
2124
|
}
|
|
1994
2125
|
}), array2(item.activity).forEach((value2) => {
|
|
1995
|
-
let
|
|
1996
|
-
assert(integer(
|
|
2126
|
+
let event = object4(value2);
|
|
2127
|
+
assert(integer(event.id) && text3(event.type) && (event.actorId === null || id2(event.actorId)) && (event.questionId === null || text3(event.questionId)) && integer(event.revision) && date(event.createdAt)), object4(event.data);
|
|
1997
2128
|
}), array2(item.work).forEach((value2) => {
|
|
1998
|
-
let work =
|
|
2129
|
+
let work = object4(value2);
|
|
1999
2130
|
assert(id2(work.id) && text3(work.questionId) && text3(work.reason) && optionalDate(work.settledAt));
|
|
2000
2131
|
}), item;
|
|
2001
2132
|
}
|
|
2002
2133
|
function parseAnswerableQuestion(value) {
|
|
2003
|
-
let entry =
|
|
2004
|
-
keys3(
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
assert(
|
|
2009
|
-
let
|
|
2010
|
-
|
|
2011
|
-
let question2 = object3(entry.question);
|
|
2012
|
-
keys3(question2, ["id", "prompt", "instructions", "response"]), assert(text3(question2.id) && question2.id === question2.id.trim() && text3(question2.prompt) && (question2.instructions === null || text3(question2.instructions, !0))), responseDefinition(question2.response);
|
|
2134
|
+
let entry = object4(json(value));
|
|
2135
|
+
keys3(
|
|
2136
|
+
entry,
|
|
2137
|
+
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "recordRefs", "instructions"],
|
|
2138
|
+
["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "recordRefs"]
|
|
2139
|
+
), assert(id2(entry.itemId) && integer(entry.revision) && text3(entry.title) && text3(entry.inboxUrl));
|
|
2140
|
+
let link = new URL(entry.inboxUrl), slug = link.hostname.slice(0, -13);
|
|
2141
|
+
assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && entry.inboxUrl === `https://${slug}.oddington.ai/inbox/${entry.itemId}`), assert(isAppRoutineName(entry.routine) && text3(entry.questionId) && entry.questionId === entry.questionId.trim() && text3(entry.prompt) && (!("instructions" in entry) || text3(entry.instructions, !0)) && typeof entry.answerable == "boolean"), responseDefinition(entry.response);
|
|
2013
2142
|
let refs = array2(entry.recordRefs);
|
|
2014
|
-
return
|
|
2143
|
+
return refs.forEach((value2) => {
|
|
2144
|
+
let ref = object4(value2);
|
|
2145
|
+
keys3(ref, ["repository", "id"]), assert(validRepositoryAlias(ref.repository) && text3(ref.id) && /^[a-zA-Z0-9][a-zA-Z0-9._/-]*$/.test(ref.id) && !ref.id.split("/").some((part) => !part || part === "." || part === ".."));
|
|
2146
|
+
}), assert(new Set(refs.map((value2) => {
|
|
2147
|
+
let ref = object4(value2);
|
|
2148
|
+
return JSON.stringify([ref.repository, ref.id]);
|
|
2149
|
+
})).size === refs.length), entry;
|
|
2015
2150
|
}
|
|
2016
2151
|
function parseInboxAcceptance(value) {
|
|
2017
|
-
let accepted =
|
|
2152
|
+
let accepted = object4(value);
|
|
2018
2153
|
return assert(id2(accepted.responseId) && date(accepted.acceptedAt)), "executionId" in accepted && assert(id2(accepted.executionId)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder)), "label" in accepted && assert(text3(accepted.label)), accepted;
|
|
2019
2154
|
}
|
|
2020
2155
|
function parseInboxResult(operation2, value) {
|
|
2021
2156
|
if (operation2 === "current") return parseInboxCurrent(value);
|
|
2022
2157
|
if (operation2 === "questions.list") {
|
|
2023
|
-
let page =
|
|
2158
|
+
let page = object4(value);
|
|
2024
2159
|
keys3(page, ["questions", "nextBeforeNumber"]);
|
|
2025
2160
|
let questions = array2(page.questions).map(parseAnswerableQuestion);
|
|
2026
2161
|
return assert(page.nextBeforeNumber === null || integer(page.nextBeforeNumber)), { questions, nextBeforeNumber: page.nextBeforeNumber };
|
|
2027
2162
|
}
|
|
2028
2163
|
if (operation2 === "items.read") return parseInboxItem(value);
|
|
2029
2164
|
if (operation2 === "items.list") {
|
|
2030
|
-
let page =
|
|
2165
|
+
let page = object4(value), items = array2(page.items).map(parseInboxItem);
|
|
2031
2166
|
return assert(items.length <= 100 && (page.nextBeforeNumber === null || integer(page.nextBeforeNumber))), { items, nextBeforeNumber: page.nextBeforeNumber };
|
|
2032
2167
|
}
|
|
2033
2168
|
if (operation2 === "items.see") {
|
|
@@ -2035,30 +2170,30 @@ function parseInboxResult(operation2, value) {
|
|
|
2035
2170
|
return;
|
|
2036
2171
|
}
|
|
2037
2172
|
if (operation2 === "items.markDigestRead") {
|
|
2038
|
-
let read2 =
|
|
2173
|
+
let read2 = object4(value);
|
|
2039
2174
|
return assert(integer(read2.activityId) && date(read2.readAt)), read2;
|
|
2040
2175
|
}
|
|
2041
2176
|
if (operation2 === "items.rename" || operation2 === "items.setLifecycle") {
|
|
2042
|
-
let update =
|
|
2177
|
+
let update = object4(value), item = parseInboxItem(update.item);
|
|
2043
2178
|
return assert((update.activityId === null || integer(update.activityId)) && optionalDate(update.changedAt)), { ...update, item };
|
|
2044
2179
|
}
|
|
2045
2180
|
if (operation2 === "items.listRecipientCandidates") {
|
|
2046
2181
|
let candidates = array2(value);
|
|
2047
2182
|
return candidates.forEach((value2) => {
|
|
2048
|
-
let person =
|
|
2183
|
+
let person = object4(value2);
|
|
2049
2184
|
assert(id2(person.id) && text3(person.name) && text3(person.email));
|
|
2050
|
-
}), assert(new Set(candidates.map((value2) =>
|
|
2185
|
+
}), assert(new Set(candidates.map((value2) => object4(value2).id)).size === candidates.length), candidates;
|
|
2051
2186
|
}
|
|
2052
2187
|
if (operation2 === "items.addRecipient") {
|
|
2053
|
-
let addition =
|
|
2188
|
+
let addition = object4(value), item = parseInboxItem(addition.item);
|
|
2054
2189
|
return assert(id2(addition.addedPersonId) && item.people.some((person) => person.id === addition.addedPersonId)), { ...addition, item };
|
|
2055
2190
|
}
|
|
2056
2191
|
if (operation2 === "questions.answer") return parseInboxAcceptance(value);
|
|
2057
2192
|
if (operation2 === "questions.searchRecords") {
|
|
2058
|
-
let result2 =
|
|
2193
|
+
let result2 = object4(value);
|
|
2059
2194
|
assert(text3(result2.recordType) && integer(result2.eligibleCount, 0) && integer(result2.matchCount, 0) && Number(result2.matchCount) <= Number(result2.eligibleCount));
|
|
2060
2195
|
let labeled = (value2) => {
|
|
2061
|
-
let record3 =
|
|
2196
|
+
let record3 = object4(value2);
|
|
2062
2197
|
recordReference({ repository: record3.repository, ref: record3.ref }), assert(text3(record3.label)), "reason" in record3 && assert(text3(record3.reason));
|
|
2063
2198
|
};
|
|
2064
2199
|
return array2(result2.matches).forEach(labeled), array2(result2.suggestions).forEach(labeled), "selected" in result2 && labeled(result2.selected), result2;
|
|
@@ -2066,9 +2201,9 @@ function parseInboxResult(operation2, value) {
|
|
|
2066
2201
|
throw new Error("File content is not a JSON result");
|
|
2067
2202
|
}
|
|
2068
2203
|
|
|
2069
|
-
async function limitedBody(
|
|
2070
|
-
if (!
|
|
2071
|
-
let reader =
|
|
2204
|
+
async function limitedBody(request2, limit, timeoutMs) {
|
|
2205
|
+
if (!request2.body) return new Uint8Array();
|
|
2206
|
+
let reader = request2.body.getReader(), expired = !1, timer = timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
2072
2207
|
expired = !0, reader.cancel().catch(() => {
|
|
2073
2208
|
});
|
|
2074
2209
|
}, timeoutMs), chunks = [], length = 0;
|
|
@@ -2213,7 +2348,7 @@ function appContext(origin, active2) {
|
|
|
2213
2348
|
}
|
|
2214
2349
|
}, cancel = () => {
|
|
2215
2350
|
controller.abort(), access.abort(), clearTimeout(expiry), clearTimeout(startup), clearTimeout(renewalTimer), clearInterval(monitor), globalThis.removeEventListener?.("storage", storageChanged);
|
|
2216
|
-
for (let
|
|
2351
|
+
for (let event of ["pageshow", "focus", "visibilitychange"]) globalThis.removeEventListener?.(event, wake);
|
|
2217
2352
|
}, invalidate = () => {
|
|
2218
2353
|
denied = !0, cancel();
|
|
2219
2354
|
try {
|
|
@@ -2226,7 +2361,7 @@ function appContext(origin, active2) {
|
|
|
2226
2361
|
} catch {
|
|
2227
2362
|
return !1;
|
|
2228
2363
|
}
|
|
2229
|
-
}, sameSession = (value) => !binding || ["appId", "memberId", "workspace", "sessionId"].every((key) => value[key] === binding[key]),
|
|
2364
|
+
}, sameSession = (value) => !binding || ["appId", "memberId", "workspace", "sessionId"].every((key) => value[key] === binding[key]), bounded2 = (value) => validBinding(value) && value.expiresAt > Date.now() && value.expiresAt <= Date.now() + 6e5 && sameSession(value), readPair = (candidate) => {
|
|
2230
2365
|
let value = JSON.parse(candidate ?? "null");
|
|
2231
2366
|
if (!validPair(value) || value.context.expiresAt > Date.now() + 6e5 || !sameSession(value.context)) throw new Error();
|
|
2232
2367
|
return value;
|
|
@@ -2261,7 +2396,7 @@ function appContext(origin, active2) {
|
|
|
2261
2396
|
if (response2.status >= 500) throw new AppRenewalUnavailable();
|
|
2262
2397
|
if (!response2.ok) throw new Error();
|
|
2263
2398
|
let value = await appResponse(response2, 4096, signal);
|
|
2264
|
-
if (!alive() || !
|
|
2399
|
+
if (!alive() || !bounded2(value)) throw new Error();
|
|
2265
2400
|
return value;
|
|
2266
2401
|
}
|
|
2267
2402
|
function install(value, candidate, raw) {
|
|
@@ -2333,7 +2468,7 @@ function appContext(origin, active2) {
|
|
|
2333
2468
|
return;
|
|
2334
2469
|
}
|
|
2335
2470
|
if (!response2.ok) throw new Error();
|
|
2336
|
-
if (!alive() || !validPair(value) || !
|
|
2471
|
+
if (!alive() || !validPair(value) || !bounded2(value.context) || (/* @__PURE__ */ new Set([value.credential, value.renewalCredential, pair.credential, pair.renewalCredential])).size !== 4) throw new Error();
|
|
2337
2472
|
if (stored() !== previous) {
|
|
2338
2473
|
await synchronize(requestController.signal);
|
|
2339
2474
|
return;
|
|
@@ -2382,7 +2517,7 @@ function appContext(origin, active2) {
|
|
|
2382
2517
|
alive() && resolve().catch(() => {
|
|
2383
2518
|
});
|
|
2384
2519
|
};
|
|
2385
|
-
for (let
|
|
2520
|
+
for (let event of ["pageshow", "focus", "visibilitychange"]) globalThis.addEventListener?.(event, wake);
|
|
2386
2521
|
let dispose = () => {
|
|
2387
2522
|
disposed = !0, cancel();
|
|
2388
2523
|
};
|
|
@@ -2497,13 +2632,13 @@ function hostFailure(error, context2) {
|
|
|
2497
2632
|
return !context2.isCurrent() || context2.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") : unavailable2();
|
|
2498
2633
|
}
|
|
2499
2634
|
async function send2(operation2, input) {
|
|
2500
|
-
let envelope =
|
|
2635
|
+
let envelope = parseInboxRequest({ operation: operation2, input }), context2;
|
|
2501
2636
|
try {
|
|
2502
2637
|
context2 = await resolveAppContext();
|
|
2503
2638
|
} catch {
|
|
2504
2639
|
throw stale();
|
|
2505
2640
|
}
|
|
2506
|
-
if (
|
|
2641
|
+
if (context2.kind === "local") {
|
|
2507
2642
|
if (!isAppQuestionOperation(operation2)) throw new InboxOperationError(403, "access_denied");
|
|
2508
2643
|
let check2 = () => {
|
|
2509
2644
|
if (!context2.isCurrent() || context2.signal.aborted || context2.expiresAt <= Date.now()) throw stale();
|
|
@@ -2524,16 +2659,18 @@ async function send2(operation2, input) {
|
|
|
2524
2659
|
}
|
|
2525
2660
|
if (context2.endpoint !== `https://${context2.workspace}.oddington.ai` || ["auth", "www", "api", "os"].includes(context2.workspace)) throw stale();
|
|
2526
2661
|
let host;
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2662
|
+
if (!isAppQuestionOperation(operation2)) {
|
|
2663
|
+
try {
|
|
2664
|
+
host = await resolveHostedInboxContext(context2);
|
|
2665
|
+
} catch (error) {
|
|
2666
|
+
throw hostFailure(error, context2);
|
|
2667
|
+
}
|
|
2668
|
+
if (!host) throw unavailable2();
|
|
2531
2669
|
}
|
|
2532
|
-
if (!host) throw unavailable2();
|
|
2533
2670
|
let check = () => {
|
|
2534
|
-
if (!context2.isCurrent() || !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
|
|
2671
|
+
if (!context2.isCurrent() || host && !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
|
|
2535
2672
|
};
|
|
2536
|
-
if (check(), host
|
|
2673
|
+
if (check(), host?.context.kind === "focused")
|
|
2537
2674
|
throw new InboxOperationError(403, "access_denied");
|
|
2538
2675
|
try {
|
|
2539
2676
|
let response2 = await fetch(`${context2.endpoint}/api/inbox`, {
|
|
@@ -2567,7 +2704,7 @@ async function send2(operation2, input) {
|
|
|
2567
2704
|
} finally {
|
|
2568
2705
|
reader?.releaseLock();
|
|
2569
2706
|
}
|
|
2570
|
-
},
|
|
2707
|
+
}, body = new ReadableStream({
|
|
2571
2708
|
async pull(controller) {
|
|
2572
2709
|
try {
|
|
2573
2710
|
check(), reader ??= source.getReader();
|
|
@@ -2585,7 +2722,7 @@ async function send2(operation2, input) {
|
|
|
2585
2722
|
},
|
|
2586
2723
|
cancel
|
|
2587
2724
|
}, { highWaterMark: 0 });
|
|
2588
|
-
return new Response(
|
|
2725
|
+
return new Response(body, { status: response2.status, headers: response2.headers });
|
|
2589
2726
|
}
|
|
2590
2727
|
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
2591
2728
|
if (check(), !bytes) throw unavailable2();
|
|
@@ -2641,33 +2778,24 @@ var inbox = {
|
|
|
2641
2778
|
},
|
|
2642
2779
|
questions: {
|
|
2643
2780
|
async list(input) {
|
|
2644
|
-
let supplied =
|
|
2645
|
-
if (
|
|
2646
|
-
let routines =
|
|
2781
|
+
let supplied = parseInboxRequest({ operation: "questions.list", input }).input;
|
|
2782
|
+
if (Object.hasOwn(supplied, "beforeNumber")) throw new InboxOperationError(400, "invalid_input");
|
|
2783
|
+
let routines = Object.freeze(supplied.routines), questions = [], beforeNumber, initial;
|
|
2647
2784
|
try {
|
|
2648
2785
|
initial = await resolveAppContext();
|
|
2649
2786
|
} catch {
|
|
2650
2787
|
throw stale();
|
|
2651
2788
|
}
|
|
2652
|
-
if (initial.kind === "local" ? input !== void 0 : routines === void 0)
|
|
2653
|
-
throw new InboxOperationError(400, "invalid_input");
|
|
2654
|
-
let host;
|
|
2655
|
-
try {
|
|
2656
|
-
host = initial.kind !== "local" && await resolveHostedInboxContext(initial);
|
|
2657
|
-
} catch (error) {
|
|
2658
|
-
throw hostFailure(error, initial);
|
|
2659
|
-
}
|
|
2660
|
-
if (initial.kind !== "local" && !host) throw unavailable2();
|
|
2661
2789
|
let check = () => {
|
|
2662
|
-
if (!initial.isCurrent() ||
|
|
2790
|
+
if (!initial.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
|
|
2663
2791
|
};
|
|
2664
2792
|
do {
|
|
2665
2793
|
check();
|
|
2666
2794
|
let page = await send2("questions.list", {
|
|
2667
|
-
|
|
2795
|
+
routines,
|
|
2668
2796
|
...beforeNumber === void 0 ? {} : { beforeNumber }
|
|
2669
2797
|
});
|
|
2670
|
-
if (check(), page.questions.some((question2) => question2.
|
|
2798
|
+
if (check(), page.questions.some((question2) => question2.inboxUrl !== `https://${initial.workspace}.oddington.ai/inbox/${question2.itemId}` || !routines.includes(question2.routine)) || beforeNumber !== void 0 && page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber) throw unavailable2();
|
|
2671
2799
|
if (questions.push(...page.questions), page.nextBeforeNumber === null) return questions;
|
|
2672
2800
|
beforeNumber = page.nextBeforeNumber;
|
|
2673
2801
|
} while (!0);
|
|
@@ -2704,8 +2832,8 @@ function init({ auth: input }) {
|
|
|
2704
2832
|
url.protocol === "https:" && !url.port && !url.username && !url.password && !url.search && !url.hash && url.pathname === "/" && /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(slug) && slug !== "auth" && (endpoint = url.origin, workspace = slug);
|
|
2705
2833
|
} catch {
|
|
2706
2834
|
}
|
|
2707
|
-
let active2 = !0, revision = 0, person, token, binding = {},
|
|
2708
|
-
if (
|
|
2835
|
+
let active2 = !0, revision = 0, person, token, binding = {}, local2 = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, uninstall = installMemberContext(async () => {
|
|
2836
|
+
if (local2) return local2.resolve();
|
|
2709
2837
|
if (!active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
|
|
2710
2838
|
let started = revision, { data: { session }, error } = await auth2.getSession();
|
|
2711
2839
|
if (!active2 || globalThis.location.origin !== endpoint || started !== revision || error || !session || person !== void 0 && person !== session.user.id)
|
|
@@ -2725,12 +2853,12 @@ function init({ auth: input }) {
|
|
|
2725
2853
|
binding
|
|
2726
2854
|
};
|
|
2727
2855
|
}), dispose = () => {
|
|
2728
|
-
active2 && (active2 = !1,
|
|
2856
|
+
active2 && (active2 = !1, local2?.dispose(), revision++, subscription?.unsubscribe(), stopDisposal?.(), uninstall(), installedDispose === dispose && (installedDispose = void 0));
|
|
2729
2857
|
};
|
|
2730
|
-
installedDispose = dispose, stopDisposal = registered?.onDispose(dispose), active2 && (subscription = auth2.onAuthStateChange((
|
|
2858
|
+
installedDispose = dispose, stopDisposal = registered?.onDispose(dispose), active2 && (subscription = auth2.onAuthStateChange((event, session) => {
|
|
2731
2859
|
let next = session?.user.id ?? null;
|
|
2732
|
-
(
|
|
2733
|
-
}).data.subscription,
|
|
2860
|
+
(event === "SIGNED_OUT" || person !== void 0 && next !== person || registered && person !== void 0 && event === "SIGNED_IN" && token !== session?.access_token) && (revision++, local2?.invalidate()), person = next, token = session?.access_token;
|
|
2861
|
+
}).data.subscription, local2?.start());
|
|
2734
2862
|
}
|
|
2735
2863
|
var os = { init };
|
|
2736
2864
|
|
|
@@ -2780,19 +2908,19 @@ function createBrowserAuth(runtime) {
|
|
|
2780
2908
|
} catch {
|
|
2781
2909
|
}
|
|
2782
2910
|
}
|
|
2783
|
-
function notify(c,
|
|
2911
|
+
function notify(c, event) {
|
|
2784
2912
|
for (let listener of c.sessions)
|
|
2785
2913
|
try {
|
|
2786
|
-
listener(
|
|
2914
|
+
listener(event, event === "SIGNED_OUT" ? null : c.session);
|
|
2787
2915
|
} catch {
|
|
2788
2916
|
}
|
|
2789
2917
|
}
|
|
2790
2918
|
function expire(c) {
|
|
2791
2919
|
!c.active || !c.session && c.state.status === "expired" || (c.revision++, c.timer && clearTimeout(c.timer), c.session = null, publish(c, { status: "expired" }), notify(c, "SIGNED_OUT"));
|
|
2792
2920
|
}
|
|
2793
|
-
function accept(c,
|
|
2794
|
-
if (!c.active ||
|
|
2795
|
-
let replaced = c.session?.user?.id !== session?.user?.id ||
|
|
2921
|
+
function accept(c, event, session) {
|
|
2922
|
+
if (!c.active || event === "INITIAL_SESSION" && c.state.status !== "initializing" || event === "TOKEN_REFRESHED" && !c.session && c.state.status !== "initializing") return;
|
|
2923
|
+
let replaced = c.session?.user?.id !== session?.user?.id || event === "SIGNED_OUT" || !!(event === "SIGNED_IN" && c.session && session?.access_token !== c.session.access_token);
|
|
2796
2924
|
replaced && c.revision++, c.timer && clearTimeout(c.timer);
|
|
2797
2925
|
let pending = c.state.pending;
|
|
2798
2926
|
if (!session) {
|
|
@@ -2805,7 +2933,7 @@ function createBrowserAuth(runtime) {
|
|
|
2805
2933
|
}
|
|
2806
2934
|
c.session = session;
|
|
2807
2935
|
let email = typeof session.user.email == "string" ? session.user.email.trim() : "", metadata = session.user.user_metadata, name = ["name", "full_name", "first_name"].map((key) => metadata?.[key]).find((value) => typeof value == "string" && value.trim())?.trim() || email, account = !replaced && c.state.account?.email === email && c.state.account.displayName === name ? c.state.account : Object.freeze({ email, displayName: name });
|
|
2808
|
-
publish(c, { status: "signed_in", account, ...pending ? { pending } : {} }), notify(c,
|
|
2936
|
+
publish(c, { status: "signed_in", account, ...pending ? { pending } : {} }), notify(c, event);
|
|
2809
2937
|
let checkExpiry = () => {
|
|
2810
2938
|
if (!c.active || !c.session) return;
|
|
2811
2939
|
let remaining = c.session.expires_at * 1e3 - Date.now();
|
|
@@ -2845,8 +2973,8 @@ function createBrowserAuth(runtime) {
|
|
|
2845
2973
|
c.provider.dispose();
|
|
2846
2974
|
return;
|
|
2847
2975
|
}
|
|
2848
|
-
let subscription = c.provider.onAuthStateChange((
|
|
2849
|
-
c.state.status === "initializing" && c.state.pending === "sign_out" || accept(c,
|
|
2976
|
+
let subscription = c.provider.onAuthStateChange((event, session) => {
|
|
2977
|
+
c.state.status === "initializing" && c.state.pending === "sign_out" || accept(c, event, session);
|
|
2850
2978
|
}).data.subscription;
|
|
2851
2979
|
c.unsubscribe = () => subscription.unsubscribe();
|
|
2852
2980
|
let started = c.revision, { data: data3, error } = await c.provider.getSession();
|
|
@@ -3008,7 +3136,7 @@ function createBrowserAuth(runtime) {
|
|
|
3008
3136
|
if (!active2)
|
|
3009
3137
|
return callback("SIGNED_OUT", null), { data: { subscription: { unsubscribe() {
|
|
3010
3138
|
} } } };
|
|
3011
|
-
let listener = (
|
|
3139
|
+
let listener = (event, session) => callback(event, session);
|
|
3012
3140
|
return coordinator.sessions.add(listener), sessionObservers.add(listener), callback("INITIAL_SESSION", coordinator.session), { data: { subscription: { unsubscribe() {
|
|
3013
3141
|
coordinator.sessions.delete(listener), sessionObservers.delete(listener);
|
|
3014
3142
|
} } } };
|
|
@@ -3081,19 +3209,19 @@ async function provider(configuration, guard) {
|
|
|
3081
3209
|
}
|
|
3082
3210
|
},
|
|
3083
3211
|
fetch: Object.assign(async (input, init2) => {
|
|
3084
|
-
let revision = guard.revision(),
|
|
3085
|
-
throw
|
|
3212
|
+
let revision = guard.revision(), request2 = String(input).startsWith(`${configuration.providerUrl}/auth/v1/oauth/authorizations/`) ? authorizationRequest : void 0, rejectStale = () => {
|
|
3213
|
+
throw request2 && (request2.rejected = !0), new BrowserAuthError("stale");
|
|
3086
3214
|
};
|
|
3087
|
-
|
|
3088
|
-
let response2 = await fetch(input, { ...init2, redirect: "error" }),
|
|
3089
|
-
(!guard.current(revision) ||
|
|
3215
|
+
request2 && (!request2.current() || !guard.canAuthorize(new Headers(init2?.headers).get("authorization")?.replace(/^Bearer /, "") ?? "")) && rejectStale();
|
|
3216
|
+
let response2 = await fetch(input, { ...init2, redirect: "error" }), body = await response2.arrayBuffer();
|
|
3217
|
+
(!guard.current(revision) || request2 && !request2.current()) && rejectStale();
|
|
3090
3218
|
let result2 = new Response(
|
|
3091
|
-
[204, 205, 304].includes(response2.status) ? null :
|
|
3219
|
+
[204, 205, 304].includes(response2.status) ? null : body,
|
|
3092
3220
|
{ status: response2.status, statusText: response2.statusText, headers: response2.headers }
|
|
3093
|
-
),
|
|
3221
|
+
), json2 = result2.json.bind(result2);
|
|
3094
3222
|
return result2.json = async () => {
|
|
3095
|
-
let value = await
|
|
3096
|
-
return (!guard.current(revision) ||
|
|
3223
|
+
let value = await json2();
|
|
3224
|
+
return (!guard.current(revision) || request2 && !request2.current()) && rejectStale(), value && typeof value.access_token == "string" && provenance.set(value.access_token, revision), value;
|
|
3097
3225
|
}, result2;
|
|
3098
3226
|
}, { preconnect: fetch.preconnect })
|
|
3099
3227
|
});
|
|
@@ -3102,15 +3230,15 @@ async function provider(configuration, guard) {
|
|
|
3102
3230
|
authorizationQueue = new Promise((resolve) => {
|
|
3103
3231
|
release = resolve;
|
|
3104
3232
|
}), await previous;
|
|
3105
|
-
let
|
|
3106
|
-
authorizationRequest =
|
|
3233
|
+
let request2 = { current: current2, rejected: !1 };
|
|
3234
|
+
authorizationRequest = request2;
|
|
3107
3235
|
try {
|
|
3108
3236
|
if (!current2()) throw new BrowserAuthError("stale");
|
|
3109
3237
|
let result2 = await (kind === "get" ? client.oauth.getAuthorizationDetails(id3) : kind === "approve" ? client.oauth.approveAuthorization(id3, { skipBrowserRedirect: !0 }) : client.oauth.denyAuthorization(id3, { skipBrowserRedirect: !0 }));
|
|
3110
|
-
if (
|
|
3238
|
+
if (request2.rejected || !current2()) throw new BrowserAuthError("stale");
|
|
3111
3239
|
return result2;
|
|
3112
3240
|
} catch (error) {
|
|
3113
|
-
throw
|
|
3241
|
+
throw request2.rejected || !current2() ? new BrowserAuthError("stale") : error;
|
|
3114
3242
|
} finally {
|
|
3115
3243
|
authorizationRequest = void 0, release();
|
|
3116
3244
|
}
|
|
@@ -3122,9 +3250,9 @@ async function provider(configuration, guard) {
|
|
|
3122
3250
|
deny: (id3, current2) => authorization("deny", id3, current2)
|
|
3123
3251
|
},
|
|
3124
3252
|
getSession: () => client.getSession(),
|
|
3125
|
-
onAuthStateChange: (callback) => client.onAuthStateChange((
|
|
3253
|
+
onAuthStateChange: (callback) => client.onAuthStateChange((event, session) => {
|
|
3126
3254
|
let revision = session ? provenance.get(session.access_token) : void 0;
|
|
3127
|
-
revision !== void 0 && !guard.current(revision) || (callback(
|
|
3255
|
+
revision !== void 0 && !guard.current(revision) || (callback(event, session), session && provenance.delete(session.access_token));
|
|
3128
3256
|
}),
|
|
3129
3257
|
signInWithOtp: (input) => client.signInWithOtp(input),
|
|
3130
3258
|
verifyOtp: (input) => client.verifyOtp(input),
|
|
@@ -3143,188 +3271,166 @@ async function provider(configuration, guard) {
|
|
|
3143
3271
|
}
|
|
3144
3272
|
var auth = /* @__PURE__ */ createBrowserAuth({ provider, failure: (reason) => new BrowserAuthError(reason) });
|
|
3145
3273
|
|
|
3146
|
-
|
|
3274
|
+
function routineRunHandle(operations2) {
|
|
3275
|
+
return Object.freeze({
|
|
3276
|
+
current: operations2.current,
|
|
3277
|
+
step: operations2.step,
|
|
3278
|
+
...operations2.publish ? { publish: operations2.publish } : {},
|
|
3279
|
+
async *watch() {
|
|
3280
|
+
let previous;
|
|
3281
|
+
for (; ; ) {
|
|
3282
|
+
let state = await operations2.current(), encoded = JSON.stringify(state);
|
|
3283
|
+
if (encoded !== previous && (previous = encoded, yield state), state.status === "succeeded" || state.status === "failed") return;
|
|
3284
|
+
await (operations2.wait?.() ?? new Promise((resolve) => setTimeout(resolve, 100)));
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
});
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
var identifier = /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/, uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}(?![\s\S])/i, SUMMARY_BYTES = 17 * 1024 * 1024, AppRoutineError = class extends Error {
|
|
3147
3291
|
constructor(reason) {
|
|
3148
3292
|
super(reason);
|
|
3149
3293
|
this.reason = reason;
|
|
3150
3294
|
this.name = "AppRoutineError";
|
|
3151
3295
|
}
|
|
3152
3296
|
reason;
|
|
3153
|
-
}
|
|
3154
|
-
function fail3(reason) {
|
|
3297
|
+
}, fail3 = (reason) => {
|
|
3155
3298
|
throw new AppRoutineError(reason);
|
|
3156
|
-
}
|
|
3157
|
-
function object4(value) {
|
|
3158
|
-
return !!value && typeof value == "object" && !Array.isArray(value);
|
|
3159
|
-
}
|
|
3160
|
-
function keys4(value, expected) {
|
|
3161
|
-
return Object.keys(value).sort().join(",") === expected;
|
|
3162
|
-
}
|
|
3299
|
+
};
|
|
3163
3300
|
function current(context2) {
|
|
3164
3301
|
(!context2.isCurrent() || context2.signal.aborted) && fail3("authority_unavailable");
|
|
3165
3302
|
}
|
|
3166
|
-
|
|
3303
|
+
function appDescriptors() {
|
|
3304
|
+
return globalThis[/* @__PURE__ */ Symbol.for("oddington.app.descriptor")]?.routines ?? [];
|
|
3305
|
+
}
|
|
3306
|
+
async function local() {
|
|
3307
|
+
let context2 = await resolveAppContext().catch(() => fail3("authority_unavailable"));
|
|
3308
|
+
return context2.kind !== "local" ? fail3("execution_unavailable") : (current(context2), context2);
|
|
3309
|
+
}
|
|
3310
|
+
async function request(key, suffix, init2, maximum = SUMMARY_BYTES, retained) {
|
|
3311
|
+
(!identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable");
|
|
3312
|
+
let context2 = retained ?? await local();
|
|
3313
|
+
current(context2);
|
|
3167
3314
|
try {
|
|
3168
|
-
let value = await appResponse(response2, maximum, context2.signal);
|
|
3169
|
-
|
|
3315
|
+
let response2 = await context2.requestRoutine(key, suffix, init2), value = await appResponse(response2, maximum, context2.signal);
|
|
3316
|
+
if (current(context2), !response2.ok) {
|
|
3317
|
+
let reason = value?.error;
|
|
3318
|
+
reason === "authority_unavailable" && (context2.invalidate(), fail3(reason)), (reason === "invalid_input" || reason === "execution_unavailable") && fail3(reason), fail3("execution_unavailable");
|
|
3319
|
+
}
|
|
3320
|
+
return value;
|
|
3170
3321
|
} catch (error) {
|
|
3171
|
-
if (current(context2), error instanceof
|
|
3172
|
-
|
|
3322
|
+
if (current(context2), error instanceof AppRoutineError) throw error;
|
|
3323
|
+
fail3("execution_unavailable");
|
|
3173
3324
|
}
|
|
3174
3325
|
}
|
|
3175
|
-
function
|
|
3176
|
-
|
|
3326
|
+
function summary(value, key, id3) {
|
|
3327
|
+
let run = value;
|
|
3328
|
+
return (!only(run, "id,routine,placement,status,createdAt,startedAt,finishedAt,steps,result,failure,publication") || typeof run.id != "string" || !uuid.test(run.id) || id3 !== void 0 && run.id !== id3 || run.routine !== key || run.placement !== "local" || !["queued", "running", "succeeded", "failed"].includes(run.status) || !timestamp(run.createdAt) || !optionalTimes(run) || !Array.isArray(run.steps) || run.steps.length > 64 || run.steps.some((step) => !only(step, "id,title,status,startedAt,finishedAt,summary,detailAvailable") || typeof step.detailAvailable != "boolean" || !validStep(step)) || new Set(run.steps.map((step) => step.id)).size !== run.steps.length || Object.hasOwn(run, "result") && (run.status !== "succeeded" || !bounded(run.result)) || run.failure !== void 0 && (run.status !== "failed" || !only(run.failure, "message") || !message(run.failure.message)) || run.publication !== void 0 && (run.status !== "succeeded" || !validPublication(run.publication))) && fail3("execution_unavailable"), run;
|
|
3177
3329
|
}
|
|
3178
|
-
function
|
|
3179
|
-
return
|
|
3330
|
+
function only(value, allowed) {
|
|
3331
|
+
return !!value && typeof value == "object" && !Array.isArray(value) && Object.keys(value).every((key) => allowed.split(",").includes(key));
|
|
3180
3332
|
}
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
if (
|
|
3199
|
-
|
|
3200
|
-
if (
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
},
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
}
|
|
3214
|
-
|
|
3215
|
-
return Object.freeze({
|
|
3216
|
-
async *events(...args) {
|
|
3217
|
-
args.length && fail3("invalid_input");
|
|
3218
|
-
let cursor = 0, terminal = !1, delay = 100, retainedBytes = 0, seen = [];
|
|
3219
|
-
for (; !terminal; ) {
|
|
3220
|
-
current(context2);
|
|
3221
|
-
let response2;
|
|
3222
|
-
try {
|
|
3223
|
-
response2 = await context2.requestRoutine(run.key, `runs/${run.runId}/events?after=${cursor}`);
|
|
3224
|
-
} catch {
|
|
3225
|
-
current(context2), await pause(context2, delay), delay = Math.min(delay * 2, 2e3);
|
|
3226
|
-
continue;
|
|
3227
|
-
}
|
|
3228
|
-
if (response2.status >= 500) {
|
|
3229
|
-
await response2.body?.cancel(), await pause(context2, delay), delay = Math.min(delay * 2, 2e3);
|
|
3230
|
-
continue;
|
|
3231
|
-
}
|
|
3232
|
-
let value;
|
|
3233
|
-
try {
|
|
3234
|
-
value = await body(context2, response2, 80 * 1024);
|
|
3235
|
-
} catch (error) {
|
|
3236
|
-
if (!(error instanceof AppResponseReadError)) throw error;
|
|
3237
|
-
await pause(context2, delay), delay = Math.min(delay * 2, 2e3);
|
|
3238
|
-
continue;
|
|
3239
|
-
}
|
|
3240
|
-
(!object4(value) || !keys4(value, "after,events,terminal") || !Array.isArray(value.events) || value.events.length > 256 || typeof value.terminal != "boolean" || !Number.isSafeInteger(value.after)) && fail3("execution_unavailable");
|
|
3241
|
-
let delivery = [];
|
|
3242
|
-
for (let raw of value.events) {
|
|
3243
|
-
let publicEvent = event(raw, run, steps), encoded = JSON.stringify(raw), sequence = raw.sequence;
|
|
3244
|
-
if (sequence <= cursor) {
|
|
3245
|
-
seen[sequence - 1] !== encoded && fail3("execution_unavailable");
|
|
3246
|
-
continue;
|
|
3247
|
-
}
|
|
3248
|
-
(terminal || sequence !== cursor + 1 || sequence > 256 || (cursor === 0 ? publicEvent.type !== "started" : publicEvent.type === "started")) && fail3("execution_unavailable"), retainedBytes += new TextEncoder().encode(encoded).byteLength, retainedBytes > 1024 * 1024 && fail3("execution_unavailable"), seen.push(encoded), cursor = sequence, terminal = publicEvent.type === "finished", delivery.push(publicEvent);
|
|
3249
|
-
}
|
|
3250
|
-
(value.after !== cursor || value.terminal !== terminal) && fail3("execution_unavailable");
|
|
3251
|
-
for (let item of delivery)
|
|
3252
|
-
current(context2), yield item;
|
|
3253
|
-
delay = 100, terminal || await pause(context2, delivery.length ? 100 : 250);
|
|
3254
|
-
}
|
|
3333
|
+
var timestamp = (value) => typeof value == "string" && value.length <= 32 && Number.isFinite(Date.parse(value)), message = (value) => typeof value == "string" && value.length > 0 && value.length <= 512, bounded = (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength <= 256 * 1024;
|
|
3334
|
+
function optionalTimes(value) {
|
|
3335
|
+
return (value.startedAt === void 0 || timestamp(value.startedAt)) && (value.finishedAt === void 0 || timestamp(value.finishedAt));
|
|
3336
|
+
}
|
|
3337
|
+
function validStep(step) {
|
|
3338
|
+
return typeof step.id == "string" && identifier.test(step.id) && typeof step.title == "string" && step.title.length > 0 && step.title.length <= 256 && ["pending", "running", "completed", "failed", "skipped"].includes(step.status) && optionalTimes(step) && (!Object.hasOwn(step, "summary") || bounded(step.summary)) && (!Object.hasOwn(step, "data") || bounded(step.data));
|
|
3339
|
+
}
|
|
3340
|
+
function validPublication(value) {
|
|
3341
|
+
return value && only(value, value.state === "failed" ? "state,message" : "state") && (["not_needed", "ready", "published"].includes(value.state) || value.state === "failed" && message(value.message));
|
|
3342
|
+
}
|
|
3343
|
+
function jsonInput(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
3344
|
+
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return;
|
|
3345
|
+
if (!value || typeof value != "object" || ancestors.has(value)) return fail3("invalid_input");
|
|
3346
|
+
let array3 = Array.isArray(value), keys4 = Reflect.ownKeys(value);
|
|
3347
|
+
if (!array3 && ![Object.prototype, null].includes(Object.getPrototypeOf(value)) || array3 && (keys4.length !== value.length + 1 || !Array.from({ length: value.length }, (_, index) => Object.hasOwn(value, index)).every(Boolean))) return fail3("invalid_input");
|
|
3348
|
+
ancestors.add(value);
|
|
3349
|
+
for (let key of keys4) {
|
|
3350
|
+
if (array3 && key === "length") continue;
|
|
3351
|
+
let descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
3352
|
+
if (typeof key != "string" || !descriptor.enumerable || !Object.hasOwn(descriptor, "value")) return fail3("invalid_input");
|
|
3353
|
+
jsonInput(descriptor.value, ancestors);
|
|
3354
|
+
}
|
|
3355
|
+
ancestors.delete(value);
|
|
3356
|
+
}
|
|
3357
|
+
function structure(value) {
|
|
3358
|
+
return JSON.stringify(value, (_key, item) => item && typeof item == "object" && !Array.isArray(item) ? Object.fromEntries(Object.keys(item).sort().map((key) => [key, item[key]])) : item);
|
|
3359
|
+
}
|
|
3360
|
+
function handle(key, id3, context2) {
|
|
3361
|
+
return (typeof id3 != "string" || !uuid.test(id3)) && fail3("invalid_input"), routineRunHandle({
|
|
3362
|
+
current: async () => summary(await request(key, `runs/${id3}`, void 0, SUMMARY_BYTES, context2), key, id3),
|
|
3363
|
+
async step(step) {
|
|
3364
|
+
(typeof step != "string" || !identifier.test(step)) && fail3("invalid_input");
|
|
3365
|
+
let value = await request(key, `runs/${id3}/steps/${step}`, void 0, 514 * 1024, context2);
|
|
3366
|
+
return (!only(value, "id,title,status,startedAt,finishedAt,summary,data") || value.id !== step || !validStep(value)) && fail3("execution_unavailable"), value;
|
|
3255
3367
|
},
|
|
3256
|
-
async
|
|
3257
|
-
|
|
3258
|
-
try {
|
|
3259
|
-
let value = await body(context2, await context2.requestRoutine(run.key, `runs/${run.runId}/cancel`, { method: "POST" }), 1024);
|
|
3260
|
-
(!object4(value) || !keys4(value, "cancelled") || value.cancelled !== !0) && fail3("execution_unavailable");
|
|
3261
|
-
} catch (error) {
|
|
3262
|
-
if (current(context2), error instanceof AppRoutineError) throw error;
|
|
3263
|
-
fail3("execution_unavailable");
|
|
3264
|
-
}
|
|
3368
|
+
async publish() {
|
|
3369
|
+
return summary(await request(key, `runs/${id3}/publish`, { method: "POST" }, SUMMARY_BYTES, context2), key, id3);
|
|
3265
3370
|
}
|
|
3266
3371
|
});
|
|
3267
3372
|
}
|
|
3268
|
-
async function
|
|
3269
|
-
let
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
let runs = value2.runs.map((run) => descriptor(run, key));
|
|
3277
|
-
return (new Set(runs.map((run) => run.runId)).size !== runs.length || new Set(runs.map((run) => run.routine)).size > 1) && fail3("execution_unavailable"), runs.map((run) => handle(resolved, run));
|
|
3278
|
-
}
|
|
3279
|
-
let available = await body(context2, await context2.requestAvailability(key), 16 * 1024);
|
|
3280
|
-
object4(available) && keys4(available, "available,reason") && available.available === !1 && isReason(available.reason) && fail3(available.reason), (!object4(available) || !keys4(available, "available,steps") || available.available !== !0 || !Array.isArray(available.steps) || available.steps.length < 1 || available.steps.length > 64 || !available.steps.every((step) => typeof step == "string" && identifier.test(step)) || new Set(available.steps).size !== available.steps.length) && fail3("execution_unavailable");
|
|
3281
|
-
let steps = [...available.steps], encoded;
|
|
3282
|
-
try {
|
|
3283
|
-
encoded = JSON.stringify(input), (encoded === void 0 || new TextEncoder().encode(encoded).byteLength > 16 * 1024) && fail3("invalid_input");
|
|
3284
|
-
} catch {
|
|
3285
|
-
fail3("invalid_input");
|
|
3286
|
-
}
|
|
3287
|
-
let value = await body(context2, await context2.requestRoutine(key, "runs", {
|
|
3288
|
-
method: "POST",
|
|
3289
|
-
body: `{"input":${encoded}}`
|
|
3290
|
-
}), 16 * 1024);
|
|
3291
|
-
return handle(context2, descriptor(value, key), steps);
|
|
3292
|
-
} catch (error) {
|
|
3293
|
-
if (context2 && current(context2), error instanceof AppRoutineError) throw error;
|
|
3294
|
-
return fail3(context2 ? "execution_unavailable" : "authority_unavailable");
|
|
3295
|
-
}
|
|
3296
|
-
}
|
|
3297
|
-
|
|
3298
|
-
var authorityUnavailable = () => ({ available: !1, reason: "authority_unavailable" }), MAX_RESPONSE_BYTES = 16 * 1024;
|
|
3299
|
-
async function availability(key) {
|
|
3373
|
+
async function describeAppRoutine(key) {
|
|
3374
|
+
let descriptor = appDescriptors().find((item) => item.id === key);
|
|
3375
|
+
if (!descriptor) return fail3("authority_unavailable");
|
|
3376
|
+
let unavailable3 = () => ({
|
|
3377
|
+
...structuredClone(descriptor),
|
|
3378
|
+
connections: descriptor.connections.map((connection) => ({ ...connection, available: !1 })),
|
|
3379
|
+
readiness: { state: "unavailable", reason: "capability_unavailable", message: "Routine capability unavailable." }
|
|
3380
|
+
});
|
|
3300
3381
|
try {
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
if (context2.kind !== "local") return { available: !1, reason: "execution_unavailable" };
|
|
3304
|
-
let response2 = await context2.requestAvailability(key);
|
|
3305
|
-
if (!response2.ok || response2.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "application/json")
|
|
3306
|
-
return authorityUnavailable();
|
|
3307
|
-
let value = await appResponse(response2, MAX_RESPONSE_BYTES, context2.signal);
|
|
3308
|
-
if (!context2.isCurrent() || !value || typeof value != "object" || Array.isArray(value)) return authorityUnavailable();
|
|
3309
|
-
let result2 = value;
|
|
3310
|
-
return result2.available === !1 && Object.keys(result2).sort().join(",") === "available,reason" && (result2.reason === "not_enabled" || result2.reason === "authority_unavailable" || result2.reason === "execution_unavailable") ? { available: !1, reason: result2.reason } : result2.available !== !0 || Object.keys(result2).sort().join(",") !== "available,steps" || !Array.isArray(result2.steps) || result2.steps.length < 1 || result2.steps.length > 64 || !result2.steps.every((step) => typeof step == "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/.test(step)) || new Set(result2.steps).size !== result2.steps.length ? authorityUnavailable() : { available: !0, steps: [...result2.steps] };
|
|
3382
|
+
let value = await request(key, "describe", void 0, 1048576);
|
|
3383
|
+
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;
|
|
3311
3384
|
} catch {
|
|
3312
|
-
return
|
|
3385
|
+
return unavailable3();
|
|
3313
3386
|
}
|
|
3314
3387
|
}
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
}
|
|
3388
|
+
function appRoutineBinding(key) {
|
|
3389
|
+
return Object.freeze({
|
|
3390
|
+
describe: () => describeAppRoutine(key),
|
|
3391
|
+
async run(...args) {
|
|
3392
|
+
args.length > 1 && fail3("invalid_input");
|
|
3393
|
+
let encoded;
|
|
3394
|
+
try {
|
|
3395
|
+
if (args[0] === void 0) encoded = "{}";
|
|
3396
|
+
else {
|
|
3397
|
+
jsonInput(args[0]);
|
|
3398
|
+
let input = JSON.stringify(args[0]);
|
|
3399
|
+
new TextEncoder().encode(input).byteLength > 256 * 1024 && fail3("invalid_input"), encoded = `{"input":${input}}`;
|
|
3400
|
+
}
|
|
3401
|
+
} catch {
|
|
3402
|
+
return fail3("invalid_input");
|
|
3403
|
+
}
|
|
3404
|
+
let context2 = await local(), run = summary(await request(key, "runs", { method: "POST", body: encoded }, SUMMARY_BYTES, context2), key);
|
|
3405
|
+
return handle(key, run.id, context2);
|
|
3406
|
+
},
|
|
3407
|
+
runs: Object.freeze({
|
|
3408
|
+
async list() {
|
|
3409
|
+
let value = await request(key, "runs", void 0, 20 * SUMMARY_BYTES);
|
|
3410
|
+
if (!Array.isArray(value) || value.length > 20) return fail3("execution_unavailable");
|
|
3411
|
+
let runs = value.map((run) => summary(run, key));
|
|
3412
|
+
return new Set(runs.map((run) => run.id)).size !== runs.length && fail3("execution_unavailable"), runs;
|
|
3413
|
+
},
|
|
3414
|
+
async get(id3) {
|
|
3415
|
+
let run = handle(key, id3, await local());
|
|
3416
|
+
return await run.current(), run;
|
|
3417
|
+
}
|
|
3418
|
+
})
|
|
3419
|
+
});
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3422
|
+
var app = Object.freeze({
|
|
3423
|
+
listRoutines: () => Promise.all(appDescriptors().map(({ id: id3 }) => describeAppRoutine(id3))),
|
|
3424
|
+
routines: new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
3425
|
+
get(_target, key) {
|
|
3426
|
+
if (!(typeof key != "string" || !appDescriptors().some((item) => item.id === key)))
|
|
3427
|
+
return appRoutineBinding(key);
|
|
3428
|
+
},
|
|
3429
|
+
set: () => !1,
|
|
3430
|
+
defineProperty: () => !1,
|
|
3431
|
+
deleteProperty: () => !1
|
|
3432
|
+
})
|
|
3433
|
+
});
|
|
3328
3434
|
|
|
3329
3435
|
var LIMIT2 = 16 * 1024, context;
|
|
3330
3436
|
var appRun = {
|
|
@@ -3354,10 +3460,10 @@ function routineDataEnvelope(command) {
|
|
|
3354
3460
|
}
|
|
3355
3461
|
|
|
3356
3462
|
function routinePublicationClient2(options = {}) {
|
|
3357
|
-
let environment = {}, installed2 = routineTransport(),
|
|
3463
|
+
let environment = {}, installed2 = routineTransport(), local2 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.ODDINGTON_ROUTINE_WORKSPACE, capability = options.capability ?? environment.ODDINGTON_ROUTINE_RUN;
|
|
3358
3464
|
if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
|
|
3359
3465
|
throw new Error("A workspace and valid optional routine capability are required");
|
|
3360
|
-
let workingRoot = options.workingRoot ?? environment.ODDINGTON_INBOX_WORKING_ROOT ?? void 0, headers = capability ? { "x-oddington-run": capability } : {},
|
|
3466
|
+
let workingRoot = options.workingRoot ?? environment.ODDINGTON_INBOX_WORKING_ROOT ?? void 0, headers = capability ? { "x-oddington-run": capability } : {}, request2 = options.request ?? (capability ? async (path, init2) => {
|
|
3361
3467
|
if (path === "/api/data") return fetch(`https://${workspace}.oddington.ai/api/data`, { ...init2, redirect: "error" });
|
|
3362
3468
|
let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
|
|
3363
3469
|
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")
|
|
@@ -3366,16 +3472,16 @@ function routinePublicationClient2(options = {}) {
|
|
|
3366
3472
|
} : async () => {
|
|
3367
3473
|
throw new Error("Member publication requires a host-supplied request");
|
|
3368
3474
|
});
|
|
3369
|
-
async function send3(operation2,
|
|
3370
|
-
if (
|
|
3371
|
-
let writing = operation2 === "records/update", reading = operation2 === "records/read", response2 = await
|
|
3475
|
+
async function send3(operation2, body) {
|
|
3476
|
+
if (local2) return await local2(operation2, body);
|
|
3477
|
+
let writing = operation2 === "records/update", reading = operation2 === "records/read", response2 = await request2(writing || reading ? "/api/data" : `/api/inbox/${operation2}`, {
|
|
3372
3478
|
method: "POST",
|
|
3373
3479
|
headers: {
|
|
3374
3480
|
"content-type": "application/json",
|
|
3375
3481
|
...headers,
|
|
3376
3482
|
...writing || reading ? { "x-oddington-workspace": workspace, "x-oddington-captured-records": "1" } : {}
|
|
3377
3483
|
},
|
|
3378
|
-
body: JSON.stringify(writing ? routineDataEnvelope(validateRoutineRecordWrite(
|
|
3484
|
+
body: JSON.stringify(writing ? routineDataEnvelope(validateRoutineRecordWrite(body)) : reading ? { operation: "records.select", request: validateRecordRead(body) } : body)
|
|
3379
3485
|
}), result2 = await response2.json();
|
|
3380
3486
|
if (!response2.ok && operation2 === "records/update")
|
|
3381
3487
|
throw new RoutineRecordWriteError(result2.error ?? "Could not confirm routine preparation", result2.effect ?? "uncertain");
|
|
@@ -3383,11 +3489,11 @@ function routinePublicationClient2(options = {}) {
|
|
|
3383
3489
|
return result2;
|
|
3384
3490
|
}
|
|
3385
3491
|
let transport = {
|
|
3386
|
-
async publish(
|
|
3387
|
-
return await send3("publish",
|
|
3492
|
+
async publish(body) {
|
|
3493
|
+
return await send3("publish", body);
|
|
3388
3494
|
},
|
|
3389
|
-
async resolve(
|
|
3390
|
-
await send3("resolve",
|
|
3495
|
+
async resolve(body) {
|
|
3496
|
+
await send3("resolve", body);
|
|
3391
3497
|
}
|
|
3392
3498
|
};
|
|
3393
3499
|
async function readRecords(input) {
|
|
@@ -3414,12 +3520,12 @@ function routinePublicationClient2(options = {}) {
|
|
|
3414
3520
|
files: {
|
|
3415
3521
|
async add(value) {
|
|
3416
3522
|
let input = validateFileAddOptions(value);
|
|
3417
|
-
if (
|
|
3523
|
+
if (local2) return validateInboxFile(await local2("files/add", input));
|
|
3418
3524
|
throw workingRoot ? new Error("Inbox file reads require a Node working root") : new Error("Inbox file reads require a working root");
|
|
3419
3525
|
}
|
|
3420
3526
|
},
|
|
3421
|
-
async check(
|
|
3422
|
-
await send3("check", { requestKey:
|
|
3527
|
+
async check(body) {
|
|
3528
|
+
await send3("check", { requestKey: body.requestKey, item: validatePublication(body.item) });
|
|
3423
3529
|
}
|
|
3424
3530
|
};
|
|
3425
3531
|
}
|