@oddington/sdk 0.1.38 → 0.1.40
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 +152 -39
- package/dist/browser.js +413 -106
- package/dist/index.js +9 -4
- package/dist/types/packages/sdk/src/public.d.ts +4 -2
- 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/routine-ai-contract.d.ts +5 -3
- package/package.json +1 -1
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;
|
|
@@ -271,7 +272,22 @@ var InboxContractError = class extends Error {
|
|
|
271
272
|
constructor(message2) {
|
|
272
273
|
super(message2), this.name = "InboxContractError";
|
|
273
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;
|
|
274
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
|
+
}
|
|
275
291
|
function fail(message2) {
|
|
276
292
|
throw new InboxContractError(message2);
|
|
277
293
|
}
|
|
@@ -612,7 +628,7 @@ function createInboxPublisher(transport) {
|
|
|
612
628
|
keys(source2, ["title", "description", "recipients", "views", "body", "questions", "notifyImmediately", "tags", "recordRefs"], "ask");
|
|
613
629
|
let result2 = await transport.publish({
|
|
614
630
|
requestKey: publicationRequestKey(options),
|
|
615
|
-
item: validatePublication({ ...source2, kind: "ask" })
|
|
631
|
+
item: enforcePublicationSize(validatePublication({ ...source2, kind: "ask" }))
|
|
616
632
|
});
|
|
617
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 };
|
|
618
634
|
},
|
|
@@ -621,7 +637,7 @@ function createInboxPublisher(transport) {
|
|
|
621
637
|
keys(source2, ["title", "description", "recipients", "views", "body", "notifyImmediately"], "digest");
|
|
622
638
|
let result2 = await transport.publish({
|
|
623
639
|
requestKey: publicationRequestKey(options),
|
|
624
|
-
item: validatePublication({ ...source2, kind: "digest" })
|
|
640
|
+
item: enforcePublicationSize(validatePublication({ ...source2, kind: "digest" }))
|
|
625
641
|
});
|
|
626
642
|
return { id: id(result2.id, "published digest ID") };
|
|
627
643
|
},
|
|
@@ -774,12 +790,12 @@ function routineAIOutputMessage(issue) {
|
|
|
774
790
|
}
|
|
775
791
|
|
|
776
792
|
var ROUTINE_AI_VALUE_BYTES = 256 * 1024, ROUTINE_AI_RESULT_BYTES = 6 * ROUTINE_AI_VALUE_BYTES + 1024, ROUTINE_AI_EVIDENCE_BYTES = 4 * 1024;
|
|
777
|
-
var
|
|
793
|
+
var AIError = class extends Error {
|
|
778
794
|
constructor(code, options = {}) {
|
|
779
795
|
let detail = code === "invalid_output" ? parseRoutineAIOutputIssue(options.detail) : void 0;
|
|
780
796
|
super(detail ? routineAIOutputMessage(detail) : code);
|
|
781
797
|
this.code = code;
|
|
782
|
-
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 });
|
|
783
799
|
}
|
|
784
800
|
code;
|
|
785
801
|
detail;
|
|
@@ -788,10 +804,10 @@ function capture(value, invalid9, oversized, limit = ROUTINE_AI_VALUE_BYTES) {
|
|
|
788
804
|
try {
|
|
789
805
|
assertRoutineJson(value);
|
|
790
806
|
let encoded = JSON.stringify(value);
|
|
791
|
-
if (new TextEncoder().encode(encoded).byteLength > limit) throw new
|
|
807
|
+
if (new TextEncoder().encode(encoded).byteLength > limit) throw new AIError(oversized);
|
|
792
808
|
return freezeRoutineMetadata(JSON.parse(encoded));
|
|
793
809
|
} catch (error) {
|
|
794
|
-
throw error instanceof
|
|
810
|
+
throw error instanceof AIError ? error : new AIError(invalid9);
|
|
795
811
|
}
|
|
796
812
|
}
|
|
797
813
|
function parseRoutineAIRequest(value) {
|
|
@@ -803,7 +819,7 @@ function parseRoutineAIRequest(value) {
|
|
|
803
819
|
let schema2 = parseAppRoutineContract({ routine: "ai", input: v.schema, steps: [{ id: "generate" }] }).input;
|
|
804
820
|
return freezeRoutineMetadata({ kind: v.kind, instructions: v.instructions, input, schema: schema2 });
|
|
805
821
|
} catch {
|
|
806
|
-
throw new
|
|
822
|
+
throw new AIError("invalid_input");
|
|
807
823
|
}
|
|
808
824
|
}
|
|
809
825
|
function parseRoutineAIResult(request2, value) {
|
|
@@ -820,7 +836,7 @@ function parseRoutineAIResult(request2, value) {
|
|
|
820
836
|
}
|
|
821
837
|
if (!Object.hasOwn(v, "object")) throw new Error();
|
|
822
838
|
} catch (error) {
|
|
823
|
-
throw error instanceof
|
|
839
|
+
throw error instanceof AIError ? error : new AIError("invalid_output", { detail: { reason: "invalid_response" } });
|
|
824
840
|
}
|
|
825
841
|
return validateObject(request2.schema, v.object), freezeRoutineMetadata({ object: v.object });
|
|
826
842
|
}
|
|
@@ -831,20 +847,20 @@ function validateObject(schema2, object5, text5) {
|
|
|
831
847
|
detail = issue;
|
|
832
848
|
});
|
|
833
849
|
} catch {
|
|
834
|
-
throw new
|
|
850
|
+
throw new AIError("invalid_output", { ...text5 === void 0 ? {} : { text: text5 }, detail });
|
|
835
851
|
}
|
|
836
852
|
}
|
|
837
853
|
function acceptText(request2, text5) {
|
|
838
|
-
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");
|
|
839
855
|
if (request2.kind === "generateText") {
|
|
840
|
-
if (!text5.trim()) throw new
|
|
856
|
+
if (!text5.trim()) throw new AIError("invalid_output", { text: text5, detail: { reason: "empty_text" } });
|
|
841
857
|
return freezeRoutineMetadata({ text: text5 });
|
|
842
858
|
}
|
|
843
|
-
let object5;
|
|
859
|
+
let object5, trimmed = text5.trim(), fenced = /^(`{3,}|~{3,})(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n\1[ \t]*$/i.exec(trimmed);
|
|
844
860
|
try {
|
|
845
|
-
object5 = JSON.parse(text5);
|
|
861
|
+
object5 = JSON.parse(fenced ? fenced[2] : text5);
|
|
846
862
|
} catch {
|
|
847
|
-
throw new
|
|
863
|
+
throw new AIError("invalid_output", { text: text5, detail: { reason: "invalid_json" } });
|
|
848
864
|
}
|
|
849
865
|
return validateObject(request2.schema, object5, text5), capture({ object: object5 }, "invalid_output", "output_too_large");
|
|
850
866
|
}
|
|
@@ -854,10 +870,10 @@ var LIMIT = 256 * 1024, invalid3 = () => {
|
|
|
854
870
|
}, invalidContract3 = () => {
|
|
855
871
|
throw new AppRoutineContractError("invalid_contract");
|
|
856
872
|
}, empty = { type: "object", properties: {}, required: [], additionalProperties: !1 };
|
|
857
|
-
function captureJson(value) {
|
|
873
|
+
function captureJson(value, maximum = LIMIT) {
|
|
858
874
|
assertRoutineJson(value);
|
|
859
875
|
let encoded = JSON.stringify(value);
|
|
860
|
-
return new TextEncoder().encode(encoded).byteLength >
|
|
876
|
+
return maximum !== null && new TextEncoder().encode(encoded).byteLength > maximum ? invalid3() : freezeRoutineMetadata(JSON.parse(encoded));
|
|
861
877
|
}
|
|
862
878
|
function capture2(schema2, value) {
|
|
863
879
|
let captured = captureJson(value);
|
|
@@ -975,8 +991,8 @@ function captureRoutineInput(definition, input) {
|
|
|
975
991
|
async function executeRoutineDefinition(definition, input, runtime) {
|
|
976
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) => {
|
|
977
993
|
let operation2 = (async () => {
|
|
978
|
-
if (!active2 || broken || contract.access.ai !== !0) throw new
|
|
979
|
-
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");
|
|
980
996
|
let request2;
|
|
981
997
|
try {
|
|
982
998
|
assertRoutineFields(value, kind === "generateObject" ? ["instructions", "input", "schema"] : ["instructions", "input"]), request2 = parseRoutineAIRequest({
|
|
@@ -986,10 +1002,10 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
986
1002
|
...kind === "generateObject" ? { schema: schemaMetadata(value.schema).schema } : {}
|
|
987
1003
|
});
|
|
988
1004
|
} catch (error) {
|
|
989
|
-
throw error instanceof
|
|
1005
|
+
throw error instanceof AIError ? error : new AIError("invalid_input");
|
|
990
1006
|
}
|
|
991
1007
|
let result3 = await runtime.ai[kind](request2);
|
|
992
|
-
if (!active2 || broken) throw new
|
|
1008
|
+
if (!active2 || broken) throw new AIError("access_denied");
|
|
993
1009
|
return parseRoutineAIResult(request2, result3);
|
|
994
1010
|
})();
|
|
995
1011
|
return aiWork.add(operation2), operation2.then(() => aiWork.delete(operation2), () => aiWork.delete(operation2)), operation2;
|
|
@@ -1025,7 +1041,7 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
1025
1041
|
let saved;
|
|
1026
1042
|
try {
|
|
1027
1043
|
if (!active2 || !accepting || broken || !Object.hasOwn(steps, id3) || called.has(id3) || input2.length > 1) return invalid3();
|
|
1028
|
-
input2.length && (saved = captureJson(input2[0])), called.add(id3);
|
|
1044
|
+
input2.length && (saved = captureJson(input2[0], null)), called.add(id3);
|
|
1029
1045
|
} catch (error) {
|
|
1030
1046
|
return broken = !0, Promise.reject(error);
|
|
1031
1047
|
}
|
|
@@ -1061,26 +1077,171 @@ async function executeRoutineDefinition(definition, input, runtime) {
|
|
|
1061
1077
|
if (result2 !== void 0) return invalid3();
|
|
1062
1078
|
}
|
|
1063
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
|
+
}
|
|
1064
1225
|
var DataOperationError = class extends Error {
|
|
1065
|
-
constructor(code, retryable = !1, effect, component) {
|
|
1066
|
-
|
|
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}`);
|
|
1067
1231
|
this.code = code;
|
|
1068
1232
|
this.retryable = retryable;
|
|
1069
1233
|
this.effect = effect;
|
|
1070
1234
|
this.component = component;
|
|
1071
|
-
this.
|
|
1235
|
+
this.detail = detail;
|
|
1236
|
+
this.name = "DataOperationError", parsed !== void 0 && (this.detail = parsed);
|
|
1072
1237
|
}
|
|
1073
1238
|
code;
|
|
1074
1239
|
retryable;
|
|
1075
1240
|
effect;
|
|
1076
1241
|
component;
|
|
1242
|
+
detail;
|
|
1077
1243
|
};
|
|
1078
1244
|
|
|
1079
|
-
var RECORD_READ_INPUT_LIMIT = 1024 * 1024, RECORD_CAPTURE_OUTPUT_LIMIT = 25 * 1024 * 1024;
|
|
1080
|
-
function validRecordRef(value) {
|
|
1081
|
-
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);
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
1245
|
var invalid4 = () => {
|
|
1085
1246
|
throw new DataOperationError("invalid_query");
|
|
1086
1247
|
}, historyText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
|
|
@@ -1174,8 +1335,24 @@ function captureRecordsReadRefs(value) {
|
|
|
1174
1335
|
throw new DataOperationError("invalid_query");
|
|
1175
1336
|
return refs;
|
|
1176
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
|
+
}
|
|
1177
1349
|
|
|
1178
|
-
|
|
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 = () => {
|
|
1179
1356
|
throw new DataOperationError("invalid_change", !1, "unapplied");
|
|
1180
1357
|
};
|
|
1181
1358
|
function mapping(value) {
|
|
@@ -1200,16 +1377,16 @@ function captureDataDelete(record4) {
|
|
|
1200
1377
|
return !validRecordRef(identity.$ref) || typeof identity.$version != "string" || !identity.$version.length || identity.$version.length > 512 ? invalidChange() : { ref: identity.$ref, expectedVersion: identity.$version };
|
|
1201
1378
|
}
|
|
1202
1379
|
function captureDataUpdate(record4, set) {
|
|
1203
|
-
let identity = captureDataDelete(record4),
|
|
1204
|
-
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 } : {} };
|
|
1205
1382
|
}
|
|
1206
1383
|
function captureIdentities(value, update, allowEmpty = !0) {
|
|
1207
1384
|
if (!Array.isArray(value) || !allowEmpty && !value.length || value.length > 1e4) return invalidChange();
|
|
1208
1385
|
let captured = value.map((item) => {
|
|
1209
1386
|
let row = mapping(item);
|
|
1210
|
-
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();
|
|
1211
1388
|
let identity = { $ref: row.ref, $version: row.expectedVersion };
|
|
1212
|
-
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);
|
|
1213
1390
|
});
|
|
1214
1391
|
return new Set(captured.map((item) => item.ref)).size !== captured.length ? invalidChange() : captured;
|
|
1215
1392
|
}
|
|
@@ -1218,30 +1395,37 @@ function captureDataUpdates(value, allowEmpty = !1) {
|
|
|
1218
1395
|
}
|
|
1219
1396
|
function captureDataCreate(value) {
|
|
1220
1397
|
let row = mapping(value);
|
|
1221
|
-
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)))
|
|
1222
1399
|
return invalidChange();
|
|
1223
|
-
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;
|
|
1224
1403
|
if ($filing !== void 0) {
|
|
1225
1404
|
let components = mapping($filing);
|
|
1226
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)))
|
|
1227
1406
|
return invalidChange();
|
|
1228
1407
|
filing = { ...components };
|
|
1229
1408
|
}
|
|
1230
|
-
return { ref, fields: captureValue(fields5), ...filing ? { filing } : {} };
|
|
1409
|
+
return { ref, fields: captureValue(fields5), ...filing ? { filing } : {}, ...body ? { body: $body } : {} };
|
|
1231
1410
|
}
|
|
1232
1411
|
function captureDataChanges(updatesValue, createsValue = [], deletesValue = []) {
|
|
1233
1412
|
let updates = captureDataUpdates(updatesValue, !0);
|
|
1234
1413
|
if (!Array.isArray(createsValue) || createsValue.length > 1e4) return invalidChange();
|
|
1235
1414
|
let creates = createsValue.map((item) => {
|
|
1236
1415
|
let row = mapping(item);
|
|
1237
|
-
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();
|
|
1238
1417
|
let fields5 = mapping(row.fields);
|
|
1239
|
-
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
|
+
});
|
|
1240
1424
|
}), deletes = captureIdentities(deletesValue, !1), refs = [...updates, ...creates, ...deletes].map((item) => item.ref);
|
|
1241
1425
|
return !refs.length || refs.length > 1e4 || new Set(refs).size !== refs.length ? invalidChange() : { updates, creates, deletes };
|
|
1242
1426
|
}
|
|
1243
|
-
function checkDataRequestSize(input) {
|
|
1244
|
-
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)
|
|
1245
1429
|
throw new DataOperationError("request_too_large", !1, "unapplied");
|
|
1246
1430
|
}
|
|
1247
1431
|
function dataTransportError(status, value) {
|
|
@@ -1249,17 +1433,22 @@ function dataTransportError(status, value) {
|
|
|
1249
1433
|
400: ["invalid_query", "invalid_change"],
|
|
1250
1434
|
401: ["unauthenticated"],
|
|
1251
1435
|
403: ["access_denied"],
|
|
1252
|
-
409: ["conflict", "
|
|
1436
|
+
409: ["conflict", "apply_pending"],
|
|
1253
1437
|
413: ["request_too_large"],
|
|
1254
1438
|
429: ["capacity"],
|
|
1255
|
-
503: ["unavailable", "
|
|
1256
|
-
}, 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;
|
|
1257
|
-
|
|
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(
|
|
1258
1446
|
code,
|
|
1259
|
-
["capacity", "unavailable", "
|
|
1447
|
+
typeof row?.retryable == "boolean" ? row.retryable : ["capacity", "unavailable", "apply_pending"].includes(code),
|
|
1260
1448
|
code === "conflict" ? "unapplied" : effect,
|
|
1261
|
-
code === "invalid_change" && typeof row?.component == "string" && /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(row.component) ? row.component : void 0
|
|
1262
|
-
|
|
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);
|
|
1263
1452
|
}
|
|
1264
1453
|
|
|
1265
1454
|
var installed, ended = !1;
|
|
@@ -1409,12 +1598,21 @@ function recordPagination(select) {
|
|
|
1409
1598
|
async function all(query, options) {
|
|
1410
1599
|
let properties = historyProperties(options), maxRecords = properties.maxRecords?.value;
|
|
1411
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
|
+
}
|
|
1412
1606
|
let result2, total = 0;
|
|
1413
|
-
for await (let page of pages(
|
|
1414
|
-
let
|
|
1415
|
-
if (size > maxRecords - total) throw new DataOperationError("capacity"
|
|
1416
|
-
|
|
1417
|
-
|
|
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) {
|
|
1418
1616
|
let target = result2[name2];
|
|
1419
1617
|
for (let record4 of page[name2]) target.push(record4);
|
|
1420
1618
|
}
|
|
@@ -1428,8 +1626,8 @@ function recordPagination(select) {
|
|
|
1428
1626
|
var genericData = {
|
|
1429
1627
|
repository(repository) {
|
|
1430
1628
|
async function send3(input) {
|
|
1431
|
-
let context = await resolveDataContext(), envelope = { repository, ...input };
|
|
1432
|
-
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);
|
|
1433
1631
|
try {
|
|
1434
1632
|
let response2 = await fetch(context.url, {
|
|
1435
1633
|
method: "POST",
|
|
@@ -1445,8 +1643,8 @@ var genericData = {
|
|
|
1445
1643
|
throw error instanceof DataOperationError ? error : new DataOperationError("unavailable", !0);
|
|
1446
1644
|
}
|
|
1447
1645
|
}
|
|
1448
|
-
async function read2(input) {
|
|
1449
|
-
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 } });
|
|
1450
1648
|
return typeof input == "string" ? result2.records[0] : result2;
|
|
1451
1649
|
}
|
|
1452
1650
|
let select = (query) => send3({ operation: "records.select", query });
|
|
@@ -1467,16 +1665,16 @@ var genericData = {
|
|
|
1467
1665
|
changes: async (options) => send3({ operation: "history.changes", options: captureHistoryChangesOptions(options) })
|
|
1468
1666
|
},
|
|
1469
1667
|
changes() {
|
|
1470
|
-
let updates = [], creates = [], deletes = [],
|
|
1471
|
-
if (
|
|
1668
|
+
let updates = [], creates = [], deletes = [], applyId, pending, confirmed, assertMutable = () => {
|
|
1669
|
+
if (applyId) throw new DataOperationError("invalid_change", !1, "unapplied");
|
|
1472
1670
|
}, snapshot = (nextUpdates = updates, nextCreates = creates, nextDeletes = deletes) => {
|
|
1473
1671
|
let { updates: updates2, creates: creates2, deletes: deletes2 } = captureDataChanges(nextUpdates, nextCreates, nextDeletes), input = { updates: updates2, ...creates2.length ? { creates: creates2 } : {}, ...deletes2.length ? { deletes: deletes2 } : {} };
|
|
1474
1672
|
return checkDataRequestSize({
|
|
1475
1673
|
repository,
|
|
1476
|
-
operation: "changes.
|
|
1674
|
+
operation: "changes.apply",
|
|
1477
1675
|
...input,
|
|
1478
|
-
|
|
1479
|
-
}), input;
|
|
1676
|
+
applyId: applyId ?? "00000000-0000-4000-8000-000000000000"
|
|
1677
|
+
}, LOCAL_DATA_CHANGE_REQUEST_LIMIT), input;
|
|
1480
1678
|
};
|
|
1481
1679
|
return {
|
|
1482
1680
|
create(record4) {
|
|
@@ -1497,7 +1695,7 @@ var genericData = {
|
|
|
1497
1695
|
async validate() {
|
|
1498
1696
|
await send3({ operation: "changes.validate", ...snapshot() });
|
|
1499
1697
|
},
|
|
1500
|
-
|
|
1698
|
+
apply() {
|
|
1501
1699
|
if (confirmed) return Promise.resolve(structuredClone(confirmed));
|
|
1502
1700
|
if (!pending) {
|
|
1503
1701
|
let captured;
|
|
@@ -1506,13 +1704,14 @@ var genericData = {
|
|
|
1506
1704
|
} catch (error) {
|
|
1507
1705
|
return Promise.reject(error);
|
|
1508
1706
|
}
|
|
1509
|
-
|
|
1510
|
-
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(
|
|
1511
1709
|
error.code,
|
|
1512
1710
|
error.retryable,
|
|
1513
|
-
error.effect ?? (["unavailable", "
|
|
1514
|
-
error.component
|
|
1515
|
-
|
|
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");
|
|
1516
1715
|
}).finally(() => {
|
|
1517
1716
|
pending = void 0;
|
|
1518
1717
|
});
|
|
@@ -1583,7 +1782,7 @@ async function hostedContent(url, init2, parent, upstream = fetch, check = async
|
|
|
1583
1782
|
}
|
|
1584
1783
|
}
|
|
1585
1784
|
|
|
1586
|
-
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 = {
|
|
1587
1786
|
400: ["invalid_input", "unsupported_context"],
|
|
1588
1787
|
401: ["unauthenticated"],
|
|
1589
1788
|
403: ["access_denied"],
|
|
@@ -1593,6 +1792,41 @@ var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES =
|
|
|
1593
1792
|
429: ["capacity"],
|
|
1594
1793
|
503: ["integrity", "unavailable"]
|
|
1595
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
|
+
}
|
|
1596
1830
|
async function boundedBytes(stream, limit, signal) {
|
|
1597
1831
|
if (!stream) return new Uint8Array();
|
|
1598
1832
|
let reader = stream.getReader(), bytes = new Uint8Array(limit), size = 0, cancel = () => {
|
|
@@ -1702,9 +1936,7 @@ function idPath(id3) {
|
|
|
1702
1936
|
if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid7();
|
|
1703
1937
|
return `/${id3}`;
|
|
1704
1938
|
}
|
|
1705
|
-
async function multipartCreate(input, metadata, exchange, release
|
|
1706
|
-
active--;
|
|
1707
|
-
}, upload) {
|
|
1939
|
+
async function multipartCreate(input, metadata, exchange, release, upload, expectedSha256) {
|
|
1708
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) => {
|
|
1709
1941
|
let task = work(signal);
|
|
1710
1942
|
return pending.add(task), task.then(() => pending.delete(task), () => pending.delete(task)), task;
|
|
@@ -1714,7 +1946,9 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1714
1946
|
body: JSON.stringify(body)
|
|
1715
1947
|
});
|
|
1716
1948
|
try {
|
|
1717
|
-
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));
|
|
1718
1952
|
if (!start || typeof start != "object" || Array.isArray(start)) throw unavailable2();
|
|
1719
1953
|
let session = start;
|
|
1720
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();
|
|
@@ -1795,16 +2029,13 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1795
2029
|
}
|
|
1796
2030
|
}
|
|
1797
2031
|
async function operation(work, initial, parent) {
|
|
1798
|
-
let context = initial ?? await resolveFilesContext()
|
|
1799
|
-
if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
|
|
1800
|
-
active++;
|
|
1801
|
-
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) => {
|
|
1802
2033
|
try {
|
|
1803
2034
|
return await work(context, signal2);
|
|
1804
2035
|
} finally {
|
|
1805
|
-
|
|
2036
|
+
release();
|
|
1806
2037
|
}
|
|
1807
|
-
}
|
|
2038
|
+
};
|
|
1808
2039
|
return context.localFiles ? execute(signal ?? new AbortController().signal) : timed(execute, signal).catch((error) => {
|
|
1809
2040
|
throw error instanceof FileOperationError ? error : unavailable2();
|
|
1810
2041
|
});
|
|
@@ -1882,28 +2113,27 @@ var files = {
|
|
|
1882
2113
|
if (!context.local && !context.localFiles && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
|
|
1883
2114
|
let header = encodeURIComponent(JSON.stringify(metadata));
|
|
1884
2115
|
if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid7();
|
|
1885
|
-
|
|
1886
|
-
if (
|
|
1887
|
-
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({
|
|
1888
|
-
pull(controller) {
|
|
1889
|
-
if (offset === file2.byteLength) {
|
|
1890
|
-
controller.close();
|
|
1891
|
-
return;
|
|
1892
|
-
}
|
|
1893
|
-
let end = Math.min(offset + 256 * 1024, file2.byteLength);
|
|
1894
|
-
controller.enqueue(file2.subarray(offset, end)), offset = end;
|
|
1895
|
-
}
|
|
1896
|
-
}, { highWaterMark: 0 });
|
|
2116
|
+
let release = await acquireSlot(context.signal);
|
|
2117
|
+
if (context.localFiles && !routineTransport() && metadata.size > MAX_BYTES)
|
|
1897
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 });
|
|
1898
2129
|
return await send("", { method: "POST", headers: {
|
|
1899
2130
|
"content-type": "application/octet-stream",
|
|
1900
2131
|
"x-os-file": header
|
|
1901
2132
|
}, body }, !0, context, signal);
|
|
1902
2133
|
} finally {
|
|
1903
|
-
|
|
2134
|
+
release();
|
|
1904
2135
|
}
|
|
1905
|
-
|
|
1906
|
-
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) => {
|
|
1907
2137
|
try {
|
|
1908
2138
|
let bytes = array3 ? new Uint8Array(input.file) : await boundedBytes(
|
|
1909
2139
|
blob ? input.file.stream() : input.file,
|
|
@@ -1923,7 +2153,7 @@ var files = {
|
|
|
1923
2153
|
body: bytes.buffer
|
|
1924
2154
|
}, !0, context, signal);
|
|
1925
2155
|
} finally {
|
|
1926
|
-
|
|
2156
|
+
release();
|
|
1927
2157
|
}
|
|
1928
2158
|
}, context.signal).catch((error) => {
|
|
1929
2159
|
throw error instanceof FileOperationError ? error : unavailable2();
|
|
@@ -2316,16 +2546,75 @@ async function reportLocalRoutineEffect(value) {
|
|
|
2316
2546
|
await observer?.(value);
|
|
2317
2547
|
}
|
|
2318
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
|
+
|
|
2319
2581
|
var local;
|
|
2320
|
-
async function localLease(identity
|
|
2582
|
+
async function localLease(identity) {
|
|
2321
2583
|
let current2 = local;
|
|
2322
2584
|
if (!current2 || !current2.declared.includes(identity)) throw new Error("Connection unavailable");
|
|
2323
|
-
|
|
2324
|
-
|
|
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
|
+
}
|
|
2325
2606
|
if (local !== current2 || !lease || lease.runId !== current2.runId || `${lease.provider}/${lease.name}` !== identity)
|
|
2326
2607
|
throw new Error("Connection unavailable");
|
|
2327
2608
|
return parseConnectionLease(lease);
|
|
2328
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
|
+
}
|
|
2329
2618
|
var airtable = /* @__PURE__ */ createConnections(async (name2, operation2, input) => {
|
|
2330
2619
|
throw new AirtableOperationError("Airtable connection unavailable");
|
|
2331
2620
|
});
|
|
@@ -2333,7 +2622,7 @@ function runtimeConnections() {
|
|
|
2333
2622
|
return {
|
|
2334
2623
|
...airtable,
|
|
2335
2624
|
async get(identity) {
|
|
2336
|
-
throw
|
|
2625
|
+
throw connectionFailure(identity);
|
|
2337
2626
|
}
|
|
2338
2627
|
};
|
|
2339
2628
|
}
|
|
@@ -3922,7 +4211,18 @@ function parseRemoteRun(value, expected = {}) {
|
|
|
3922
4211
|
};
|
|
3923
4212
|
}
|
|
3924
4213
|
|
|
3925
|
-
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 {
|
|
3926
4226
|
constructor(reason) {
|
|
3927
4227
|
super(reason);
|
|
3928
4228
|
this.reason = reason;
|
|
@@ -4002,7 +4302,13 @@ function validStep(step) {
|
|
|
4002
4302
|
}
|
|
4003
4303
|
function validLocalActivity(value) {
|
|
4004
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));
|
|
4005
|
-
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") && 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) =>
|
|
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,durationMs,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.durationMs === void 0 || typeof item.durationMs == "number" && Number.isFinite(item.durationMs) && item.durationMs >= 0) && (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)));
|
|
4006
4312
|
}
|
|
4007
4313
|
function jsonInput(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
4008
4314
|
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return;
|
|
@@ -4168,11 +4474,12 @@ function routinePublicationClient2(options = {}) {
|
|
|
4168
4474
|
}
|
|
4169
4475
|
}),
|
|
4170
4476
|
async check(body) {
|
|
4171
|
-
await send3("check", { requestKey: body.requestKey, item: validatePublication(body.item) });
|
|
4477
|
+
await send3("check", { requestKey: body.requestKey, item: enforcePublicationSize(validatePublication(body.item)) });
|
|
4172
4478
|
}
|
|
4173
4479
|
};
|
|
4174
4480
|
}
|
|
4175
4481
|
export {
|
|
4482
|
+
AIError,
|
|
4176
4483
|
AirtableOperationError,
|
|
4177
4484
|
AppRoutineError,
|
|
4178
4485
|
BrowserAuthError,
|
|
@@ -4180,7 +4487,7 @@ export {
|
|
|
4180
4487
|
FileOperationError,
|
|
4181
4488
|
InboxContractError,
|
|
4182
4489
|
InboxOperationError,
|
|
4183
|
-
RoutineAIError,
|
|
4490
|
+
AIError as RoutineAIError,
|
|
4184
4491
|
app,
|
|
4185
4492
|
asksBlock,
|
|
4186
4493
|
auth,
|