@oddington/sdk 0.1.37 → 0.1.39

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