@oddington/sdk 0.1.38 → 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/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 RoutineAIError = class extends Error {
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 = "RoutineAIError", 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 });
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 RoutineAIError(oversized);
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 RoutineAIError ? error : new RoutineAIError(invalid9);
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 RoutineAIError("invalid_input");
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 RoutineAIError ? error : new RoutineAIError("invalid_output", { detail: { reason: "invalid_response" } });
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 RoutineAIError("invalid_output", { ...text5 === void 0 ? {} : { text: text5 }, detail });
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 RoutineAIError("output_too_large");
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 RoutineAIError("invalid_output", { text: text5, detail: { reason: "empty_text" } });
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 RoutineAIError("invalid_output", { text: text5, detail: { reason: "invalid_json" } });
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 > LIMIT ? invalid3() : freezeRoutineMetadata(JSON.parse(encoded));
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 RoutineAIError("access_denied");
979
- if (!runtime.ai) throw new RoutineAIError("capability_unavailable");
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 RoutineAIError ? error : new RoutineAIError("invalid_input");
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 RoutineAIError("access_denied");
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
- super(`Data operation failed: ${code}`);
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.name = "DataOperationError";
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
- var DATA_REQUEST_LIMIT = 256 * 1024, invalidChange = () => {
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), fields5 = mapping(set);
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, filing;
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({ ...fields5, $ref: row.ref, ...Object.hasOwn(row, "filing") ? { $filing: row.filing } : {} });
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 > DATA_REQUEST_LIMIT)
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", "publication_pending"],
1436
+ 409: ["conflict", "apply_pending"],
1253
1437
  413: ["request_too_large"],
1254
1438
  429: ["capacity"],
1255
- 503: ["unavailable", "publication_pending"]
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
- return new DataOperationError(
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", "publication_pending"].includes(code),
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(query)) {
1414
- let names = Object.keys(page.$meta.collections), size = names.reduce((sum, name2) => sum + page[name2].length, 0);
1415
- if (size > maxRecords - total) throw new DataOperationError("capacity");
1416
- total += size, result2 ??= { ...Object.fromEntries(names.map((name2) => [name2, []])), $meta: page.$meta };
1417
- for (let name2 of names) {
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 = [], publicationId, pending, confirmed, assertMutable = () => {
1471
- if (publicationId) throw new DataOperationError("invalid_change", !1, "unapplied");
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.publish",
1674
+ operation: "changes.apply",
1477
1675
  ...input,
1478
- publicationId: publicationId ?? "00000000-0000-4000-8000-000000000000"
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
- publish() {
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
- publicationId ??= routineTransport()?.key("data") ?? crypto.randomUUID(), pending = send3({ operation: "changes.publish", ...captured, publicationId }).then((result2) => (confirmed = structuredClone(result2), result2)).catch((error) => {
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", "publication_pending"].includes(error.code) ? "uncertain" : "unapplied"),
1514
- error.component
1515
- ) : new DataOperationError("unavailable", !0, "uncertain");
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 start = await request2((signal) => exchange(`${route}/start`, control(upload?.file ?? metadata), "control", signal));
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
- active--;
2036
+ release();
1806
2037
  }
1807
- }, signal = context.signal && parent ? AbortSignal.any([context.signal, parent]) : context.signal ?? parent;
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
- if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1886
- if (active++, context.localFiles && !routineTransport() && metadata.size > MAX_BYTES) {
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
- active--;
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
- active--;
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, reportUse = !0) {
2582
+ async function localLease(identity) {
2321
2583
  let current2 = local;
2322
2584
  if (!current2 || !current2.declared.includes(identity)) throw new Error("Connection unavailable");
2323
- reportUse && await current2.recheck(identity);
2324
- let lease = current2.acquire ? parseConnectionLease(await current2.acquire(identity)) : current2.leases.find((lease2) => `${lease2.provider}/${lease2.name}` === identity);
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 new Error("Connection unavailable");
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, SUMMARY_BYTES = 17 * 1024 * 1024, AppRoutineError = class extends Error {
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) => code === "unavailable"))) && 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)));
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)));
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,