@oddington/sdk 0.1.37 → 0.1.39
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 +217 -127
- package/dist/browser.js +457 -173
- package/dist/index.js +9 -4
- package/dist/types/packages/sdk/src/public.d.ts +25 -20
- package/dist/types/packages/sdk/src/routine-definition-types.d.ts +2 -2
- package/dist/types/shared/app-routine-contract.d.ts +1 -1
- package/dist/types/shared/data-contract.d.ts +80 -8
- package/dist/types/shared/data-validation-message.d.ts +23 -0
- package/dist/types/shared/files-contract.d.ts +3 -0
- package/dist/types/shared/inbox-contract.d.ts +11 -0
- package/dist/types/shared/inbox-member-contract.d.ts +1 -1
- package/dist/types/shared/inbox-member-types.d.ts +0 -6
- package/dist/types/shared/routine-ai-contract.d.ts +5 -3
- package/package.json +1 -1
- package/dist/types/shared/delimited-text.d.ts +0 -2
- package/dist/types/shared/inbox-files.d.ts +0 -12
package/dist/browser.js
CHANGED
|
@@ -8,7 +8,8 @@ var fileValidationReasons = {
|
|
|
8
8
|
invalid_request_key: "File request key must contain 1\u2013256 characters, with no surrounding whitespace or control characters.",
|
|
9
9
|
invalid_enrichment_name: "Enrichment name must be a safe filename and cannot be original or original.*.",
|
|
10
10
|
invalid_replacement: "Enrichment replacement must be a SHA-256 hash of 64 lowercase hexadecimal characters.",
|
|
11
|
-
invalid_bytes: "File content must contain byte chunks."
|
|
11
|
+
invalid_bytes: "File content must contain byte chunks.",
|
|
12
|
+
original_changed: "The selected file changed while OS was reading it. Wait for it to finish saving, then try again."
|
|
12
13
|
};
|
|
13
14
|
function parseFileErrorDetail(value) {
|
|
14
15
|
if (!value || typeof value != "object" || Array.isArray(value)) return;
|
|
@@ -29,10 +30,10 @@ function parseFileErrorDetail(value) {
|
|
|
29
30
|
function fileErrorExplanation(detail) {
|
|
30
31
|
return detail.reason === "size_mismatch" ? `File byte count mismatch: expected ${detail.expectedBytes} bytes; received ${detail.receivedAtLeast ? "at least " : ""}${detail.receivedBytes} bytes.` : detail.reason === "size_limit" ? `File size exceeds the ${detail.limitBytes}-byte limit; received ${detail.receivedAtLeast ? "at least " : ""}${detail.receivedBytes} bytes.` : fileValidationReasons[detail.reason];
|
|
31
32
|
}
|
|
32
|
-
var FileOperationError = class extends Error {
|
|
33
|
+
var FILE_CAPACITY_MESSAGE = "OS reached its file-processing limit. Try again in a moment. If this keeps happening with a large batch, split the files into smaller groups.", FILE_INTEGRITY_MESSAGE = "OS could not verify this File against its saved record. Try again. If the problem continues, add the original file again.", FileOperationError = class extends Error {
|
|
33
34
|
constructor(code, status, retryable = !1, detail) {
|
|
34
35
|
let safe = ["invalid_input", "request_too_large"].includes(code) ? parseFileErrorDetail(detail) : void 0;
|
|
35
|
-
super(safe ? `${code}: ${fileErrorExplanation(safe)}` : code);
|
|
36
|
+
super(safe ? `${code}: ${fileErrorExplanation(safe)}` : code === "capacity" ? FILE_CAPACITY_MESSAGE : code === "integrity" ? FILE_INTEGRITY_MESSAGE : code);
|
|
36
37
|
this.code = code;
|
|
37
38
|
this.status = status;
|
|
38
39
|
this.retryable = retryable;
|
|
@@ -185,7 +186,11 @@ function parseAppRoutineContract(value) {
|
|
|
185
186
|
};
|
|
186
187
|
}
|
|
187
188
|
case "array":
|
|
188
|
-
return !fields(value2, ["type", "items", "maxItems"]) || !Number.isSafeInteger(value2.maxItems) || value2.maxItems < 1
|
|
189
|
+
return !fields(value2, ["type", "items"], ["maxItems"]) || owns(value2, "maxItems") && (!Number.isSafeInteger(value2.maxItems) || value2.maxItems < 1) ? invalidContract() : {
|
|
190
|
+
type: "array",
|
|
191
|
+
items: schema2(value2.items, depth + 1),
|
|
192
|
+
...owns(value2, "maxItems") ? { maxItems: value2.maxItems } : {}
|
|
193
|
+
};
|
|
189
194
|
case "boolean":
|
|
190
195
|
return fields(value2, ["type"]) ? { type: value2.type } : invalidContract();
|
|
191
196
|
case "file":
|
|
@@ -238,7 +243,8 @@ function validateRoutineSchemaValue(schema2, value, rejected) {
|
|
|
238
243
|
return;
|
|
239
244
|
case "array":
|
|
240
245
|
if (!denseArray(value2)) return fail4("wrong_type");
|
|
241
|
-
if (
|
|
246
|
+
if (schema3.maxItems !== void 0 && value2.length > schema3.maxItems)
|
|
247
|
+
return fail4("out_of_bounds", { constraint: "maxItems", limit: schema3.maxItems });
|
|
242
248
|
value2.forEach((child, index) => check(schema3.items, child, `${path}[${index}]`));
|
|
243
249
|
return;
|
|
244
250
|
case "boolean":
|
|
@@ -266,7 +272,22 @@ var InboxContractError = class extends Error {
|
|
|
266
272
|
constructor(message2) {
|
|
267
273
|
super(message2), this.name = "InboxContractError";
|
|
268
274
|
}
|
|
275
|
+
}, INBOX_PUBLICATION_ITEM_BYTES = 1024 * 1024, INBOX_PUBLICATION_REQUEST_BYTES = INBOX_PUBLICATION_ITEM_BYTES + 4096, publicationAdvice = "Trim the content, or attach long reports, data, and supporting materials as files instead. Then try again.", INBOX_PUBLICATION_TOO_LARGE = `Your Inbox item failed to publish. Its content exceeds the 1 MB limit. ${publicationAdvice}`, InboxPublicationSizeError = class extends InboxContractError {
|
|
276
|
+
constructor(kind, bytes) {
|
|
277
|
+
let label = kind === "ask" ? "Ask" : "Digest", size = Math.ceil(bytes / INBOX_PUBLICATION_ITEM_BYTES * 100) / 100;
|
|
278
|
+
super(`Your ${label} failed to publish. Its content is ${size} MB, which exceeds the 1 MB limit. ${publicationAdvice}`);
|
|
279
|
+
this.kind = kind;
|
|
280
|
+
this.bytes = bytes;
|
|
281
|
+
this.name = "InboxPublicationSizeError";
|
|
282
|
+
}
|
|
283
|
+
kind;
|
|
284
|
+
bytes;
|
|
269
285
|
};
|
|
286
|
+
function enforcePublicationSize(value) {
|
|
287
|
+
let bytes = new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
288
|
+
if (bytes > INBOX_PUBLICATION_ITEM_BYTES) throw new InboxPublicationSizeError(value.kind, bytes);
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
270
291
|
function fail(message2) {
|
|
271
292
|
throw new InboxContractError(message2);
|
|
272
293
|
}
|
|
@@ -607,7 +628,7 @@ function createInboxPublisher(transport) {
|
|
|
607
628
|
keys(source2, ["title", "description", "recipients", "views", "body", "questions", "notifyImmediately", "tags", "recordRefs"], "ask");
|
|
608
629
|
let result2 = await transport.publish({
|
|
609
630
|
requestKey: publicationRequestKey(options),
|
|
610
|
-
item: validatePublication({ ...source2, kind: "ask" })
|
|
631
|
+
item: enforcePublicationSize(validatePublication({ ...source2, kind: "ask" }))
|
|
611
632
|
});
|
|
612
633
|
return id(result2.id, "published ask ID"), (!("revision" in result2) || !Number.isSafeInteger(result2.revision) || result2.revision !== 1) && fail("Initial ask publication must return revision 1"), { id: result2.id, revision: result2.revision };
|
|
613
634
|
},
|
|
@@ -616,7 +637,7 @@ function createInboxPublisher(transport) {
|
|
|
616
637
|
keys(source2, ["title", "description", "recipients", "views", "body", "notifyImmediately"], "digest");
|
|
617
638
|
let result2 = await transport.publish({
|
|
618
639
|
requestKey: publicationRequestKey(options),
|
|
619
|
-
item: validatePublication({ ...source2, kind: "digest" })
|
|
640
|
+
item: enforcePublicationSize(validatePublication({ ...source2, kind: "digest" }))
|
|
620
641
|
});
|
|
621
642
|
return { id: id(result2.id, "published digest ID") };
|
|
622
643
|
},
|
|
@@ -769,12 +790,12 @@ function routineAIOutputMessage(issue) {
|
|
|
769
790
|
}
|
|
770
791
|
|
|
771
792
|
var ROUTINE_AI_VALUE_BYTES = 256 * 1024, ROUTINE_AI_RESULT_BYTES = 6 * ROUTINE_AI_VALUE_BYTES + 1024, ROUTINE_AI_EVIDENCE_BYTES = 4 * 1024;
|
|
772
|
-
var
|
|
793
|
+
var AIError = class extends Error {
|
|
773
794
|
constructor(code, options = {}) {
|
|
774
795
|
let detail = code === "invalid_output" ? parseRoutineAIOutputIssue(options.detail) : void 0;
|
|
775
796
|
super(detail ? routineAIOutputMessage(detail) : code);
|
|
776
797
|
this.code = code;
|
|
777
|
-
this.name = "
|
|
798
|
+
this.name = "AIError", detail && (this.detail = Object.freeze(detail)), code === "invalid_output" && typeof options.text == "string" && new TextEncoder().encode(options.text).byteLength <= ROUTINE_AI_VALUE_BYTES && Object.defineProperty(this, "text", { value: options.text });
|
|
778
799
|
}
|
|
779
800
|
code;
|
|
780
801
|
detail;
|
|
@@ -783,10 +804,10 @@ function capture(value, invalid9, oversized, limit = ROUTINE_AI_VALUE_BYTES) {
|
|
|
783
804
|
try {
|
|
784
805
|
assertRoutineJson(value);
|
|
785
806
|
let encoded = JSON.stringify(value);
|
|
786
|
-
if (new TextEncoder().encode(encoded).byteLength > limit) throw new
|
|
807
|
+
if (new TextEncoder().encode(encoded).byteLength > limit) throw new AIError(oversized);
|
|
787
808
|
return freezeRoutineMetadata(JSON.parse(encoded));
|
|
788
809
|
} catch (error) {
|
|
789
|
-
throw error instanceof
|
|
810
|
+
throw error instanceof AIError ? error : new AIError(invalid9);
|
|
790
811
|
}
|
|
791
812
|
}
|
|
792
813
|
function parseRoutineAIRequest(value) {
|
|
@@ -798,7 +819,7 @@ function parseRoutineAIRequest(value) {
|
|
|
798
819
|
let schema2 = parseAppRoutineContract({ routine: "ai", input: v.schema, steps: [{ id: "generate" }] }).input;
|
|
799
820
|
return freezeRoutineMetadata({ kind: v.kind, instructions: v.instructions, input, schema: schema2 });
|
|
800
821
|
} catch {
|
|
801
|
-
throw new
|
|
822
|
+
throw new AIError("invalid_input");
|
|
802
823
|
}
|
|
803
824
|
}
|
|
804
825
|
function parseRoutineAIResult(request2, value) {
|
|
@@ -815,7 +836,7 @@ function parseRoutineAIResult(request2, value) {
|
|
|
815
836
|
}
|
|
816
837
|
if (!Object.hasOwn(v, "object")) throw new Error();
|
|
817
838
|
} catch (error) {
|
|
818
|
-
throw error instanceof
|
|
839
|
+
throw error instanceof AIError ? error : new AIError("invalid_output", { detail: { reason: "invalid_response" } });
|
|
819
840
|
}
|
|
820
841
|
return validateObject(request2.schema, v.object), freezeRoutineMetadata({ object: v.object });
|
|
821
842
|
}
|
|
@@ -826,20 +847,20 @@ function validateObject(schema2, object5, text5) {
|
|
|
826
847
|
detail = issue;
|
|
827
848
|
});
|
|
828
849
|
} catch {
|
|
829
|
-
throw new
|
|
850
|
+
throw new AIError("invalid_output", { ...text5 === void 0 ? {} : { text: text5 }, detail });
|
|
830
851
|
}
|
|
831
852
|
}
|
|
832
853
|
function acceptText(request2, text5) {
|
|
833
|
-
if (new TextEncoder().encode(text5).byteLength > ROUTINE_AI_VALUE_BYTES) throw new
|
|
854
|
+
if (new TextEncoder().encode(text5).byteLength > ROUTINE_AI_VALUE_BYTES) throw new AIError("output_too_large");
|
|
834
855
|
if (request2.kind === "generateText") {
|
|
835
|
-
if (!text5.trim()) throw new
|
|
856
|
+
if (!text5.trim()) throw new AIError("invalid_output", { text: text5, detail: { reason: "empty_text" } });
|
|
836
857
|
return freezeRoutineMetadata({ text: text5 });
|
|
837
858
|
}
|
|
838
|
-
let object5;
|
|
859
|
+
let object5, trimmed = text5.trim(), fenced = /^(`{3,}|~{3,})(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n\1[ \t]*$/i.exec(trimmed);
|
|
839
860
|
try {
|
|
840
|
-
object5 = JSON.parse(text5);
|
|
861
|
+
object5 = JSON.parse(fenced ? fenced[2] : text5);
|
|
841
862
|
} catch {
|
|
842
|
-
throw new
|
|
863
|
+
throw new AIError("invalid_output", { text: text5, detail: { reason: "invalid_json" } });
|
|
843
864
|
}
|
|
844
865
|
return validateObject(request2.schema, object5, text5), capture({ object: object5 }, "invalid_output", "output_too_large");
|
|
845
866
|
}
|
|
@@ -849,10 +870,10 @@ var LIMIT = 256 * 1024, invalid3 = () => {
|
|
|
849
870
|
}, invalidContract3 = () => {
|
|
850
871
|
throw new AppRoutineContractError("invalid_contract");
|
|
851
872
|
}, empty = { type: "object", properties: {}, required: [], additionalProperties: !1 };
|
|
852
|
-
function captureJson(value) {
|
|
873
|
+
function captureJson(value, maximum = LIMIT) {
|
|
853
874
|
assertRoutineJson(value);
|
|
854
875
|
let encoded = JSON.stringify(value);
|
|
855
|
-
return new TextEncoder().encode(encoded).byteLength >
|
|
876
|
+
return maximum !== null && new TextEncoder().encode(encoded).byteLength > maximum ? invalid3() : freezeRoutineMetadata(JSON.parse(encoded));
|
|
856
877
|
}
|
|
857
878
|
function capture2(schema2, value) {
|
|
858
879
|
let captured = captureJson(value);
|
|
@@ -887,8 +908,8 @@ var schema = {
|
|
|
887
908
|
object(properties) {
|
|
888
909
|
return declaration({ type: "object", properties: Object.fromEntries(Object.entries(properties).map(([key, value]) => [key, nestedSchema(value)])), required: Object.keys(properties), additionalProperties: !1 });
|
|
889
910
|
},
|
|
890
|
-
array(items, options) {
|
|
891
|
-
return declaration({ type: "array", items: nestedSchema(items),
|
|
911
|
+
array(items, options = {}) {
|
|
912
|
+
return assertRoutineFields(options, ["maxItems"]), declaration({ type: "array", items: nestedSchema(items), ...options });
|
|
892
913
|
},
|
|
893
914
|
string(options = {}) {
|
|
894
915
|
return declaration({ type: "string", ...options });
|
|
@@ -970,8 +991,8 @@ function captureRoutineInput(definition, input) {
|
|
|
970
991
|
async function executeRoutineDefinition(definition, input, runtime) {
|
|
971
992
|
let captured = captureRoutineInput(definition, input), { contract, steps, run } = definitions.get(definition), active2 = !0, accepting = !0, broken = !1, work = Promise.resolve(), aiWork = /* @__PURE__ */ new Set(), generate = (kind, value) => {
|
|
972
993
|
let operation2 = (async () => {
|
|
973
|
-
if (!active2 || broken || contract.access.ai !== !0) throw new
|
|
974
|
-
if (!runtime.ai) throw new
|
|
994
|
+
if (!active2 || broken || contract.access.ai !== !0) throw new AIError("access_denied");
|
|
995
|
+
if (!runtime.ai) throw new AIError("capability_unavailable");
|
|
975
996
|
let request2;
|
|
976
997
|
try {
|
|
977
998
|
assertRoutineFields(value, kind === "generateObject" ? ["instructions", "input", "schema"] : ["instructions", "input"]), request2 = parseRoutineAIRequest({
|
|
@@ -981,10 +1002,10 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
981
1002
|
...kind === "generateObject" ? { schema: schemaMetadata(value.schema).schema } : {}
|
|
982
1003
|
});
|
|
983
1004
|
} catch (error) {
|
|
984
|
-
throw error instanceof
|
|
1005
|
+
throw error instanceof AIError ? error : new AIError("invalid_input");
|
|
985
1006
|
}
|
|
986
1007
|
let result3 = await runtime.ai[kind](request2);
|
|
987
|
-
if (!active2 || broken) throw new
|
|
1008
|
+
if (!active2 || broken) throw new AIError("access_denied");
|
|
988
1009
|
return parseRoutineAIResult(request2, result3);
|
|
989
1010
|
})();
|
|
990
1011
|
return aiWork.add(operation2), operation2.then(() => aiWork.delete(operation2), () => aiWork.delete(operation2)), operation2;
|
|
@@ -1020,7 +1041,7 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
1020
1041
|
let saved;
|
|
1021
1042
|
try {
|
|
1022
1043
|
if (!active2 || !accepting || broken || !Object.hasOwn(steps, id3) || called.has(id3) || input2.length > 1) return invalid3();
|
|
1023
|
-
input2.length && (saved = captureJson(input2[0])), called.add(id3);
|
|
1044
|
+
input2.length && (saved = captureJson(input2[0], null)), called.add(id3);
|
|
1024
1045
|
} catch (error) {
|
|
1025
1046
|
return broken = !0, Promise.reject(error);
|
|
1026
1047
|
}
|
|
@@ -1056,26 +1077,171 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
1056
1077
|
if (result2 !== void 0) return invalid3();
|
|
1057
1078
|
}
|
|
1058
1079
|
|
|
1080
|
+
var RECORD_READ_INPUT_LIMIT = 1024 * 1024, RECORD_CAPTURE_OUTPUT_LIMIT = 25 * 1024 * 1024;
|
|
1081
|
+
function validRecordRef(value) {
|
|
1082
|
+
return typeof value == "string" && value.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)+$/.test(value);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
var fieldProblems = ["unknown", "missing", "invalid", "source_schema"], reasons = {
|
|
1086
|
+
unknown: "unknown_field",
|
|
1087
|
+
missing: "missing_field",
|
|
1088
|
+
invalid: "invalid_value",
|
|
1089
|
+
source_schema: "source_schema_mismatch"
|
|
1090
|
+
}, expectationKinds = {
|
|
1091
|
+
string: "a string",
|
|
1092
|
+
integer: "a safe integer",
|
|
1093
|
+
number: "a finite number",
|
|
1094
|
+
boolean: "a boolean",
|
|
1095
|
+
date: "a date in YYYY-MM-DD format",
|
|
1096
|
+
const: "the constant declared in the schema",
|
|
1097
|
+
enum: "one of the choices declared in the schema",
|
|
1098
|
+
link: "a link to an existing record of an allowed type",
|
|
1099
|
+
object: "an object matching the schema",
|
|
1100
|
+
map: "a map matching the schema"
|
|
1101
|
+
};
|
|
1102
|
+
function expectationText(expected) {
|
|
1103
|
+
if (!Object.hasOwn(expectationKinds, expected.type) || typeof expected.many != "boolean" || typeof expected.nullable != "boolean" || expected.decimalPlaces !== void 0 && (expected.type !== "number" || !Number.isInteger(expected.decimalPlaces) || expected.decimalPlaces < 0 || expected.decimalPlaces > 6) || expected.format !== void 0 && (expected.type !== "date" || expected.format !== "month")) return;
|
|
1104
|
+
let scalar = expected.type === "number" && expected.decimalPlaces !== void 0 ? `a finite number with at most ${expected.decimalPlaces} decimal places` : expected.type === "date" && expected.format === "month" ? "a date in YYYY-MM format" : expectationKinds[expected.type];
|
|
1105
|
+
return `${expected.many ? "Expected a list. Each item must be" : "Expected"} ${scalar}.${expected.nullable ? " The field may also be null." : ""}`;
|
|
1106
|
+
}
|
|
1107
|
+
function parseExpectation(text5) {
|
|
1108
|
+
if (!text5) return;
|
|
1109
|
+
let parts = /^Expected (a list\. Each item must be )?(.+?)\.( The field may also be null\.)?$/.exec(text5);
|
|
1110
|
+
if (!parts) return;
|
|
1111
|
+
let number = /^a finite number with at most ([0-6]) decimal places$/.exec(parts[2]), month = parts[2] === "a date in YYYY-MM format", kind = number ? "number" : month ? "date" : Object.keys(expectationKinds).find((kind2) => expectationKinds[kind2] === parts[2]);
|
|
1112
|
+
if (!kind) return;
|
|
1113
|
+
let expected = {
|
|
1114
|
+
type: kind,
|
|
1115
|
+
many: !!parts[1],
|
|
1116
|
+
nullable: !!parts[3],
|
|
1117
|
+
...number ? { decimalPlaces: Number(number[1]) } : {},
|
|
1118
|
+
...month ? { format: "month" } : {}
|
|
1119
|
+
};
|
|
1120
|
+
return expectationText(expected) === text5 ? expected : void 0;
|
|
1121
|
+
}
|
|
1122
|
+
function parseDataValidationDetail(value) {
|
|
1123
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return;
|
|
1124
|
+
let v = value;
|
|
1125
|
+
if (Object.keys(v).some((key) => !["record", "field", "reason", "schemaFile", "expected"].includes(key)) || typeof v.record != "string" || typeof v.field != "string") return;
|
|
1126
|
+
let problem = fieldProblems.find((problem2) => reasons[problem2] === v.reason);
|
|
1127
|
+
if (!problem || v.schemaFile !== void 0 && typeof v.schemaFile != "string") return;
|
|
1128
|
+
let expected;
|
|
1129
|
+
if (Object.hasOwn(v, "expected")) {
|
|
1130
|
+
if (!v.expected || typeof v.expected != "object" || Array.isArray(v.expected)) return;
|
|
1131
|
+
let e = v.expected;
|
|
1132
|
+
if (Object.keys(e).some((key) => !["type", "many", "nullable", "decimalPlaces", "format"].includes(key)) || (expected = { ...e }, !expectationText(expected))) return;
|
|
1133
|
+
}
|
|
1134
|
+
if (!(problem === "unknown" && expected || problem === "source_schema" && (v.field !== "media_type" || expected?.type !== "string" || expected.many || expected.nullable)) && recordFieldMessage(
|
|
1135
|
+
v.record,
|
|
1136
|
+
v.field,
|
|
1137
|
+
problem,
|
|
1138
|
+
v.schemaFile,
|
|
1139
|
+
expected
|
|
1140
|
+
))
|
|
1141
|
+
return {
|
|
1142
|
+
record: v.record,
|
|
1143
|
+
field: v.field,
|
|
1144
|
+
reason: reasons[problem],
|
|
1145
|
+
...typeof v.schemaFile == "string" ? { schemaFile: v.schemaFile } : {},
|
|
1146
|
+
...expected ? { expected } : {}
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
function recordFieldMessage(record4, field, problem, schemaPath, expected) {
|
|
1150
|
+
if (!validRecordRef(record4) || !/^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(field) || schemaPath !== void 0 && (schemaPath.length > 256 || !/^[a-zA-Z0-9_.-]+(?:\/[a-zA-Z0-9_.-]+)*\/_schema\.yaml$/.test(schemaPath) || schemaPath.split("/").some((part) => [".", "..", ".git", "routines"].includes(part)))) return;
|
|
1151
|
+
let prefix = `Record "${record4}" isn't valid.`, schema2 = schemaPath ? `"${schemaPath}"` : "the collection schema";
|
|
1152
|
+
if (problem === "source_schema") return field === "media_type" ? `${prefix} This repository's Source schema${schemaPath ? ` ${schema2}` : ""} doesn't include "media_type". The OS SDK uses "media_type" for file Sources. Update the Source schema in this repository to include this field.` : void 0;
|
|
1153
|
+
if (problem === "unknown") return `${prefix} The record contains "${field}", but ${schema2} doesn't define that field. Check that the record and ${schemaPath ? "that file" : "the collection schema"} use the same field name.`;
|
|
1154
|
+
if (problem === "missing") return `${prefix} The record is missing required field "${field}". Add it as defined in ${schema2}.`;
|
|
1155
|
+
let expectation = expected ? expectationText(expected) : void 0;
|
|
1156
|
+
if (!(expected && !expectation))
|
|
1157
|
+
return `${prefix} The record has an invalid value for field "${field}".${expectation ? ` ${expectation}` : ""} Check its definition in ${schema2}.`;
|
|
1158
|
+
}
|
|
1159
|
+
function safeRecordFieldMessage(value) {
|
|
1160
|
+
if (typeof value != "string" || value.length > 1200) return;
|
|
1161
|
+
let parts = /^Record "([^"]+)" isn't valid\. (.+)$/.exec(value);
|
|
1162
|
+
if (!parts) return;
|
|
1163
|
+
let schemaPath = /"([^"]+\/_schema\.yaml)"/.exec(value)?.[1], field = [...parts[2].matchAll(/"([^"]+)"/g)].map((match) => match[1]).find((part) => part !== schemaPath);
|
|
1164
|
+
if (!field) return;
|
|
1165
|
+
let expected = parseExpectation(/\. (Expected .+) Check its definition in /.exec(value)?.[1]);
|
|
1166
|
+
return fieldProblems.map((problem) => recordFieldMessage(parts[1], field, problem, schemaPath, expected)).find((message2) => message2 === value);
|
|
1167
|
+
}
|
|
1168
|
+
function dataValidationMessageFacts(error) {
|
|
1169
|
+
if (error.code === "invalid_change") {
|
|
1170
|
+
let detail = parseDataValidationDetail(error.detail);
|
|
1171
|
+
if (detail) {
|
|
1172
|
+
let problem = fieldProblems.find((problem2) => reasons[problem2] === detail.reason);
|
|
1173
|
+
return { detail, message: recordFieldMessage(
|
|
1174
|
+
detail.record,
|
|
1175
|
+
detail.field,
|
|
1176
|
+
problem,
|
|
1177
|
+
detail.schemaFile,
|
|
1178
|
+
detail.expected
|
|
1179
|
+
) };
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
let message2 = error.code === "invalid_change" ? safeRecordFieldMessage(error.message) : void 0;
|
|
1183
|
+
return message2 ? { message: message2 } : {};
|
|
1184
|
+
}
|
|
1185
|
+
function explainDataValidation(error, message2, detail) {
|
|
1186
|
+
return Object.assign(error, dataValidationMessageFacts({ code: error.code, message: typeof message2 == "string" ? message2 : "", detail })), error;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
var localDataPath = (value, repository) => typeof value == "string" && value.length <= 1024 && value.startsWith(`${repository}/`) && !value.includes("\\") && !/[\x00-\x1f\x7f]/.test(value) && value.split("/").every((part) => !!part && part !== "." && part !== ".."), localDataFile = (value, repository) => {
|
|
1190
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return !1;
|
|
1191
|
+
let row = value;
|
|
1192
|
+
return Object.keys(row).sort().join(",") === "action,path" && ["created", "updated", "deleted"].includes(String(row.action)) && localDataPath(row.path, repository);
|
|
1193
|
+
};
|
|
1194
|
+
function parseDataFailureDetail(value) {
|
|
1195
|
+
let invalid9 = () => {
|
|
1196
|
+
throw new Error("Invalid local Data failure detail");
|
|
1197
|
+
};
|
|
1198
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return invalid9();
|
|
1199
|
+
let row = value;
|
|
1200
|
+
if (Object.keys(row).sort().join(",") !== "cause,code,files,nextAction,operation,repository" || !["local_data_read_failed", "local_data_write_failed", "local_data_write_partial"].includes(String(row.code)) || !["read", "write"].includes(String(row.operation)) || typeof row.repository != "string" || !/^[a-z0-9][a-z0-9._/-]{0,127}$/.test(row.repository) || row.repository.includes("//") || row.repository.includes("..") || !["fix_failed_file_then_rerun", "review_resolve_then_rerun"].includes(String(row.nextAction))) return invalid9();
|
|
1201
|
+
let repository = row.repository;
|
|
1202
|
+
if (!row.cause || typeof row.cause != "object" || Array.isArray(row.cause)) return invalid9();
|
|
1203
|
+
let cause = row.cause;
|
|
1204
|
+
if (!["code,message", "code,message,path"].includes(Object.keys(cause).sort().join(",")) || !["schema_validation_failed", "invalid_record", "unsafe_record", "stale_record", "path_conflict", "filesystem_unavailable"].includes(String(cause.code)) || typeof cause.message != "string" || !cause.message || cause.message.length > 512 || /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/.test(cause.message) || cause.path !== void 0 && !localDataPath(cause.path, repository) || !row.files || typeof row.files != "object" || Array.isArray(row.files)) return invalid9();
|
|
1205
|
+
let files3 = row.files;
|
|
1206
|
+
if (Object.keys(files3).some((key) => !["state", "saved", "failed", "notAttempted", "savedOmitted", "notAttemptedOmitted"].includes(key)) || !["none", "partial"].includes(String(files3.state)) || !Array.isArray(files3.saved) || files3.saved.length > 128 || !files3.saved.every((item) => localDataFile(item, repository)) || files3.failed !== void 0 && !localDataFile(files3.failed, repository) || !Array.isArray(files3.notAttempted) || files3.notAttempted.length > 128 || !files3.notAttempted.every((item) => localDataFile(item, repository))) return invalid9();
|
|
1207
|
+
for (let key of ["savedOmitted", "notAttemptedOmitted"]) if (files3[key] !== void 0 && (!Number.isSafeInteger(files3[key]) || Number(files3[key]) < 1 || Number(files3[key]) > 1e4)) return invalid9();
|
|
1208
|
+
return row.operation === "read" && (row.code !== "local_data_read_failed" || files3.state !== "none" || files3.saved.length || files3.failed !== void 0 || files3.notAttempted.length) || row.operation === "write" && row.code === "local_data_read_failed" || row.code === "local_data_write_partial" && (files3.state !== "partial" || !files3.saved.length) || row.code !== "local_data_write_partial" && files3.state === "partial" ? invalid9() : structuredClone(value);
|
|
1209
|
+
}
|
|
1210
|
+
function parseDataOperationDetail(value) {
|
|
1211
|
+
let validation = parseDataValidationDetail(value);
|
|
1212
|
+
if (validation) return validation;
|
|
1213
|
+
if (value && typeof value == "object" && !Array.isArray(value) && value.code === "record_limit_exceeded") {
|
|
1214
|
+
let row = value;
|
|
1215
|
+
if (Object.keys(row).sort().join(",") !== "code,collections,maxRecords" || !Number.isSafeInteger(row.maxRecords) || Number(row.maxRecords) < 1 || !Array.isArray(row.collections) || !row.collections.length || row.collections.length > 16 || !row.collections.every((name2) => typeof name2 == "string" && name2.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(name2)) || new Set(row.collections).size !== row.collections.length)
|
|
1216
|
+
throw new Error("Invalid Data operation detail");
|
|
1217
|
+
return structuredClone(value);
|
|
1218
|
+
}
|
|
1219
|
+
return parseDataFailureDetail(value);
|
|
1220
|
+
}
|
|
1221
|
+
function dataRecordLimitMessage(detail) {
|
|
1222
|
+
let scope = detail.collections.length === 1 ? ` from ${detail.collections[0]}` : ` across ${detail.collections.join(", ")}`;
|
|
1223
|
+
return `The routine tried to load more than ${detail.maxRecords.toLocaleString("en-US")} matching Records${scope}. Narrow the query or increase maxRecords.`;
|
|
1224
|
+
}
|
|
1059
1225
|
var DataOperationError = class extends Error {
|
|
1060
|
-
constructor(code, retryable = !1, effect, component) {
|
|
1061
|
-
|
|
1226
|
+
constructor(code, retryable = !1, effect, component, detail) {
|
|
1227
|
+
let parsed = detail === void 0 ? void 0 : parseDataOperationDetail(detail);
|
|
1228
|
+
if (parsed && ("reason" in parsed ? code !== "invalid_change" : parsed.code === "record_limit_exceeded" && code !== "capacity"))
|
|
1229
|
+
throw new Error("Invalid Data operation detail");
|
|
1230
|
+
super(code === "capacity" && parsed && "code" in parsed && parsed.code === "record_limit_exceeded" ? dataRecordLimitMessage(parsed) : `Data operation failed: ${code}`);
|
|
1062
1231
|
this.code = code;
|
|
1063
1232
|
this.retryable = retryable;
|
|
1064
1233
|
this.effect = effect;
|
|
1065
1234
|
this.component = component;
|
|
1066
|
-
this.
|
|
1235
|
+
this.detail = detail;
|
|
1236
|
+
this.name = "DataOperationError", parsed !== void 0 && (this.detail = parsed);
|
|
1067
1237
|
}
|
|
1068
1238
|
code;
|
|
1069
1239
|
retryable;
|
|
1070
1240
|
effect;
|
|
1071
1241
|
component;
|
|
1242
|
+
detail;
|
|
1072
1243
|
};
|
|
1073
1244
|
|
|
1074
|
-
var RECORD_READ_INPUT_LIMIT = 1024 * 1024, RECORD_CAPTURE_OUTPUT_LIMIT = 25 * 1024 * 1024;
|
|
1075
|
-
function validRecordRef(value) {
|
|
1076
|
-
return typeof value == "string" && value.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)+$/.test(value);
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
1245
|
var invalid4 = () => {
|
|
1080
1246
|
throw new DataOperationError("invalid_query");
|
|
1081
1247
|
}, historyText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
|
|
@@ -1169,8 +1335,24 @@ function captureRecordsReadRefs(value) {
|
|
|
1169
1335
|
throw new DataOperationError("invalid_query");
|
|
1170
1336
|
return refs;
|
|
1171
1337
|
}
|
|
1338
|
+
function captureRecordsReadOptions(value) {
|
|
1339
|
+
if (value === void 0) return {};
|
|
1340
|
+
let row;
|
|
1341
|
+
try {
|
|
1342
|
+
row = Object.fromEntries(Object.entries(historyProperties(value)).map(([key, descriptor]) => [key, descriptor.value]));
|
|
1343
|
+
} catch {
|
|
1344
|
+
throw new DataOperationError("invalid_query");
|
|
1345
|
+
}
|
|
1346
|
+
if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)) || Reflect.ownKeys(value).some((key) => key !== "body" || !Object.hasOwn(Object.getOwnPropertyDescriptor(value, key), "value")) || Object.hasOwn(row, "body") && typeof row.body != "boolean") throw new DataOperationError("invalid_query");
|
|
1347
|
+
return Object.hasOwn(row, "body") ? { body: row.body } : {};
|
|
1348
|
+
}
|
|
1172
1349
|
|
|
1173
|
-
|
|
1350
|
+
function validRecordBody(value) {
|
|
1351
|
+
return typeof value == "string" && value === new TextDecoder("utf-8", { ignoreBOM: !0 }).decode(new TextEncoder().encode(value));
|
|
1352
|
+
}
|
|
1353
|
+
var RECORD_BODY_READ_BYTES = 8 * 1024 * 1024;
|
|
1354
|
+
|
|
1355
|
+
var DATA_REQUEST_LIMIT = 256 * 1024, LOCAL_DATA_CHANGE_REQUEST_LIMIT = 32 * 1024 * 1024, invalidChange = () => {
|
|
1174
1356
|
throw new DataOperationError("invalid_change", !1, "unapplied");
|
|
1175
1357
|
};
|
|
1176
1358
|
function mapping(value) {
|
|
@@ -1195,16 +1377,16 @@ function captureDataDelete(record4) {
|
|
|
1195
1377
|
return !validRecordRef(identity.$ref) || typeof identity.$version != "string" || !identity.$version.length || identity.$version.length > 512 ? invalidChange() : { ref: identity.$ref, expectedVersion: identity.$version };
|
|
1196
1378
|
}
|
|
1197
1379
|
function captureDataUpdate(record4, set) {
|
|
1198
|
-
let identity = captureDataDelete(record4),
|
|
1199
|
-
return !Object.keys(fields5).length || Object.keys(fields5).some((key) => key.startsWith("$") || ["id", "type"].includes(key)) ? invalidChange() : { ...identity, set: captureValue(fields5) };
|
|
1380
|
+
let identity = captureDataDelete(record4), input = mapping(set), { $body, ...fields5 } = input, body = Object.hasOwn(input, "$body");
|
|
1381
|
+
return body && !validRecordBody($body) || !Object.keys(fields5).length && !body || Object.keys(fields5).some((key) => key.startsWith("$") || ["id", "type"].includes(key)) ? invalidChange() : { ...identity, set: captureValue(fields5), ...body ? { body: $body } : {} };
|
|
1200
1382
|
}
|
|
1201
1383
|
function captureIdentities(value, update, allowEmpty = !0) {
|
|
1202
1384
|
if (!Array.isArray(value) || !allowEmpty && !value.length || value.length > 1e4) return invalidChange();
|
|
1203
1385
|
let captured = value.map((item) => {
|
|
1204
1386
|
let row = mapping(item);
|
|
1205
|
-
if (Object.keys(row).sort().join(",") !== (update ? "expectedVersion,ref,set" : "expectedVersion,ref")) return invalidChange();
|
|
1387
|
+
if (Object.keys(row).filter((key) => !update || key !== "body").sort().join(",") !== (update ? "expectedVersion,ref,set" : "expectedVersion,ref")) return invalidChange();
|
|
1206
1388
|
let identity = { $ref: row.ref, $version: row.expectedVersion };
|
|
1207
|
-
return update ? captureDataUpdate(identity, row.set) : captureDataDelete(identity);
|
|
1389
|
+
return update && Object.keys(mapping(row.set)).some((key) => key.startsWith("$")) ? invalidChange() : update ? captureDataUpdate(identity, { ...mapping(row.set), ...Object.hasOwn(row, "body") ? { $body: row.body } : {} }) : captureDataDelete(identity);
|
|
1208
1390
|
});
|
|
1209
1391
|
return new Set(captured.map((item) => item.ref)).size !== captured.length ? invalidChange() : captured;
|
|
1210
1392
|
}
|
|
@@ -1213,30 +1395,37 @@ function captureDataUpdates(value, allowEmpty = !1) {
|
|
|
1213
1395
|
}
|
|
1214
1396
|
function captureDataCreate(value) {
|
|
1215
1397
|
let row = mapping(value);
|
|
1216
|
-
if (!validRecordRef(row.$ref) || Object.keys(row).some((key) => key.startsWith("$") && !["$ref", "$filing"].includes(key)))
|
|
1398
|
+
if (!validRecordRef(row.$ref) || Object.keys(row).some((key) => key.startsWith("$") && !["$ref", "$filing", "$body"].includes(key)))
|
|
1217
1399
|
return invalidChange();
|
|
1218
|
-
let { $ref: ref, $filing, ...fields5 } = row,
|
|
1400
|
+
let { $ref: ref, $filing, $body, ...fields5 } = row, body = Object.hasOwn(row, "$body");
|
|
1401
|
+
if (body && !validRecordBody($body)) return invalidChange();
|
|
1402
|
+
let filing;
|
|
1219
1403
|
if ($filing !== void 0) {
|
|
1220
1404
|
let components = mapping($filing);
|
|
1221
1405
|
if (Object.entries(components).some(([name2, value2]) => !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name2) || ["constructor", "prototype"].includes(name2) || typeof value2 != "string" || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(value2)))
|
|
1222
1406
|
return invalidChange();
|
|
1223
1407
|
filing = { ...components };
|
|
1224
1408
|
}
|
|
1225
|
-
return { ref, fields: captureValue(fields5), ...filing ? { filing } : {} };
|
|
1409
|
+
return { ref, fields: captureValue(fields5), ...filing ? { filing } : {}, ...body ? { body: $body } : {} };
|
|
1226
1410
|
}
|
|
1227
1411
|
function captureDataChanges(updatesValue, createsValue = [], deletesValue = []) {
|
|
1228
1412
|
let updates = captureDataUpdates(updatesValue, !0);
|
|
1229
1413
|
if (!Array.isArray(createsValue) || createsValue.length > 1e4) return invalidChange();
|
|
1230
1414
|
let creates = createsValue.map((item) => {
|
|
1231
1415
|
let row = mapping(item);
|
|
1232
|
-
if (Object.keys(row).some((key) => !["ref", "fields", "filing"].includes(key)) || !Object.hasOwn(row, "ref") || !Object.hasOwn(row, "fields")) return invalidChange();
|
|
1416
|
+
if (Object.keys(row).some((key) => !["ref", "fields", "filing", "body"].includes(key)) || !Object.hasOwn(row, "ref") || !Object.hasOwn(row, "fields")) return invalidChange();
|
|
1233
1417
|
let fields5 = mapping(row.fields);
|
|
1234
|
-
return Object.keys(fields5).some((key) => key.startsWith("$")) ? invalidChange() : captureDataCreate({
|
|
1418
|
+
return Object.keys(fields5).some((key) => key.startsWith("$")) ? invalidChange() : captureDataCreate({
|
|
1419
|
+
...fields5,
|
|
1420
|
+
$ref: row.ref,
|
|
1421
|
+
...Object.hasOwn(row, "filing") ? { $filing: row.filing } : {},
|
|
1422
|
+
...Object.hasOwn(row, "body") ? { $body: row.body } : {}
|
|
1423
|
+
});
|
|
1235
1424
|
}), deletes = captureIdentities(deletesValue, !1), refs = [...updates, ...creates, ...deletes].map((item) => item.ref);
|
|
1236
1425
|
return !refs.length || refs.length > 1e4 || new Set(refs).size !== refs.length ? invalidChange() : { updates, creates, deletes };
|
|
1237
1426
|
}
|
|
1238
|
-
function checkDataRequestSize(input) {
|
|
1239
|
-
if (new TextEncoder().encode(JSON.stringify(input)).byteLength >
|
|
1427
|
+
function checkDataRequestSize(input, limit = DATA_REQUEST_LIMIT) {
|
|
1428
|
+
if (new TextEncoder().encode(JSON.stringify(input)).byteLength > limit)
|
|
1240
1429
|
throw new DataOperationError("request_too_large", !1, "unapplied");
|
|
1241
1430
|
}
|
|
1242
1431
|
function dataTransportError(status, value) {
|
|
@@ -1244,17 +1433,22 @@ function dataTransportError(status, value) {
|
|
|
1244
1433
|
400: ["invalid_query", "invalid_change"],
|
|
1245
1434
|
401: ["unauthenticated"],
|
|
1246
1435
|
403: ["access_denied"],
|
|
1247
|
-
409: ["conflict", "
|
|
1436
|
+
409: ["conflict", "apply_pending"],
|
|
1248
1437
|
413: ["request_too_large"],
|
|
1249
1438
|
429: ["capacity"],
|
|
1250
|
-
503: ["unavailable", "
|
|
1251
|
-
}, error = value && typeof value == "object" && "error" in value ? value.error : void 0, row = error && typeof error == "object" ? error : void 0, code = failures2[status]?.find((allowed) => allowed === row?.code) ?? "unavailable", effect = ["unapplied", "uncertain", "applied"].includes(String(row?.effect)) ? row.effect : void 0;
|
|
1252
|
-
|
|
1439
|
+
503: ["unavailable", "apply_pending"]
|
|
1440
|
+
}, error = value && typeof value == "object" && "error" in value ? value.error : void 0, row = error && typeof error == "object" ? error : void 0, code = failures2[status]?.find((allowed) => allowed === row?.code) ?? "unavailable", effect = ["unapplied", "uncertain", "applied"].includes(String(row?.effect)) ? row.effect : void 0, detail;
|
|
1441
|
+
try {
|
|
1442
|
+
detail = row?.detail === void 0 ? void 0 : parseDataOperationDetail(row.detail);
|
|
1443
|
+
} catch {
|
|
1444
|
+
}
|
|
1445
|
+
return detail && "reason" in detail && code !== "invalid_change" && (detail = void 0), explainDataValidation(new DataOperationError(
|
|
1253
1446
|
code,
|
|
1254
|
-
["capacity", "unavailable", "
|
|
1447
|
+
typeof row?.retryable == "boolean" ? row.retryable : ["capacity", "unavailable", "apply_pending"].includes(code),
|
|
1255
1448
|
code === "conflict" ? "unapplied" : effect,
|
|
1256
|
-
code === "invalid_change" && typeof row?.component == "string" && /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(row.component) ? row.component : void 0
|
|
1257
|
-
|
|
1449
|
+
code === "invalid_change" && typeof row?.component == "string" && /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(row.component) ? row.component : void 0,
|
|
1450
|
+
detail
|
|
1451
|
+
), row?.message, row?.detail);
|
|
1258
1452
|
}
|
|
1259
1453
|
|
|
1260
1454
|
var installed, ended = !1;
|
|
@@ -1404,12 +1598,21 @@ function recordPagination(select) {
|
|
|
1404
1598
|
async function all(query, options) {
|
|
1405
1599
|
let properties = historyProperties(options), maxRecords = properties.maxRecords?.value;
|
|
1406
1600
|
(Object.keys(properties).join(",") !== "maxRecords" || !Number.isSafeInteger(maxRecords) || maxRecords < 1) && invalid6();
|
|
1601
|
+
let captured = capture3(query), names = Object.keys(historyProperties(captured));
|
|
1602
|
+
if (names.length === 1) {
|
|
1603
|
+
let name2 = names[0], selection2 = historyProperties(captured[name2]), selectionNames = Object.keys(selection2), authored = selection2.$ ? historyProperties(selection2.$.value) : {};
|
|
1604
|
+
selectionNames.every((key) => key === "$") && !Object.hasOwn(authored, "limit") && (captured[name2] = { ...captured[name2], $: { ...captured[name2].$, limit: Math.min(500, maxRecords) } });
|
|
1605
|
+
}
|
|
1407
1606
|
let result2, total = 0;
|
|
1408
|
-
for await (let page of pages(
|
|
1409
|
-
let
|
|
1410
|
-
if (size > maxRecords - total) throw new DataOperationError("capacity"
|
|
1411
|
-
|
|
1412
|
-
|
|
1607
|
+
for await (let page of pages(captured)) {
|
|
1608
|
+
let names2 = Object.keys(page.$meta.collections), size = names2.reduce((sum, name2) => sum + page[name2].length, 0);
|
|
1609
|
+
if (size > maxRecords - total) throw new DataOperationError("capacity", !1, void 0, void 0, {
|
|
1610
|
+
code: "record_limit_exceeded",
|
|
1611
|
+
maxRecords,
|
|
1612
|
+
collections: names2
|
|
1613
|
+
});
|
|
1614
|
+
total += size, result2 ??= { ...Object.fromEntries(names2.map((name2) => [name2, []])), $meta: page.$meta };
|
|
1615
|
+
for (let name2 of names2) {
|
|
1413
1616
|
let target = result2[name2];
|
|
1414
1617
|
for (let record4 of page[name2]) target.push(record4);
|
|
1415
1618
|
}
|
|
@@ -1423,8 +1626,8 @@ function recordPagination(select) {
|
|
|
1423
1626
|
var genericData = {
|
|
1424
1627
|
repository(repository) {
|
|
1425
1628
|
async function send3(input) {
|
|
1426
|
-
let context = await resolveDataContext(), envelope = { repository, ...input };
|
|
1427
|
-
if (checkDataRequestSize(envelope), "local" in context) return await context.local("data/query", envelope);
|
|
1629
|
+
let context = await resolveDataContext(), envelope = { repository, ...input }, changing = "operation" in input && ["changes.validate", "changes.apply"].includes(String(input.operation));
|
|
1630
|
+
if (checkDataRequestSize(envelope, "local" in context && changing ? LOCAL_DATA_CHANGE_REQUEST_LIMIT : DATA_REQUEST_LIMIT), "local" in context) return await context.local("data/query", envelope);
|
|
1428
1631
|
try {
|
|
1429
1632
|
let response2 = await fetch(context.url, {
|
|
1430
1633
|
method: "POST",
|
|
@@ -1440,8 +1643,8 @@ var genericData = {
|
|
|
1440
1643
|
throw error instanceof DataOperationError ? error : new DataOperationError("unavailable", !0);
|
|
1441
1644
|
}
|
|
1442
1645
|
}
|
|
1443
|
-
async function read2(input) {
|
|
1444
|
-
let refs = captureRecordsReadRefs(typeof input == "string" ? [input] : input), result2 = await send3({ operation: "records.read", refs });
|
|
1646
|
+
async function read2(input, options) {
|
|
1647
|
+
let refs = captureRecordsReadRefs(typeof input == "string" ? [input] : input), captured = captureRecordsReadOptions(options), result2 = await send3({ operation: "records.read", refs, ...options === void 0 ? {} : { options: captured } });
|
|
1445
1648
|
return typeof input == "string" ? result2.records[0] : result2;
|
|
1446
1649
|
}
|
|
1447
1650
|
let select = (query) => send3({ operation: "records.select", query });
|
|
@@ -1462,16 +1665,16 @@ var genericData = {
|
|
|
1462
1665
|
changes: async (options) => send3({ operation: "history.changes", options: captureHistoryChangesOptions(options) })
|
|
1463
1666
|
},
|
|
1464
1667
|
changes() {
|
|
1465
|
-
let updates = [], creates = [], deletes = [],
|
|
1466
|
-
if (
|
|
1668
|
+
let updates = [], creates = [], deletes = [], applyId, pending, confirmed, assertMutable = () => {
|
|
1669
|
+
if (applyId) throw new DataOperationError("invalid_change", !1, "unapplied");
|
|
1467
1670
|
}, snapshot = (nextUpdates = updates, nextCreates = creates, nextDeletes = deletes) => {
|
|
1468
1671
|
let { updates: updates2, creates: creates2, deletes: deletes2 } = captureDataChanges(nextUpdates, nextCreates, nextDeletes), input = { updates: updates2, ...creates2.length ? { creates: creates2 } : {}, ...deletes2.length ? { deletes: deletes2 } : {} };
|
|
1469
1672
|
return checkDataRequestSize({
|
|
1470
1673
|
repository,
|
|
1471
|
-
operation: "changes.
|
|
1674
|
+
operation: "changes.apply",
|
|
1472
1675
|
...input,
|
|
1473
|
-
|
|
1474
|
-
}), input;
|
|
1676
|
+
applyId: applyId ?? "00000000-0000-4000-8000-000000000000"
|
|
1677
|
+
}, LOCAL_DATA_CHANGE_REQUEST_LIMIT), input;
|
|
1475
1678
|
};
|
|
1476
1679
|
return {
|
|
1477
1680
|
create(record4) {
|
|
@@ -1492,7 +1695,7 @@ var genericData = {
|
|
|
1492
1695
|
async validate() {
|
|
1493
1696
|
await send3({ operation: "changes.validate", ...snapshot() });
|
|
1494
1697
|
},
|
|
1495
|
-
|
|
1698
|
+
apply() {
|
|
1496
1699
|
if (confirmed) return Promise.resolve(structuredClone(confirmed));
|
|
1497
1700
|
if (!pending) {
|
|
1498
1701
|
let captured;
|
|
@@ -1501,13 +1704,14 @@ var genericData = {
|
|
|
1501
1704
|
} catch (error) {
|
|
1502
1705
|
return Promise.reject(error);
|
|
1503
1706
|
}
|
|
1504
|
-
|
|
1505
|
-
throw error instanceof DataOperationError ? new DataOperationError(
|
|
1707
|
+
applyId ??= routineTransport()?.key("data") ?? crypto.randomUUID(), pending = send3({ operation: "changes.apply", ...captured, applyId }).then((result2) => (confirmed = structuredClone(result2), result2)).catch((error) => {
|
|
1708
|
+
throw error instanceof DataOperationError ? explainDataValidation(new DataOperationError(
|
|
1506
1709
|
error.code,
|
|
1507
1710
|
error.retryable,
|
|
1508
|
-
error.effect ?? (["unavailable", "
|
|
1509
|
-
error.component
|
|
1510
|
-
|
|
1711
|
+
error.effect ?? (["unavailable", "apply_pending"].includes(error.code) ? "uncertain" : "unapplied"),
|
|
1712
|
+
error.component,
|
|
1713
|
+
error.detail
|
|
1714
|
+
), error.message, error.detail) : new DataOperationError("unavailable", !0, "uncertain");
|
|
1511
1715
|
}).finally(() => {
|
|
1512
1716
|
pending = void 0;
|
|
1513
1717
|
});
|
|
@@ -1578,7 +1782,7 @@ async function hostedContent(url, init2, parent, upstream = fetch, check = async
|
|
|
1578
1782
|
}
|
|
1579
1783
|
}
|
|
1580
1784
|
|
|
1581
|
-
var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0, invalid7 = () => new FileOperationError("invalid_input", 400), unavailable2 = () => new FileOperationError("unavailable", 503, !0), failures = {
|
|
1785
|
+
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, waiters = [], invalid7 = () => new FileOperationError("invalid_input", 400), unavailable2 = () => new FileOperationError("unavailable", 503, !0), failures = {
|
|
1582
1786
|
400: ["invalid_input", "unsupported_context"],
|
|
1583
1787
|
401: ["unauthenticated"],
|
|
1584
1788
|
403: ["access_denied"],
|
|
@@ -1588,6 +1792,41 @@ var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES =
|
|
|
1588
1792
|
429: ["capacity"],
|
|
1589
1793
|
503: ["integrity", "unavailable"]
|
|
1590
1794
|
};
|
|
1795
|
+
function heldSlot() {
|
|
1796
|
+
let held = !0;
|
|
1797
|
+
return () => {
|
|
1798
|
+
if (held)
|
|
1799
|
+
for (held = !1; ; ) {
|
|
1800
|
+
let waiter = waiters.shift();
|
|
1801
|
+
if (!waiter) {
|
|
1802
|
+
active--;
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
if (waiter.waiting) {
|
|
1806
|
+
waiter.waiting = !1, waiter.signal?.removeEventListener("abort", waiter.abort), waiter.resolve(heldSlot());
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
async function acquireSlot(signal) {
|
|
1813
|
+
if (signal?.aborted) throw unavailable2();
|
|
1814
|
+
return active < MAX_ACTIVE ? (active++, heldSlot()) : new Promise((resolve, reject) => {
|
|
1815
|
+
let waiter = {
|
|
1816
|
+
signal,
|
|
1817
|
+
waiting: !0,
|
|
1818
|
+
resolve,
|
|
1819
|
+
reject,
|
|
1820
|
+
abort() {
|
|
1821
|
+
if (!waiter.waiting) return;
|
|
1822
|
+
waiter.waiting = !1;
|
|
1823
|
+
let index = waiters.indexOf(waiter);
|
|
1824
|
+
index !== -1 && waiters.splice(index, 1), reject(unavailable2());
|
|
1825
|
+
}
|
|
1826
|
+
};
|
|
1827
|
+
waiters.push(waiter), signal?.addEventListener("abort", waiter.abort, { once: !0 }), signal?.aborted && waiter.abort();
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1591
1830
|
async function boundedBytes(stream, limit, signal) {
|
|
1592
1831
|
if (!stream) return new Uint8Array();
|
|
1593
1832
|
let reader = stream.getReader(), bytes = new Uint8Array(limit), size = 0, cancel = () => {
|
|
@@ -1665,7 +1904,7 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1665
1904
|
parseFileErrorDetail(error?.detail)
|
|
1666
1905
|
) : unavailable2();
|
|
1667
1906
|
}
|
|
1668
|
-
if (response2.status !==
|
|
1907
|
+
if (response2.status !== 200)
|
|
1669
1908
|
throw response2.body?.cancel().catch(() => {
|
|
1670
1909
|
}), unavailable2();
|
|
1671
1910
|
try {
|
|
@@ -1674,7 +1913,6 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1674
1913
|
throw response2.body?.cancel().catch(() => {
|
|
1675
1914
|
}), error;
|
|
1676
1915
|
}
|
|
1677
|
-
if (descriptor === 204) return;
|
|
1678
1916
|
if (!descriptor) return response2;
|
|
1679
1917
|
let value = await result(response2, descriptor === "control" ? CONTROL_RESULT_BYTES : RESULT_BYTES);
|
|
1680
1918
|
if (descriptor === "control")
|
|
@@ -1698,9 +1936,7 @@ function idPath(id3) {
|
|
|
1698
1936
|
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid7();
|
|
1699
1937
|
return `/${id3}`;
|
|
1700
1938
|
}
|
|
1701
|
-
async function multipartCreate(input, metadata, exchange, release
|
|
1702
|
-
active--;
|
|
1703
|
-
}, upload) {
|
|
1939
|
+
async function multipartCreate(input, metadata, exchange, release, upload, expectedSha256) {
|
|
1704
1940
|
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) => {
|
|
1705
1941
|
let task = work(signal);
|
|
1706
1942
|
return pending.add(task), task.then(() => pending.delete(task), () => pending.delete(task)), task;
|
|
@@ -1710,7 +1946,9 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1710
1946
|
body: JSON.stringify(body)
|
|
1711
1947
|
});
|
|
1712
1948
|
try {
|
|
1713
|
-
let
|
|
1949
|
+
let startRequest = control(upload?.file ?? metadata);
|
|
1950
|
+
expectedSha256 && (startRequest.headers["x-os-original-sha256"] = expectedSha256);
|
|
1951
|
+
let start = await request2((signal) => exchange(`${route}/start`, startRequest, "control", signal));
|
|
1714
1952
|
if (!start || typeof start != "object" || Array.isArray(start)) throw unavailable2();
|
|
1715
1953
|
let session = start;
|
|
1716
1954
|
if (Object.keys(session).sort().join(",") !== "partBytes,ticket" || session.partBytes !== PART_BYTES || typeof session.ticket != "string" || !session.ticket || session.ticket.length > 64 * 1024) throw unavailable2();
|
|
@@ -1773,10 +2011,15 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1773
2011
|
await upload?.beforeComplete();
|
|
1774
2012
|
let completion = control({ parts: receipts });
|
|
1775
2013
|
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw unavailable2();
|
|
1776
|
-
|
|
2014
|
+
let completed = parseFileDescriptor(await request2(
|
|
1777
2015
|
(signal) => exchange(`${route}/complete`, completion, !0, signal),
|
|
1778
2016
|
TIMEOUT_MS + Math.ceil(metadata.size / (1024 * 1024)) * 1e3
|
|
1779
2017
|
));
|
|
2018
|
+
if (!upload) {
|
|
2019
|
+
let acknowledged = await request2((signal) => exchange(`${route}/acknowledge`, control(completed), "control", signal));
|
|
2020
|
+
if (!acknowledged || typeof acknowledged != "object" || Object.keys(acknowledged).join(",") !== "acknowledged" || acknowledged.acknowledged !== !0) throw unavailable2();
|
|
2021
|
+
}
|
|
2022
|
+
return completed;
|
|
1780
2023
|
} catch (error) {
|
|
1781
2024
|
throw reader && await reader.cancel(error).catch(() => {
|
|
1782
2025
|
}), ticket && await request2((signal) => exchange(`${route}/abort`, control({}), "control", signal)).catch(() => {
|
|
@@ -1786,16 +2029,13 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1786
2029
|
}
|
|
1787
2030
|
}
|
|
1788
2031
|
async function operation(work, initial, parent) {
|
|
1789
|
-
let context = initial ?? await resolveFilesContext()
|
|
1790
|
-
if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
|
|
1791
|
-
active++;
|
|
1792
|
-
let execute = async (signal2) => {
|
|
2032
|
+
let context = initial ?? await resolveFilesContext(), signal = context.signal && parent ? AbortSignal.any([context.signal, parent]) : context.signal ?? parent, release = await acquireSlot(signal), execute = async (signal2) => {
|
|
1793
2033
|
try {
|
|
1794
2034
|
return await work(context, signal2);
|
|
1795
2035
|
} finally {
|
|
1796
|
-
|
|
2036
|
+
release();
|
|
1797
2037
|
}
|
|
1798
|
-
}
|
|
2038
|
+
};
|
|
1799
2039
|
return context.localFiles ? execute(signal ?? new AbortController().signal) : timed(execute, signal).catch((error) => {
|
|
1800
2040
|
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1801
2041
|
});
|
|
@@ -1839,9 +2079,6 @@ async function read(id3, names) {
|
|
|
1839
2079
|
});
|
|
1840
2080
|
}
|
|
1841
2081
|
var files = {
|
|
1842
|
-
delete(id3) {
|
|
1843
|
-
return operation((context, signal) => send(idPath(id3), { method: "DELETE" }, 204, context, signal));
|
|
1844
|
-
},
|
|
1845
2082
|
async upload(id3) {
|
|
1846
2083
|
return operation(async (context, signal) => {
|
|
1847
2084
|
let file2 = await send(`${idPath(id3)}/upload`, { method: "POST" }, !0, context, signal);
|
|
@@ -1876,28 +2113,27 @@ var files = {
|
|
|
1876
2113
|
if (!context.local && !context.localFiles && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
1877
2114
|
let header = encodeURIComponent(JSON.stringify(metadata));
|
|
1878
2115
|
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1879
|
-
|
|
1880
|
-
if (
|
|
1881
|
-
let signal = context.signal ?? new AbortController().signal, file2 = input.file, offset = 0, body = file2 instanceof Blob ? context.signal ? file2 : file2.stream() : file2 instanceof ReadableStream ? file2 : new ReadableStream({
|
|
1882
|
-
pull(controller) {
|
|
1883
|
-
if (offset === file2.byteLength) {
|
|
1884
|
-
controller.close();
|
|
1885
|
-
return;
|
|
1886
|
-
}
|
|
1887
|
-
let end = Math.min(offset + 256 * 1024, file2.byteLength);
|
|
1888
|
-
controller.enqueue(file2.subarray(offset, end)), offset = end;
|
|
1889
|
-
}
|
|
1890
|
-
}, { highWaterMark: 0 });
|
|
2116
|
+
let release = await acquireSlot(context.signal);
|
|
2117
|
+
if (context.localFiles && !routineTransport() && metadata.size > MAX_BYTES)
|
|
1891
2118
|
try {
|
|
2119
|
+
let signal = context.signal ?? new AbortController().signal, file2 = input.file, offset = 0, body = file2 instanceof Blob ? context.signal ? file2 : file2.stream() : file2 instanceof ReadableStream ? file2 : new ReadableStream({
|
|
2120
|
+
pull(controller) {
|
|
2121
|
+
if (offset === file2.byteLength) {
|
|
2122
|
+
controller.close();
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
let end = Math.min(offset + 256 * 1024, file2.byteLength);
|
|
2126
|
+
controller.enqueue(file2.subarray(offset, end)), offset = end;
|
|
2127
|
+
}
|
|
2128
|
+
}, { highWaterMark: 0 });
|
|
1892
2129
|
return await send("", { method: "POST", headers: {
|
|
1893
2130
|
"content-type": "application/octet-stream",
|
|
1894
2131
|
"x-os-file": header
|
|
1895
2132
|
}, body }, !0, context, signal);
|
|
1896
2133
|
} finally {
|
|
1897
|
-
|
|
2134
|
+
release();
|
|
1898
2135
|
}
|
|
1899
|
-
|
|
1900
|
-
return metadata.size > MAX_BYTES ? multipartCreate(input, metadata, (suffix, init2, kind, signal) => kind === !0 ? send(suffix, init2, !0, context, signal) : send(suffix, init2, "control", context, signal)) : timed(async (signal) => {
|
|
2136
|
+
return metadata.size > MAX_BYTES ? multipartCreate(input, metadata, (suffix, init2, kind, signal) => kind === !0 ? send(suffix, init2, !0, context, signal) : send(suffix, init2, "control", context, signal), release) : timed(async (signal) => {
|
|
1901
2137
|
try {
|
|
1902
2138
|
let bytes = array3 ? new Uint8Array(input.file) : await boundedBytes(
|
|
1903
2139
|
blob ? input.file.stream() : input.file,
|
|
@@ -1917,7 +2153,7 @@ var files = {
|
|
|
1917
2153
|
body: bytes.buffer
|
|
1918
2154
|
}, !0, context, signal);
|
|
1919
2155
|
} finally {
|
|
1920
|
-
|
|
2156
|
+
release();
|
|
1921
2157
|
}
|
|
1922
2158
|
}, context.signal).catch((error) => {
|
|
1923
2159
|
throw error instanceof FileOperationError ? error : unavailable2();
|
|
@@ -2310,16 +2546,75 @@ async function reportLocalRoutineEffect(value) {
|
|
|
2310
2546
|
await observer?.(value);
|
|
2311
2547
|
}
|
|
2312
2548
|
|
|
2549
|
+
var identityPattern = /^(gmail|airtable|dropbox|outlook|sharepoint)\/([a-z0-9][a-z0-9-]{0,62})$/, workspacePattern = /^[a-z0-9][a-z0-9-]{0,62}$/, providerNames = {
|
|
2550
|
+
gmail: "Gmail",
|
|
2551
|
+
airtable: "Airtable",
|
|
2552
|
+
dropbox: "Dropbox",
|
|
2553
|
+
outlook: "Outlook",
|
|
2554
|
+
sharepoint: "SharePoint"
|
|
2555
|
+
};
|
|
2556
|
+
function parseConnectionFailureDetail(value) {
|
|
2557
|
+
if (!value || typeof value != "object" || Array.isArray(value)) throw new Error("Invalid Connection failure");
|
|
2558
|
+
let detail = value;
|
|
2559
|
+
if (!["identity", "identity,workspace"].includes(Object.keys(detail).sort().join(",")) || typeof detail.identity != "string" || !identityPattern.test(detail.identity) || detail.workspace !== void 0 && (typeof detail.workspace != "string" || !workspacePattern.test(detail.workspace)))
|
|
2560
|
+
throw new Error("Invalid Connection failure");
|
|
2561
|
+
return { identity: detail.identity, ...detail.workspace === void 0 ? {} : { workspace: detail.workspace } };
|
|
2562
|
+
}
|
|
2563
|
+
function connectionFailureMessage(value) {
|
|
2564
|
+
let detail = parseConnectionFailureDetail(value), [, provider2, name2] = identityPattern.exec(detail.identity), first = `Couldn\u2019t use ${providerNames[provider2] ?? provider2} connection ${name2}.`;
|
|
2565
|
+
return detail.workspace ? `${first}
|
|
2566
|
+
|
|
2567
|
+
Check it with:
|
|
2568
|
+
os connection test --workspace ${detail.workspace} --connection ${detail.identity}` : `${first}
|
|
2569
|
+
|
|
2570
|
+
Check or reconnect this Connection, then try again.`;
|
|
2571
|
+
}
|
|
2572
|
+
var ConnectionOperationError = class extends Error {
|
|
2573
|
+
code = "unavailable";
|
|
2574
|
+
detail;
|
|
2575
|
+
constructor(identity, workspace) {
|
|
2576
|
+
let detail = parseConnectionFailureDetail({ identity, ...workspace === void 0 ? {} : { workspace } });
|
|
2577
|
+
super(connectionFailureMessage(detail)), this.name = "ConnectionOperationError", this.detail = detail;
|
|
2578
|
+
}
|
|
2579
|
+
};
|
|
2580
|
+
|
|
2313
2581
|
var local;
|
|
2314
|
-
async function localLease(identity
|
|
2582
|
+
async function localLease(identity) {
|
|
2315
2583
|
let current2 = local;
|
|
2316
2584
|
if (!current2 || !current2.declared.includes(identity)) throw new Error("Connection unavailable");
|
|
2317
|
-
|
|
2318
|
-
|
|
2585
|
+
let lease = current2.leases.find((value) => `${value.provider}/${value.name}` === identity);
|
|
2586
|
+
if (lease)
|
|
2587
|
+
try {
|
|
2588
|
+
return parseConnectionLease(lease);
|
|
2589
|
+
} catch {
|
|
2590
|
+
let index = current2.leases.indexOf(lease);
|
|
2591
|
+
if (index !== -1 && current2.leases.splice(index, 1), !current2.acquire) throw new Error("Connection unavailable");
|
|
2592
|
+
lease = void 0;
|
|
2593
|
+
}
|
|
2594
|
+
if (!lease && current2.acquire) {
|
|
2595
|
+
let acquiring = current2.acquiring.get(identity);
|
|
2596
|
+
acquiring || (acquiring = (async () => {
|
|
2597
|
+
let acquired = parseConnectionLease(await current2.acquire(identity));
|
|
2598
|
+
if (local !== current2 || acquired.runId !== current2.runId || `${acquired.provider}/${acquired.name}` !== identity)
|
|
2599
|
+
throw new Error("Connection unavailable");
|
|
2600
|
+
return current2.leases.push(acquired), acquired;
|
|
2601
|
+
})(), current2.acquiring.set(identity, acquiring), acquiring.finally(() => {
|
|
2602
|
+
current2.acquiring.get(identity) === acquiring && current2.acquiring.delete(identity);
|
|
2603
|
+
}).catch(() => {
|
|
2604
|
+
})), lease = await acquiring;
|
|
2605
|
+
}
|
|
2319
2606
|
if (local !== current2 || !lease || lease.runId !== current2.runId || `${lease.provider}/${lease.name}` !== identity)
|
|
2320
2607
|
throw new Error("Connection unavailable");
|
|
2321
2608
|
return parseConnectionLease(lease);
|
|
2322
2609
|
}
|
|
2610
|
+
function connectionFailure(identity) {
|
|
2611
|
+
let workspace = typeof process > "u" ? void 0 : process.env.OS_ROUTINE_WORKSPACE;
|
|
2612
|
+
try {
|
|
2613
|
+
return new ConnectionOperationError(identity, workspace);
|
|
2614
|
+
} catch {
|
|
2615
|
+
return new Error("Connection unavailable");
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2323
2618
|
var airtable = /* @__PURE__ */ createConnections(async (name2, operation2, input) => {
|
|
2324
2619
|
throw new AirtableOperationError("Airtable connection unavailable");
|
|
2325
2620
|
});
|
|
@@ -2327,7 +2622,7 @@ function runtimeConnections() {
|
|
|
2327
2622
|
return {
|
|
2328
2623
|
...airtable,
|
|
2329
2624
|
async get(identity) {
|
|
2330
|
-
throw
|
|
2625
|
+
throw connectionFailure(identity);
|
|
2331
2626
|
}
|
|
2332
2627
|
};
|
|
2333
2628
|
}
|
|
@@ -2452,8 +2747,7 @@ var operations = {
|
|
|
2452
2747
|
"items.listRecipientCandidates": ["itemId"],
|
|
2453
2748
|
"items.addRecipient": ["itemId", "personId"],
|
|
2454
2749
|
"questions.answer": ["itemId", "revision", "questionId", "response"],
|
|
2455
|
-
"questions.searchRecords": ["itemId", "revision", "questionId", "query"]
|
|
2456
|
-
"files.read": ["itemId", "fileId"]
|
|
2750
|
+
"questions.searchRecords": ["itemId", "revision", "questionId", "query"]
|
|
2457
2751
|
};
|
|
2458
2752
|
function assert(value) {
|
|
2459
2753
|
if (!value) throw new Error("Invalid Inbox result");
|
|
@@ -3259,34 +3553,6 @@ async function send2(operation2, input, admitted) {
|
|
|
3259
3553
|
if (response2.status !== 200)
|
|
3260
3554
|
throw response2.body?.cancel().catch(() => {
|
|
3261
3555
|
}), unavailable3();
|
|
3262
|
-
if (operation2 === "files.read") {
|
|
3263
|
-
if (!response2.body) throw unavailable3();
|
|
3264
|
-
let source2 = response2.body, reader, size = 0, cancel = async (reason) => {
|
|
3265
|
-
try {
|
|
3266
|
-
await (reader ? reader.cancel(reason) : source2.cancel(reason));
|
|
3267
|
-
} finally {
|
|
3268
|
-
reader?.releaseLock();
|
|
3269
|
-
}
|
|
3270
|
-
}, body = new ReadableStream({
|
|
3271
|
-
async pull(controller) {
|
|
3272
|
-
try {
|
|
3273
|
-
check(), reader ??= source2.getReader();
|
|
3274
|
-
let next = await reader.read();
|
|
3275
|
-
if (check(), next.done) {
|
|
3276
|
-
reader.releaseLock(), controller.close();
|
|
3277
|
-
return;
|
|
3278
|
-
}
|
|
3279
|
-
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw unavailable3();
|
|
3280
|
-
controller.enqueue(next.value);
|
|
3281
|
-
} catch (error) {
|
|
3282
|
-
controller.error(error), await cancel(error).catch(() => {
|
|
3283
|
-
});
|
|
3284
|
-
}
|
|
3285
|
-
},
|
|
3286
|
-
cancel
|
|
3287
|
-
}, { highWaterMark: 0 });
|
|
3288
|
-
return new Response(body, { status: response2.status, headers: response2.headers });
|
|
3289
|
-
}
|
|
3290
3556
|
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
3291
3557
|
if (check(), !bytes) throw unavailable3();
|
|
3292
3558
|
let value = JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)), parsed = parseInboxResult(operation2, value);
|
|
@@ -3365,8 +3631,7 @@ var inbox = {
|
|
|
3365
3631
|
},
|
|
3366
3632
|
answer: async (input) => await send2("questions.answer", input),
|
|
3367
3633
|
searchRecords: async (input) => await send2("questions.searchRecords", input)
|
|
3368
|
-
}
|
|
3369
|
-
files: { read: async (input) => await send2("files.read", input) }
|
|
3634
|
+
}
|
|
3370
3635
|
};
|
|
3371
3636
|
|
|
3372
3637
|
var sources = /* @__PURE__ */ new WeakMap();
|
|
@@ -3882,7 +4147,6 @@ function routineRunHandle(operations2) {
|
|
|
3882
4147
|
return Object.freeze({
|
|
3883
4148
|
current: operations2.current,
|
|
3884
4149
|
step: operations2.step,
|
|
3885
|
-
...operations2.publish ? { publish: operations2.publish } : {},
|
|
3886
4150
|
async *watch() {
|
|
3887
4151
|
let previous;
|
|
3888
4152
|
for (; ; ) {
|
|
@@ -3947,7 +4211,18 @@ function parseRemoteRun(value, expected = {}) {
|
|
|
3947
4211
|
};
|
|
3948
4212
|
}
|
|
3949
4213
|
|
|
3950
|
-
var identifier = /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/, uuid2 = /^[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,
|
|
4214
|
+
var identifier = /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/, uuid2 = /^[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, dataErrorCodes = /* @__PURE__ */ new Set([
|
|
4215
|
+
"context_unavailable",
|
|
4216
|
+
"unauthenticated",
|
|
4217
|
+
"access_denied",
|
|
4218
|
+
"invalid_query",
|
|
4219
|
+
"request_too_large",
|
|
4220
|
+
"capacity",
|
|
4221
|
+
"unavailable",
|
|
4222
|
+
"invalid_change",
|
|
4223
|
+
"conflict",
|
|
4224
|
+
"apply_pending"
|
|
4225
|
+
]), SUMMARY_BYTES = 17 * 1024 * 1024, AppRoutineError = class extends Error {
|
|
3951
4226
|
constructor(reason) {
|
|
3952
4227
|
super(reason);
|
|
3953
4228
|
this.reason = reason;
|
|
@@ -4013,7 +4288,7 @@ function summary(value, key, context, id3) {
|
|
|
4013
4288
|
return fail3("execution_unavailable");
|
|
4014
4289
|
}
|
|
4015
4290
|
let run = value;
|
|
4016
|
-
return (!only(run, "id,routine,placement,status,createdAt,startedAt,finishedAt,steps,result,failure,
|
|
4291
|
+
return (!only(run, "id,routine,placement,status,createdAt,startedAt,finishedAt,steps,result,failure,local") || typeof run.id != "string" || !uuid2.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" || !bounded2(run.result)) || run.failure !== void 0 && (run.status !== "failed" || !only(run.failure, "message") || !message(run.failure.message)) || run.local !== void 0 && !validLocalActivity(run.local)) && fail3("execution_unavailable"), run;
|
|
4017
4292
|
}
|
|
4018
4293
|
function only(value, allowed) {
|
|
4019
4294
|
return !!value && typeof value == "object" && !Array.isArray(value) && Object.keys(value).every((key) => allowed.split(",").includes(key));
|
|
@@ -4025,8 +4300,15 @@ function optionalTimes(value) {
|
|
|
4025
4300
|
function validStep(step) {
|
|
4026
4301
|
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") || bounded2(step.summary)) && (!Object.hasOwn(step, "data") || bounded2(step.data));
|
|
4027
4302
|
}
|
|
4028
|
-
function
|
|
4029
|
-
|
|
4303
|
+
function validLocalActivity(value) {
|
|
4304
|
+
let paths = (value2) => Array.isArray(value2) && value2.every((path) => typeof path == "string" && path.length > 0 && path.length <= 4096 && !path.startsWith("/") && !path.includes("\\") && !path.split("/").some((part) => !part || part === "." || part === "..") && !/[\x00-\x1f\x7f]/.test(path));
|
|
4305
|
+
return value && only(value, "data,effects,git") && bounded2(value) && Array.isArray(value.data) && Array.isArray(value.effects) && value.data.every((item) => only(item, "repository,created,updated,deleted,failures,failure") && typeof item.repository == "string" && identifier.test(item.repository) && paths(item.created) && paths(item.updated) && paths(item.deleted) && (item.failures === void 0 || Array.isArray(item.failures) && item.failures.every((code) => typeof code == "string" && dataErrorCodes.has(code))) && (item.failure === void 0 || (() => {
|
|
4306
|
+
try {
|
|
4307
|
+
return parseDataFailureDetail(item.failure), !0;
|
|
4308
|
+
} catch {
|
|
4309
|
+
return !1;
|
|
4310
|
+
}
|
|
4311
|
+
})())) && value.effects.every((item) => only(item, "capability,operation,status,reference,summary") && ["files", "inbox", "ai"].includes(item.capability) && typeof item.operation == "string" && /^[a-zA-Z][a-zA-Z0-9-]{0,62}$/.test(item.operation) && ["completed", "failed"].includes(item.status) && (item.reference === void 0 || typeof item.reference == "string" && uuid2.test(item.reference)) && (!Object.hasOwn(item, "summary") || bounded2(item.summary))) && (value.git === void 0 || only(value.git, "branch,commit,dirty") && typeof value.git.dirty == "boolean" && (value.git.branch === void 0 || typeof value.git.branch == "string" && value.git.branch.length <= 256 && !/[\x00-\x1f\x7f]/.test(value.git.branch)) && (value.git.commit === void 0 || typeof value.git.commit == "string" && /^[0-9a-f]{40}$/.test(value.git.commit)));
|
|
4030
4312
|
}
|
|
4031
4313
|
function jsonInput(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
4032
4314
|
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return;
|
|
@@ -4062,9 +4344,6 @@ function handle(key, id3, context) {
|
|
|
4062
4344
|
return fail3("execution_unavailable");
|
|
4063
4345
|
}
|
|
4064
4346
|
return (!only(value, "id,title,status,startedAt,finishedAt,summary,data") || value.id !== step || !validStep(value)) && fail3("execution_unavailable"), value;
|
|
4065
|
-
},
|
|
4066
|
-
async publish() {
|
|
4067
|
-
return context.kind !== "local" && fail3("execution_unavailable"), summary(await request(key, `runs/${id3}/publish`, { method: "POST" }, SUMMARY_BYTES, context), key, context, id3);
|
|
4068
4347
|
}
|
|
4069
4348
|
});
|
|
4070
4349
|
}
|
|
@@ -4144,21 +4423,31 @@ var app = /* @__PURE__ */ Object.freeze({
|
|
|
4144
4423
|
})
|
|
4145
4424
|
});
|
|
4146
4425
|
|
|
4147
|
-
function
|
|
4148
|
-
let
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4426
|
+
async function requestInboxPublication(operation2, request2, caller) {
|
|
4427
|
+
let attempt = () => {
|
|
4428
|
+
if (caller?.aborted) throw caller.reason;
|
|
4429
|
+
let timeout = AbortSignal.timeout(3e4);
|
|
4430
|
+
return request2(caller ? AbortSignal.any([caller, timeout]) : timeout);
|
|
4431
|
+
};
|
|
4432
|
+
if (operation2 !== "publish") return attempt();
|
|
4433
|
+
try {
|
|
4434
|
+
let response2 = await attempt();
|
|
4435
|
+
if (response2.status !== 408 && response2.status !== 429 && response2.status < 500) return response2;
|
|
4436
|
+
await response2.body?.cancel();
|
|
4437
|
+
} catch (error) {
|
|
4438
|
+
if (caller?.aborted) throw error;
|
|
4439
|
+
}
|
|
4440
|
+
if (caller?.aborted) throw caller.reason;
|
|
4441
|
+
return attempt();
|
|
4153
4442
|
}
|
|
4154
4443
|
|
|
4155
4444
|
function routinePublicationClient2(options = {}) {
|
|
4156
|
-
let environment = {}, installed2 = routineTransport(), local2 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.OS_ROUTINE_WORKSPACE, capability = options.capability ?? environment.OS_ROUTINE_RUN;
|
|
4445
|
+
let environment = {}, installed2 = options.request ? void 0 : routineTransport(), local2 = options.request ? void 0 : installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.OS_ROUTINE_WORKSPACE, capability = options.capability ?? (options.request ? void 0 : environment.OS_ROUTINE_RUN);
|
|
4157
4446
|
if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
|
|
4158
4447
|
throw new Error("A workspace and valid optional routine capability are required");
|
|
4159
|
-
let
|
|
4448
|
+
let headers = capability ? { "x-os-run": capability } : {}, request2 = options.request ?? (capability ? async (path, init2) => {
|
|
4160
4449
|
let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
|
|
4161
|
-
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
|
|
4450
|
+
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)$/.test(path) || init2?.method !== "POST")
|
|
4162
4451
|
throw new Error("Invalid routine endpoint");
|
|
4163
4452
|
return fetch(target, { ...init2, redirect: "error" });
|
|
4164
4453
|
} : async () => {
|
|
@@ -4166,11 +4455,12 @@ function routinePublicationClient2(options = {}) {
|
|
|
4166
4455
|
});
|
|
4167
4456
|
async function send3(operation2, body) {
|
|
4168
4457
|
if (local2) return await local2(operation2, body);
|
|
4169
|
-
let response2 = await request2(`/api/inbox/${operation2}`, {
|
|
4458
|
+
let response2 = await requestInboxPublication(operation2, (signal) => request2(`/api/inbox/${operation2}`, {
|
|
4170
4459
|
method: "POST",
|
|
4171
4460
|
headers: { "content-type": "application/json", ...headers },
|
|
4172
|
-
body: JSON.stringify(body)
|
|
4173
|
-
|
|
4461
|
+
body: JSON.stringify(body),
|
|
4462
|
+
signal
|
|
4463
|
+
})), result2 = await response2.json();
|
|
4174
4464
|
if (!response2.ok) throw new Error(result2.error ?? "Could not confirm routine publication");
|
|
4175
4465
|
return result2;
|
|
4176
4466
|
}
|
|
@@ -4183,19 +4473,13 @@ function routinePublicationClient2(options = {}) {
|
|
|
4183
4473
|
await send3("resolve", body);
|
|
4184
4474
|
}
|
|
4185
4475
|
}),
|
|
4186
|
-
files: {
|
|
4187
|
-
async add(value) {
|
|
4188
|
-
let input = validateFileAddOptions(value);
|
|
4189
|
-
if (local2) return validateInboxFile(await local2("files/add", input));
|
|
4190
|
-
throw workingRoot ? new Error("Inbox file reads require a Node working root") : new Error("Inbox file reads require a working root");
|
|
4191
|
-
}
|
|
4192
|
-
},
|
|
4193
4476
|
async check(body) {
|
|
4194
|
-
await send3("check", { requestKey: body.requestKey, item: validatePublication(body.item) });
|
|
4477
|
+
await send3("check", { requestKey: body.requestKey, item: enforcePublicationSize(validatePublication(body.item)) });
|
|
4195
4478
|
}
|
|
4196
4479
|
};
|
|
4197
4480
|
}
|
|
4198
4481
|
export {
|
|
4482
|
+
AIError,
|
|
4199
4483
|
AirtableOperationError,
|
|
4200
4484
|
AppRoutineError,
|
|
4201
4485
|
BrowserAuthError,
|
|
@@ -4203,7 +4487,7 @@ export {
|
|
|
4203
4487
|
FileOperationError,
|
|
4204
4488
|
InboxContractError,
|
|
4205
4489
|
InboxOperationError,
|
|
4206
|
-
RoutineAIError,
|
|
4490
|
+
AIError as RoutineAIError,
|
|
4207
4491
|
app,
|
|
4208
4492
|
asksBlock,
|
|
4209
4493
|
auth,
|