@oddington/sdk 0.1.21 → 0.1.23

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
@@ -285,7 +285,7 @@ function validatePublication(value) {
285
285
  "views",
286
286
  "body",
287
287
  "notifyImmediately",
288
- ...source.kind === "ask" ? ["questions"] : []
288
+ ...source.kind === "ask" ? ["questions", "tags", "recordRefs"] : []
289
289
  ], "publication"), source.notifyImmediately !== void 0 && typeof source.notifyImmediately != "boolean" && fail("notifyImmediately must be a boolean");
290
290
  let itemPresentation = { ...presentation(source), ...source.notifyImmediately === void 0 ? {} : { notifyImmediately: source.notifyImmediately } }, linkedAsks = (itemPresentation.body ?? []).flatMap((block2) => block2.kind === "asks" ? block2.asks : []);
291
291
  if (new Set(linkedAsks).size !== linkedAsks.length && fail("Ask belongs to more than one problem"), source.kind === "digest") return {
@@ -297,10 +297,24 @@ function validatePublication(value) {
297
297
  let questions = array(source.questions === void 0 ? [] : source.questions, "questions").map((value2) => question(value2));
298
298
  new Set(questions.map((entry) => entry.id)).size !== questions.length && fail("Duplicate question ID");
299
299
  let extra = source.recipients === void 0 ? [] : distinctPeople(source.recipients, "recipients", !1);
300
- return !questions.length && !extra.length && fail("Ask requires at least one recipient"), {
300
+ !questions.length && !extra.length && fail("Ask requires at least one recipient");
301
+ let tags = array(source.tags === void 0 ? [] : source.tags, "Ask tags").map((value2) => {
302
+ let tag = text(value2, "Ask tag");
303
+ return new TextEncoder().encode(tag).byteLength > 64 && fail("Ask tag exceeds 64 UTF-8 bytes"), tag;
304
+ });
305
+ (tags.length > 32 || new Set(tags).size !== tags.length) && fail("Ask tags exceed bounds or contain duplicates");
306
+ let recordRefs = array(source.recordRefs === void 0 ? [] : source.recordRefs, "Ask Record references").map((value2) => {
307
+ let row = object(value2, "Ask Record reference");
308
+ keys(row, ["repository", "id"], "Ask Record reference");
309
+ let { repository, ref } = validateRecordReference({ repository: row.repository, ref: row.id });
310
+ return { repository, id: ref };
311
+ });
312
+ return new Set(recordRefs.map((ref) => JSON.stringify([ref.repository, ref.id]))).size !== recordRefs.length && fail("Ask Record references contain duplicates"), {
301
313
  kind: "ask",
302
314
  ...itemPresentation,
303
315
  questions,
316
+ tags,
317
+ recordRefs,
304
318
  recipients: [.../* @__PURE__ */ new Set([...extra, ...questions.flatMap((entry) => [entry.to, ...entry.allowedResponders])])]
305
319
  };
306
320
  }
@@ -335,7 +349,7 @@ function createInboxPublisher(transport) {
335
349
  return {
336
350
  async publishAsk(value, options) {
337
351
  let source = object(value, "ask");
338
- keys(source, ["title", "description", "recipients", "views", "body", "questions", "notifyImmediately"], "ask");
352
+ keys(source, ["title", "description", "recipients", "views", "body", "questions", "notifyImmediately", "tags", "recordRefs"], "ask");
339
353
  let result2 = await transport.publish({
340
354
  requestKey: publicationRequestKey(options),
341
355
  item: validatePublication({ ...source, kind: "ask" })
@@ -391,44 +405,44 @@ var FileOperationError = class extends Error {
391
405
  retryable;
392
406
  }, FILE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/, FILE_ORIGINAL_MAX_BYTES = 5 * 1024 ** 3;
393
407
  function parseFileDescriptor(value) {
394
- let invalid6 = () => {
408
+ let invalid7 = () => {
395
409
  throw new FileOperationError("unavailable", 503, !0);
396
410
  };
397
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid6();
411
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
398
412
  let f = value;
399
- if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return invalid6();
413
+ if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return invalid7();
400
414
  let d = f.details;
401
415
  if (d.kind === "other") {
402
- if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid6();
416
+ if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid7();
403
417
  } else if (d.kind === "csv") {
404
- if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return invalid6();
418
+ if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return invalid7();
405
419
  } else if (d.kind === "pdf") {
406
- if (f.mediaType !== "application/pdf" || Object.keys(d).some((key) => !["kind", "pages"].includes(key)) || "pages" in d && (!Number.isSafeInteger(d.pages) || d.pages < 1)) return invalid6();
407
- } else return invalid6();
420
+ if (f.mediaType !== "application/pdf" || Object.keys(d).some((key) => !["kind", "pages"].includes(key)) || "pages" in d && (!Number.isSafeInteger(d.pages) || d.pages < 1)) return invalid7();
421
+ } else return invalid7();
408
422
  for (let [name, descriptor] of Object.entries(f.enrichments)) {
409
- if (!safeEnrichmentName(name)) return invalid6();
423
+ if (!safeEnrichmentName(name)) return invalid7();
410
424
  parseEnrichmentDescriptor(descriptor);
411
425
  }
412
- return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid6() : f;
426
+ return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid7() : f;
413
427
  }
414
428
  function parseEnrichmentDescriptor(value) {
415
- let invalid6 = () => {
429
+ let invalid7 = () => {
416
430
  throw new FileOperationError("unavailable", 503, !0);
417
431
  };
418
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid6();
432
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
419
433
  let d = value;
420
- return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ? invalid6() : d;
434
+ return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ? invalid7() : d;
421
435
  }
422
436
  function safeEnrichmentName(value) {
423
437
  return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
424
438
  }
425
439
  function parseFileEnrichMetadata(value, maxBytes) {
426
- let invalid6 = () => {
440
+ let invalid7 = () => {
427
441
  throw new FileOperationError("invalid_input", 400);
428
442
  };
429
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid6();
443
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
430
444
  let d = value;
431
- if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid6();
445
+ if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid7();
432
446
  if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
433
447
  return d;
434
448
  }
@@ -439,23 +453,23 @@ function safeFilePath(value) {
439
453
  return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
440
454
  }
441
455
  function parseFileCreateMetadata(value, maxBytes) {
442
- let invalid6 = () => {
456
+ let invalid7 = () => {
443
457
  throw new FileOperationError("invalid_input", 400);
444
458
  };
445
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid6();
459
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid7();
446
460
  let input = value;
447
- if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return invalid6();
461
+ if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return invalid7();
448
462
  let path = input.path === void 0 ? "Files" : input.path;
449
- if (!safeFileName(input.name) || !safeFilePath(path) || path.split("/")[0].toLowerCase() === ".os" || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || input.inputMediaType !== void 0 && input.inputMediaType !== "application/pdf" || !Number.isSafeInteger(input.size) || input.size < 0) return invalid6();
463
+ if (!safeFileName(input.name) || !safeFilePath(path) || path.split("/")[0].toLowerCase() === ".os" || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || input.inputMediaType !== void 0 && input.inputMediaType !== "application/pdf" || !Number.isSafeInteger(input.size) || input.size < 0) return invalid7();
450
464
  if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
451
- if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return invalid6();
465
+ if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return invalid7();
452
466
  let csv;
453
467
  if (input.csv !== void 0) {
454
- if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid6();
468
+ if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid7();
455
469
  let hints = input.csv;
456
- if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid6();
470
+ if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid7();
457
471
  let encoding = hints.encoding === void 0 ? "utf-8" : hints.encoding, delimiter = hints.delimiter === void 0 ? "," : hints.delimiter, headerRow = hints.headerRow === void 0 ? 1 : hints.headerRow;
458
- if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid6();
472
+ if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid7();
459
473
  csv = { encoding, delimiter, headerRow };
460
474
  }
461
475
  return {
@@ -517,8 +531,9 @@ function parseAppRoutineContract(value) {
517
531
  case "array":
518
532
  return !fields2(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 };
519
533
  case "boolean":
520
- case "file":
521
534
  return fields2(value2, ["type"]) ? { type: value2.type } : invalidContract();
535
+ case "file":
536
+ return !fields2(value2, ["type"], ["storage"]) || owns(value2, "storage") && value2.storage !== "local" && value2.storage !== "remote" ? invalidContract() : { type: "file", ...owns(value2, "storage") ? { storage: value2.storage } : {} };
522
537
  case "string":
523
538
  return !fields2(value2, ["type"], ["maxLength"]) || owns(value2, "maxLength") && (!Number.isSafeInteger(value2.maxLength) || value2.maxLength < 0 || value2.maxLength > 4096) ? invalidContract() : { type: "string", ...owns(value2, "maxLength") ? { maxLength: value2.maxLength } : {} };
524
539
  case "integer":
@@ -572,10 +587,10 @@ function validateRoutineSchemaValue(schema2, value) {
572
587
  }
573
588
  }
574
589
 
575
- var ROUTINE_DECLARATION_SCHEMA = "https://schemas.oddington.ai/routine/v1.json";
590
+ var ROUTINE_DECLARATION_SCHEMA = "https://schemas.oddington.ai/routine/v1.json", ROUTINE_SOURCE_LIMITS = { files: 2e4, bytes: 256 * 1024 * 1024, declarationBytes: 64 * 1024 };
576
591
  var invalid = (field) => {
577
592
  throw new Error(`Invalid routine declaration: ${field}`);
578
- }, object2 = (value, fields6, field) => ((!value || typeof value != "object" || Array.isArray(value) || Object.keys(value).some((key) => !fields6.includes(key))) && invalid(field), value), routineAlias = (value) => typeof value == "string" && /^[a-z][a-z0-9-]{0,62}$/.test(value), list = (value, field, allowed) => value === void 0 ? [] : ((!Array.isArray(value) || value.length > 64 || value.some((item) => !routineAlias(item) || allowed && !allowed.includes(item)) || new Set(value).size !== value.length) && invalid(field), [...value].sort());
593
+ }, object2 = (value, fields5, field) => ((!value || typeof value != "object" || Array.isArray(value) || Object.keys(value).some((key) => !fields5.includes(key))) && invalid(field), value), routineAlias = (value) => typeof value == "string" && /^[a-z][a-z0-9-]{0,62}$/.test(value), list = (value, field, allowed, qualified = !1) => value === void 0 ? [] : ((!Array.isArray(value) || value.length > 64 || value.some((item) => !(routineAlias(item) || qualified && typeof item == "string" && item.split("/").length === 2 && item.split("/").every(routineAlias)) || allowed && !allowed.includes(item)) || new Set(value).size !== value.length) && invalid(field), [...value].sort());
579
594
  function routineAssetPattern(value) {
580
595
  return typeof value == "string" && value.length <= 512 && !value.startsWith("/") && !value.includes("\\") && !value.includes(":") && value.split("/").every((part) => !!part && part !== "." && part !== ".." && /^[a-zA-Z0-9_.*-]+$/.test(part));
581
596
  }
@@ -599,7 +614,7 @@ function parseRoutineDeclaration(value) {
599
614
  $schema: ROUTINE_DECLARATION_SCHEMA,
600
615
  access: {
601
616
  repositories: grants,
602
- connections: list(access.connections, "access.connections"),
617
+ connections: list(access.connections, "access.connections", void 0, !0),
603
618
  models: list(access.models, "access.models"),
604
619
  ...access.files === void 0 ? {} : { files: access.files },
605
620
  publish: list(access.publish, "access.publish", ["asks", "digests"])
@@ -614,19 +629,19 @@ function parseRoutineDeclaration(value) {
614
629
  };
615
630
  }
616
631
 
617
- var LIMIT = 256 * 1024, invalid2 = () => {
632
+ var invalid2 = () => {
618
633
  throw new AppRoutineContractError("invalid_value");
619
634
  }, invalidContract2 = () => {
620
635
  throw new AppRoutineContractError("invalid_contract");
621
- }, empty = { type: "object", properties: {}, required: [], additionalProperties: !1 };
622
- function freeze(value) {
636
+ }, routineTitle = (value) => typeof value == "string" && value.trim().length > 0 && value.length <= 256;
637
+ function freezeRoutineMetadata(value) {
623
638
  if (value !== null && typeof value == "object") {
624
- for (let child of Object.values(value)) freeze(child);
639
+ for (let child of Object.values(value)) freezeRoutineMetadata(child);
625
640
  Object.freeze(value);
626
641
  }
627
642
  return value;
628
643
  }
629
- function json(value, ancestors = /* @__PURE__ */ new Set()) {
644
+ function assertRoutineJson(value, ancestors = /* @__PURE__ */ new Set()) {
630
645
  if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return;
631
646
  if (!value || typeof value != "object" || ancestors.has(value)) return invalid2();
632
647
  let array3 = Array.isArray(value);
@@ -639,14 +654,34 @@ function json(value, ancestors = /* @__PURE__ */ new Set()) {
639
654
  if (typeof key != "string") return invalid2();
640
655
  let descriptor = Object.getOwnPropertyDescriptor(value, key);
641
656
  if (!descriptor.enumerable || !Object.hasOwn(descriptor, "value")) return invalid2();
642
- json(descriptor.value, ancestors);
657
+ assertRoutineJson(descriptor.value, ancestors);
643
658
  }
644
659
  ancestors.delete(value);
645
660
  }
661
+ function assertRoutineFields(value, allowed) {
662
+ if (!value || typeof value != "object" || Object.getPrototypeOf(value) !== Object.prototype || Reflect.ownKeys(value).some((key) => typeof key != "string" || allowed && !allowed.includes(key) || !Object.getOwnPropertyDescriptor(value, key).enumerable || !Object.hasOwn(Object.getOwnPropertyDescriptor(value, key), "value"))) return invalidContract2();
663
+ }
664
+ function parseRoutineAccess(value) {
665
+ try {
666
+ value !== void 0 && assertRoutineJson(value), assertRoutineFields(value ?? {}, ["repositories", "connections", "models", "files", "publish"]);
667
+ let access = value, names = access?.connections ?? [];
668
+ if (!Array.isArray(names) || names.length > 64 || new Set(names).size !== names.length || names.some((name) => typeof name != "string" || name.split("/").length !== 2 || name.split("/").some((part) => !isAppRoutineName(part)))) return invalidContract2();
669
+ let parsed = parseRoutineDeclaration({ $schema: ROUTINE_DECLARATION_SCHEMA, access: { ...access, connections: [] } }).access;
670
+ return freezeRoutineMetadata({ ...parsed, connections: [...names] });
671
+ } catch {
672
+ return invalidContract2();
673
+ }
674
+ }
675
+
676
+ var LIMIT = 256 * 1024, invalid3 = () => {
677
+ throw new AppRoutineContractError("invalid_value");
678
+ }, invalidContract3 = () => {
679
+ throw new AppRoutineContractError("invalid_contract");
680
+ }, empty = { type: "object", properties: {}, required: [], additionalProperties: !1 };
646
681
  function captureJson(value) {
647
- json(value);
682
+ assertRoutineJson(value);
648
683
  let encoded = JSON.stringify(value);
649
- return new TextEncoder().encode(encoded).byteLength > LIMIT ? invalid2() : freeze(JSON.parse(encoded));
684
+ return new TextEncoder().encode(encoded).byteLength > LIMIT ? invalid3() : freezeRoutineMetadata(JSON.parse(encoded));
650
685
  }
651
686
  function capture(schema2, value) {
652
687
  let captured = captureJson(value);
@@ -655,26 +690,26 @@ function capture(schema2, value) {
655
690
  var schemas = /* @__PURE__ */ new WeakMap();
656
691
  function nestedSchema(value) {
657
692
  let metadata = schemaMetadata(value);
658
- return Object.hasOwn(metadata, "default") ? invalidContract2() : metadata.schema;
693
+ return Object.hasOwn(metadata, "default") ? invalidContract3() : metadata.schema;
659
694
  }
660
695
  function schemaMetadata(value) {
661
- if (!value || typeof value != "object") return invalidContract2();
696
+ if (!value || typeof value != "object") return invalidContract3();
662
697
  let registered = schemas.get(value);
663
698
  if (registered) return registered;
664
699
  try {
665
- json(value);
700
+ assertRoutineJson(value);
666
701
  } catch {
667
- return invalidContract2();
702
+ return invalidContract3();
668
703
  }
669
704
  return { schema: parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input };
670
705
  }
671
706
  function declaration(value, defaults) {
672
707
  try {
673
- json(value);
708
+ assertRoutineJson(value);
674
709
  } catch {
675
- return invalidContract2();
710
+ return invalidContract3();
676
711
  }
677
- let parsed = freeze(parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input), captured = defaults ? capture(parsed, defaults.value) : void 0, builder = Object.defineProperty({ ...parsed }, "default", { value: (value2) => declaration(parsed, { value: value2 }) });
712
+ let parsed = freezeRoutineMetadata(parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input), captured = defaults ? capture(parsed, defaults.value) : void 0, builder = Object.defineProperty({ ...parsed }, "default", { value: (value2) => declaration(parsed, { value: value2 }) });
678
713
  return schemas.set(builder, { schema: parsed, ...defaults ? { default: captured } : {} }), Object.freeze(builder);
679
714
  }
680
715
  var schema = {
@@ -696,27 +731,11 @@ var schema = {
696
731
  boolean() {
697
732
  return declaration({ type: "boolean" });
698
733
  }
699
- }, file = () => declaration({ type: "file" }), definitions = /* @__PURE__ */ new WeakMap();
700
- function fields3(value, allowed) {
701
- if (!value || typeof value != "object" || Object.getPrototypeOf(value) !== Object.prototype || Reflect.ownKeys(value).some((key) => typeof key != "string" || allowed && !allowed.includes(key) || !Object.getOwnPropertyDescriptor(value, key).enumerable || !Object.hasOwn(Object.getOwnPropertyDescriptor(value, key), "value"))) return invalidContract2();
702
- }
703
- var title = (value) => typeof value == "string" && value.trim().length > 0 && value.length <= 256;
704
- function accessMetadata(value) {
705
- try {
706
- value !== void 0 && json(value), fields3(value ?? {}, ["repositories", "connections", "models", "files", "publish"]);
707
- let access = value, names = access?.connections ?? [];
708
- if (!Array.isArray(names) || names.length > 64 || new Set(names).size !== names.length || names.some((name) => typeof name != "string" || name.split("/").length !== 2 || name.split("/").some((part) => !isAppRoutineName(part)))) return invalidContract2();
709
- let parsed = parseRoutineDeclaration({ $schema: ROUTINE_DECLARATION_SCHEMA, access: { ...access, connections: [] } }).access;
710
- return freeze({ ...parsed, connections: [...names] });
711
- } catch {
712
- return invalidContract2();
713
- }
714
- }
715
- var defineRoutine = (definition) => {
716
- if (fields3(definition, ["id", "title", "input", "steps", "result", "access", "responses", "run"]), !isAppRoutineName(definition.id) || definition.title !== void 0 && !title(definition.title) || typeof definition.run != "function") return invalidContract2();
717
- let input = definition.input === void 0 ? { schema: empty, default: {} } : schemaMetadata(definition.input), result2 = definition.result === void 0 ? void 0 : schemaMetadata(definition.result).schema, access = accessMetadata(definition.access);
718
- fields3(definition.steps ?? {});
719
- let executable = Object.fromEntries(Object.entries(definition.steps ?? {}).map(([id3, step]) => (fields3(step, ["title", "run"]), !title(step.title) || typeof step.run != "function" ? invalidContract2() : [id3, Object.freeze({ title: step.title, run: step.run })]))), steps = Object.entries(executable).map(([id3, step]) => ({ id: id3, title: step.title }));
734
+ }, file = (options = {}) => (assertRoutineFields(options, ["storage"]), declaration({ type: "file", ...options })), definitions = /* @__PURE__ */ new WeakMap(), defineRoutine = (definition) => {
735
+ if (assertRoutineFields(definition, ["id", "title", "input", "steps", "result", "access", "responses", "run"]), !isAppRoutineName(definition.id) || definition.title !== void 0 && !routineTitle(definition.title) || typeof definition.run != "function") return invalidContract3();
736
+ let input = definition.input === void 0 ? { schema: empty, default: {} } : schemaMetadata(definition.input), result2 = definition.result === void 0 ? void 0 : schemaMetadata(definition.result).schema, access = parseRoutineAccess(definition.access);
737
+ assertRoutineFields(definition.steps ?? {});
738
+ let executable = Object.fromEntries(Object.entries(definition.steps ?? {}).map(([id3, step]) => (assertRoutineFields(step, ["title", "run"]), !routineTitle(step.title) || typeof step.run != "function" ? invalidContract3() : [id3, Object.freeze({ title: step.title, run: step.run })]))), steps = Object.entries(executable).map(([id3, step]) => ({ id: id3, title: step.title }));
720
739
  parseAppRoutineContract({
721
740
  routine: definition.id,
722
741
  input: input.schema,
@@ -725,26 +744,26 @@ var defineRoutine = (definition) => {
725
744
  });
726
745
  let responses = [], ids = /* @__PURE__ */ new Set();
727
746
  if (definition.responses !== void 0) {
728
- if (!Array.isArray(definition.responses) || definition.responses.length > 64 || Reflect.ownKeys(definition.responses).length !== definition.responses.length + 1) return invalidContract2();
747
+ if (!Array.isArray(definition.responses) || definition.responses.length > 64 || Reflect.ownKeys(definition.responses).length !== definition.responses.length + 1) return invalidContract3();
729
748
  for (let index = 0; index < definition.responses.length; index++) {
730
749
  let descriptor = Object.getOwnPropertyDescriptor(definition.responses, String(index));
731
- if (!descriptor || !Object.hasOwn(descriptor, "value")) return invalidContract2();
750
+ if (!descriptor || !Object.hasOwn(descriptor, "value")) return invalidContract3();
732
751
  let response2 = descriptor.value;
733
- if (fields3(response2, ["id", "results", "run"]), !isAppRoutineName(response2.id) || ids.has(response2.id)) return invalidContract2();
752
+ if (assertRoutineFields(response2, ["id", "results", "run"]), !isAppRoutineName(response2.id) || ids.has(response2.id)) return invalidContract3();
734
753
  if (ids.add(response2.id), response2.results !== void 0)
735
754
  try {
736
- json(response2.results);
755
+ assertRoutineJson(response2.results);
737
756
  } catch {
738
- return invalidContract2();
757
+ return invalidContract3();
739
758
  }
740
759
  try {
741
760
  responses.push(defineHandler(response2));
742
761
  } catch {
743
- return invalidContract2();
762
+ return invalidContract3();
744
763
  }
745
764
  }
746
765
  }
747
- let contract = freeze({
766
+ let contract = freezeRoutineMetadata({
748
767
  id: definition.id,
749
768
  ...definition.title === void 0 ? {} : { title: definition.title },
750
769
  input: input.schema,
@@ -769,9 +788,9 @@ var defineRoutine = (definition) => {
769
788
  return definitions.set(captured, { contract, steps: executable, run: definition.run }), captured;
770
789
  };
771
790
  function inspectRoutineDefinition(definition) {
772
- if (!definition || typeof definition != "object") return invalidContract2();
791
+ if (!definition || typeof definition != "object") return invalidContract3();
773
792
  let registered = definitions.get(definition);
774
- return registered ? registered.contract : invalidContract2();
793
+ return registered ? registered.contract : invalidContract3();
775
794
  }
776
795
  function captureRoutineInput(definition, input) {
777
796
  let contract = inspectRoutineDefinition(definition);
@@ -787,29 +806,35 @@ async function executeRoutineDefinition(definition, input, runtime) {
787
806
  get(_target, key) {
788
807
  return guarded(Reflect.get(value, key, value), value);
789
808
  }
790
- }) : value, qualify = (value) => value.questions === void 0 ? value : { ...value, questions: value.questions.map((question2) => question2.handler ? contract.responses.some((handler) => handler.id === question2.handler.id) ? { ...question2, handler: { ...question2.handler, id: `${contract.id}/${question2.handler.id}` } } : invalid2() : question2) }, os2 = Object.freeze({
809
+ }) : value, qualify = (value) => value.questions === void 0 ? value : { ...value, questions: value.questions.map((question2) => question2.handler ? contract.responses.some((handler) => handler.id === question2.handler.id) ? { ...question2, handler: { ...question2.handler, id: `${contract.id}/${question2.handler.id}` } } : invalid3() : question2) }, os2 = Object.freeze({
791
810
  ...guarded({
792
811
  ...runtime,
793
- run: freeze({ ...runtime.run }),
812
+ run: freezeRoutineMetadata({ ...runtime.run }),
813
+ connections: { ...runtime.connections, get: async (identity) => {
814
+ if (!active2 || broken || !contract.access.connections?.includes(identity)) throw new Error("Connection unavailable");
815
+ let value = await runtime.connections.get(identity);
816
+ if (!active2 || broken) throw new Error("Run authority ended");
817
+ return value;
818
+ } },
794
819
  inbox: { ...runtime.inbox, publishAsk: (value, options) => runtime.inbox.publishAsk(qualify(value), options) }
795
820
  }),
796
821
  step(id3, ...input2) {
797
822
  let saved;
798
823
  try {
799
- if (!active2 || !accepting || broken || !Object.hasOwn(steps, id3) || called.has(id3) || input2.length > 1) return invalid2();
824
+ if (!active2 || !accepting || broken || !Object.hasOwn(steps, id3) || called.has(id3) || input2.length > 1) return invalid3();
800
825
  input2.length && (saved = captureJson(input2[0])), called.add(id3);
801
826
  } catch (error) {
802
827
  return broken = !0, Promise.reject(error);
803
828
  }
804
829
  let next = work.then(async () => {
805
- if (broken) return invalid2();
830
+ if (broken) return invalid3();
806
831
  reached.add(id3);
807
832
  try {
808
833
  await runtime.step(id3, { status: "running" });
809
834
  let output = await steps[id3].run(saved, os2);
810
- if (fields3(output, ["summary", "data"]), !Object.hasOwn(output, "summary") || !Object.hasOwn(output, "data")) return invalid2();
835
+ if (assertRoutineFields(output, ["summary", "data"]), !Object.hasOwn(output, "summary") || !Object.hasOwn(output, "data")) return invalid3();
811
836
  let summary2 = captureJson(output.summary), data3 = captureJson(output.data);
812
- return await runtime.step(id3, { status: "completed", summary: summary2, data: data3 }), freeze({ summary: summary2, data: data3 });
837
+ return await runtime.step(id3, { status: "completed", summary: summary2, data: data3 }), freezeRoutineMetadata({ summary: summary2, data: data3 });
813
838
  } catch (error) {
814
839
  throw broken = !0, await runtime.step(id3, { status: "failed" }), error;
815
840
  }
@@ -829,7 +854,7 @@ async function executeRoutineDefinition(definition, input, runtime) {
829
854
  for (let step of contract.steps) reached.has(step.id) || await runtime.step(step.id, { status: "skipped" });
830
855
  if (broken) throw failure ?? new AppRoutineContractError("invalid_value");
831
856
  if (contract.result !== void 0) return capture(contract.result, result2);
832
- if (result2 !== void 0) return invalid2();
857
+ if (result2 !== void 0) return invalid3();
833
858
  }
834
859
 
835
860
  var DataOperationError = class extends Error {
@@ -847,26 +872,26 @@ var DataOperationError = class extends Error {
847
872
  component;
848
873
  };
849
874
 
850
- var invalid3 = () => {
875
+ var invalid4 = () => {
851
876
  throw new DataOperationError("invalid_query");
852
877
  }, historyText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
853
878
  function historyVersion(value) {
854
879
  return historyText(value) && value.length > 0 && new TextEncoder().encode(value).length <= 1024 && !/[\u0000-\u001f\u007f-\u009f]/.test(value) && !/^[0-9a-f]{40}$/i.test(value);
855
880
  }
856
881
  function historyProperties(value) {
857
- if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return invalid3();
882
+ if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return invalid4();
858
883
  let descriptors = Object.getOwnPropertyDescriptors(value);
859
- return Reflect.ownKeys(value).some((key) => typeof key != "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")) ? invalid3() : descriptors;
884
+ return Reflect.ownKeys(value).some((key) => typeof key != "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")) ? invalid4() : descriptors;
860
885
  }
861
886
  var historyCollection = (value) => typeof value == "string" && value.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(value), historyCursor = (value) => typeof value == "string" && value.length <= 128 * 1024 && /^history-cursor-v1\.[A-Za-z0-9_-]{1,64}\.[A-Za-z0-9_-]{16}\.[A-Za-z0-9_-]+$/.test(value);
862
887
  function historyArray(value) {
863
- if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return invalid3();
888
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return invalid4();
864
889
  let descriptors = Object.getOwnPropertyDescriptors(value);
865
- if (Reflect.ownKeys(value).length !== value.length + 1) return invalid3();
890
+ if (Reflect.ownKeys(value).length !== value.length + 1) return invalid4();
866
891
  let result2 = [];
867
892
  for (let i = 0; i < value.length; i++) {
868
893
  let descriptor = descriptors[i];
869
- if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value")) return invalid3();
894
+ if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value")) return invalid4();
870
895
  result2.push(descriptor.value);
871
896
  }
872
897
  return result2;
@@ -874,19 +899,19 @@ function historyArray(value) {
874
899
  function captureOptions(value, changes) {
875
900
  if (value === void 0) return {};
876
901
  let descriptors = historyProperties(value), result2 = {}, allowed = changes ? ["collections", "refs", "from", "through", "limit", "after"] : ["limit", "before"];
877
- if (Object.keys(descriptors).some((key) => !allowed.includes(key))) return invalid3();
902
+ if (Object.keys(descriptors).some((key) => !allowed.includes(key))) return invalid4();
878
903
  for (let key of allowed) {
879
904
  if (!Object.hasOwn(descriptors, key)) continue;
880
905
  let scalar = descriptors[key].value;
881
906
  if (key === "collections" || key === "refs") {
882
907
  let values = historyArray(scalar);
883
- if (!values.length || values.length > (key === "collections" ? 16 : 100) || !values.every(key === "collections" ? historyCollection : validRecordRef) || new Set(values).size !== values.length) return invalid3();
908
+ if (!values.length || values.length > (key === "collections" ? 16 : 100) || !values.every(key === "collections" ? historyCollection : validRecordRef) || new Set(values).size !== values.length) return invalid4();
884
909
  result2[key] = values;
885
910
  } else if (key === "limit") {
886
- if (!Number.isInteger(scalar) || scalar < 1 || scalar > (changes ? 500 : 100)) return invalid3();
911
+ if (!Number.isInteger(scalar) || scalar < 1 || scalar > (changes ? 500 : 100)) return invalid4();
887
912
  result2.limit = scalar;
888
913
  } else {
889
- if (!(key === "after" ? historyCursor(scalar) : historyVersion(scalar))) return invalid3();
914
+ if (!(key === "after" ? historyCursor(scalar) : historyVersion(scalar))) return invalid4();
890
915
  result2[key] = scalar;
891
916
  }
892
917
  }
@@ -894,39 +919,39 @@ function captureOptions(value, changes) {
894
919
  }
895
920
  var captureHistoryListOptions = (value) => captureOptions(value, !1), captureHistoryChangesOptions = (value) => captureOptions(value, !0);
896
921
  function captureHistoryInstant(value) {
897
- if (!historyText(value) || value.length > 1024) return invalid3();
922
+ if (!historyText(value) || value.length > 1024) return invalid4();
898
923
  let match = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?([Zz]|([+-])(\d{2}):(\d{2}))$/.exec(value);
899
- if (!match) return invalid3();
924
+ if (!match) return invalid4();
900
925
  let [year, month, day, hour, minute, second] = match.slice(1, 7).map(Number), days = new Date(Date.UTC(year, month, 0));
901
- return days.setUTCFullYear(year), year < 1 || month < 1 || month > 12 || day < 1 || day > days.getUTCDate() || hour > 23 || minute > 59 || second > 59 || Number(match[9] ?? 0) > 23 || Number(match[10] ?? 0) > 59 ? invalid3() : value;
926
+ return days.setUTCFullYear(year), year < 1 || month < 1 || month > 12 || day < 1 || day > days.getUTCDate() || hour > 23 || minute > 59 || second > 59 || Number(match[9] ?? 0) > 23 || Number(match[10] ?? 0) > 59 ? invalid4() : value;
902
927
  }
903
928
 
904
- var invalid4 = () => {
929
+ var invalid5 = () => {
905
930
  throw new DataOperationError("invalid_query");
906
931
  };
907
932
  function captureRecordsSearchInput(query, options) {
908
- if (!historyText(query)) return invalid4();
933
+ if (!historyText(query)) return invalid5();
909
934
  let length = [...query.trim()].length;
910
- if (length < 1 || length > 256) return invalid4();
935
+ if (length < 1 || length > 256) return invalid5();
911
936
  if (options === void 0) return { query };
912
937
  let descriptors = historyProperties(options);
913
- if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key))) return invalid4();
938
+ if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key))) return invalid5();
914
939
  let captured = {};
915
940
  if (Object.hasOwn(descriptors, "collections")) {
916
941
  let supplied = descriptors.collections.value;
917
- if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return invalid4();
942
+ if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return invalid5();
918
943
  let collections = [];
919
944
  for (let index = 0; index < supplied.length; index++) {
920
945
  let descriptor = Object.getOwnPropertyDescriptor(supplied, String(index));
921
- if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value") || !historyText(descriptor.value)) return invalid4();
946
+ if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value") || !historyText(descriptor.value)) return invalid5();
922
947
  collections.push(descriptor.value);
923
948
  }
924
- if (new Set(collections).size !== collections.length) return invalid4();
949
+ if (new Set(collections).size !== collections.length) return invalid5();
925
950
  captured.collections = collections;
926
951
  }
927
952
  if (Object.hasOwn(descriptors, "limit")) {
928
953
  let supplied = descriptors.limit.value;
929
- if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return invalid4();
954
+ if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return invalid5();
930
955
  captured.limit = supplied;
931
956
  }
932
957
  return { query, options: captured };
@@ -957,8 +982,8 @@ function captureDataDelete(record3) {
957
982
  return !validRecordRef(identity.$ref) || typeof identity.$version != "string" || !identity.$version.length || identity.$version.length > 512 ? invalidChange() : { ref: identity.$ref, expectedVersion: identity.$version };
958
983
  }
959
984
  function captureDataUpdate(record3, set) {
960
- let identity = captureDataDelete(record3), fields6 = mapping(set);
961
- return !Object.keys(fields6).length || Object.keys(fields6).some((key) => key.startsWith("$") || ["id", "type"].includes(key)) ? invalidChange() : { ...identity, set: captureValue(fields6) };
985
+ let identity = captureDataDelete(record3), fields5 = mapping(set);
986
+ return !Object.keys(fields5).length || Object.keys(fields5).some((key) => key.startsWith("$") || ["id", "type"].includes(key)) ? invalidChange() : { ...identity, set: captureValue(fields5) };
962
987
  }
963
988
  function captureIdentities(value, update, allowEmpty = !0) {
964
989
  if (!Array.isArray(value) || !allowEmpty && !value.length || value.length > 1e4) return invalidChange();
@@ -977,14 +1002,14 @@ function captureDataCreate(value) {
977
1002
  let row = mapping(value);
978
1003
  if (!validRecordRef(row.$ref) || Object.keys(row).some((key) => key.startsWith("$") && !["$ref", "$filing"].includes(key)))
979
1004
  return invalidChange();
980
- let { $ref: ref, $filing, ...fields6 } = row, filing;
1005
+ let { $ref: ref, $filing, ...fields5 } = row, filing;
981
1006
  if ($filing !== void 0) {
982
1007
  let components = mapping($filing);
983
1008
  if (Object.entries(components).some(([name, value2]) => !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name) || ["constructor", "prototype"].includes(name) || typeof value2 != "string" || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(value2)))
984
1009
  return invalidChange();
985
1010
  filing = { ...components };
986
1011
  }
987
- return { ref, fields: captureValue(fields6), ...filing ? { filing } : {} };
1012
+ return { ref, fields: captureValue(fields5), ...filing ? { filing } : {} };
988
1013
  }
989
1014
  function captureDataChanges(updatesValue, createsValue = [], deletesValue = []) {
990
1015
  let updates = captureDataUpdates(updatesValue, !0);
@@ -992,8 +1017,8 @@ function captureDataChanges(updatesValue, createsValue = [], deletesValue = [])
992
1017
  let creates = createsValue.map((item) => {
993
1018
  let row = mapping(item);
994
1019
  if (Object.keys(row).some((key) => !["ref", "fields", "filing"].includes(key)) || !Object.hasOwn(row, "ref") || !Object.hasOwn(row, "fields")) return invalidChange();
995
- let fields6 = mapping(row.fields);
996
- return Object.keys(fields6).some((key) => key.startsWith("$")) ? invalidChange() : captureDataCreate({ ...fields6, $ref: row.ref, ...Object.hasOwn(row, "filing") ? { $filing: row.filing } : {} });
1020
+ let fields5 = mapping(row.fields);
1021
+ return Object.keys(fields5).some((key) => key.startsWith("$")) ? invalidChange() : captureDataCreate({ ...fields5, $ref: row.ref, ...Object.hasOwn(row, "filing") ? { $filing: row.filing } : {} });
997
1022
  }), deletes = captureIdentities(deletesValue, !1), refs = [...updates, ...creates, ...deletes].map((item) => item.ref);
998
1023
  return !refs.length || refs.length > 1e4 || new Set(refs).size !== refs.length ? invalidChange() : { updates, creates, deletes };
999
1024
  }
@@ -1025,16 +1050,16 @@ function routineTransport() {
1025
1050
  return installed;
1026
1051
  }
1027
1052
 
1028
- var memberContext;
1029
- function installMemberContext(resolve) {
1030
- return memberContext = resolve, () => {
1031
- memberContext === resolve && (memberContext = void 0);
1053
+ var memberContext, retainedContext;
1054
+ function installMemberContext(resolve, retained = resolve) {
1055
+ return memberContext = resolve, retainedContext = retained, () => {
1056
+ memberContext === resolve && (memberContext = void 0, retainedContext = void 0);
1032
1057
  };
1033
1058
  }
1034
- async function resolveAppContext() {
1059
+ async function resolveAppContext(retained = !1) {
1035
1060
  let host = memberContext;
1036
1061
  if (!host) throw new Error("App context unavailable.");
1037
- let context2 = await host();
1062
+ let context2 = await (retained ? retainedContext : host)();
1038
1063
  if (host !== memberContext || !context2.isCurrent() || context2.expiresAt <= Date.now() || context2.kind !== "local" && (typeof context2.accessToken != "string" || !/^[^\s]{1,8192}$/.test(context2.accessToken)))
1039
1064
  throw new Error("App context unavailable.");
1040
1065
  return context2;
@@ -1059,13 +1084,22 @@ async function resolveFilesContext() {
1059
1084
  let environment = {}, host = memberContext;
1060
1085
  if (host) {
1061
1086
  let context2 = await host();
1062
- if (context2.kind === "local") throw new Error();
1087
+ if (host !== memberContext || !context2.isCurrent() || context2.expiresAt <= Date.now()) throw new Error();
1088
+ if (context2.kind === "local") return {
1089
+ url: `private:app:${context2.workspace}/${context2.memberId}`,
1090
+ headers: {},
1091
+ isCurrent: context2.isCurrent,
1092
+ signal: context2.signal,
1093
+ local: void 0,
1094
+ localFiles: context2.requestFiles
1095
+ };
1063
1096
  if (!Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now() || typeof context2.accessToken != "string" || !/^[^\s]{1,8192}$/.test(context2.accessToken)) throw new Error();
1064
1097
  return {
1065
1098
  ...filesContext(context2.workspace, context2.endpoint, { authorization: `Bearer ${context2.accessToken}` }),
1066
1099
  isCurrent: context2.isCurrent,
1067
1100
  local: void 0,
1068
- localFiles: void 0
1101
+ localFiles: void 0,
1102
+ signal: void 0
1069
1103
  };
1070
1104
  }
1071
1105
  throw new Error();
@@ -1178,7 +1212,65 @@ var data = {
1178
1212
  }
1179
1213
  };
1180
1214
 
1181
- 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, invalid5 = () => new FileOperationError("invalid_input", 400), unavailable = () => new FileOperationError("unavailable", 503, !0), failures = {
1215
+ async function hostedContent(url, init2, parent, upstream = fetch, check = async () => {
1216
+ }, failure) {
1217
+ let delivery = new AbortController(), abort = () => delivery.abort(parent.reason);
1218
+ parent.addEventListener("abort", abort, { once: !0 }), parent.aborted && abort();
1219
+ let detach = () => parent.removeEventListener("abort", abort);
1220
+ try {
1221
+ let response2 = await upstream(url, { ...init2, signal: delivery.signal });
1222
+ try {
1223
+ if (await check(), delivery.signal.aborted) throw failure?.() ?? new FileOperationError("unavailable", 503, !0);
1224
+ } catch (error) {
1225
+ throw response2.body?.cancel().catch(() => {
1226
+ }), error;
1227
+ }
1228
+ if (!response2.body)
1229
+ return detach(), response2;
1230
+ let source = response2.body, reader, settled = !1, output, cancel = async (reason) => {
1231
+ if (!settled) {
1232
+ settled = !0, detach(), delivery.signal.removeEventListener("abort", stop), delivery.abort(reason);
1233
+ try {
1234
+ await (reader ? reader.cancel(reason) : source.cancel(reason));
1235
+ } catch (error) {
1236
+ if (error !== delivery.signal.reason && !(error instanceof Error && error.name === "AbortError")) throw error;
1237
+ } finally {
1238
+ reader?.releaseLock();
1239
+ }
1240
+ }
1241
+ }, stop = () => {
1242
+ if (settled) return;
1243
+ let error = failure?.() ?? delivery.signal.reason;
1244
+ cancel(error).catch(() => {
1245
+ }), output.error(error);
1246
+ }, body = new ReadableStream({
1247
+ start(controller) {
1248
+ output = controller, delivery.signal.addEventListener("abort", stop, { once: !0 }), delivery.signal.aborted && stop();
1249
+ },
1250
+ async pull(controller) {
1251
+ try {
1252
+ if (await check(), settled) return;
1253
+ reader ??= source.getReader();
1254
+ let { done, value } = await reader.read();
1255
+ if (await check(), settled) return;
1256
+ done ? (settled = !0, detach(), delivery.signal.removeEventListener("abort", stop), reader.releaseLock(), controller.close()) : controller.enqueue(value);
1257
+ } catch (error) {
1258
+ if (settled) return;
1259
+ controller.error(failure?.() ?? error), await cancel(error).catch(() => {
1260
+ });
1261
+ }
1262
+ },
1263
+ cancel
1264
+ }, { highWaterMark: 0 }), wrapped = new Response(body, { status: response2.status, statusText: response2.statusText, headers: response2.headers });
1265
+ for (let key of ["url", "redirected", "type"])
1266
+ Object.defineProperty(wrapped, key, { value: response2[key] });
1267
+ return wrapped;
1268
+ } catch (error) {
1269
+ throw detach(), delivery.abort(error), error;
1270
+ }
1271
+ }
1272
+
1273
+ var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0, invalid6 = () => new FileOperationError("invalid_input", 400), unavailable = () => new FileOperationError("unavailable", 503, !0), failures = {
1182
1274
  400: ["invalid_input", "unsupported_context"],
1183
1275
  401: ["unauthenticated"],
1184
1276
  403: ["access_denied"],
@@ -1188,19 +1280,26 @@ var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES =
1188
1280
  429: ["capacity"],
1189
1281
  503: ["integrity", "unavailable"]
1190
1282
  };
1191
- async function boundedBytes(stream, limit) {
1283
+ async function boundedBytes(stream, limit, signal) {
1192
1284
  if (!stream) return new Uint8Array();
1193
- let reader = stream.getReader(), bytes = new Uint8Array(limit), size = 0;
1285
+ let reader = stream.getReader(), bytes = new Uint8Array(limit), size = 0, cancel = () => {
1286
+ reader.cancel().catch(() => {
1287
+ });
1288
+ };
1289
+ signal?.addEventListener("abort", cancel, { once: !0 }), signal?.aborted && cancel();
1194
1290
  try {
1195
1291
  for (; ; ) {
1196
1292
  let { done, value } = await reader.read();
1293
+ if (signal?.aborted) throw unavailable();
1197
1294
  if (done) break;
1198
- if (!(value instanceof Uint8Array)) throw invalid5();
1295
+ if (!(value instanceof Uint8Array)) throw invalid6();
1199
1296
  if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
1200
1297
  bytes.set(value, size - value.byteLength);
1201
1298
  }
1299
+ } catch (error) {
1300
+ throw cancel(), error;
1202
1301
  } finally {
1203
- reader.releaseLock();
1302
+ signal?.removeEventListener("abort", cancel), reader.releaseLock();
1204
1303
  }
1205
1304
  return bytes.slice(0, size);
1206
1305
  }
@@ -1224,50 +1323,6 @@ async function result(response2, maximum = RESULT_BYTES) {
1224
1323
  throw unavailable();
1225
1324
  }
1226
1325
  }
1227
- async function hostedContent(url, init2, parent, upstream = fetch) {
1228
- let delivery = new AbortController(), abort = () => delivery.abort(parent.reason);
1229
- parent.addEventListener("abort", abort, { once: !0 }), parent.aborted && abort();
1230
- let detach = () => parent.removeEventListener("abort", abort);
1231
- try {
1232
- let response2 = await upstream(url, { ...init2, signal: delivery.signal });
1233
- if (delivery.signal.aborted)
1234
- throw response2.body?.cancel().catch(() => {
1235
- }), unavailable();
1236
- if (!response2.body)
1237
- return detach(), response2;
1238
- let source = response2.body, reader, settled = !1, cancel = async (reason) => {
1239
- if (!settled) {
1240
- settled = !0, detach(), delivery.abort(reason);
1241
- try {
1242
- await (reader ? reader.cancel(reason) : source.cancel(reason));
1243
- } catch (error) {
1244
- if (error !== delivery.signal.reason && !(error instanceof Error && error.name === "AbortError")) throw error;
1245
- } finally {
1246
- reader?.releaseLock();
1247
- }
1248
- }
1249
- }, body = new ReadableStream({
1250
- async pull(controller) {
1251
- try {
1252
- reader ??= source.getReader();
1253
- let { done, value } = await reader.read();
1254
- if (settled) return;
1255
- done ? (settled = !0, detach(), reader.releaseLock(), controller.close()) : controller.enqueue(value);
1256
- } catch (error) {
1257
- if (settled) return;
1258
- controller.error(error), await cancel(error).catch(() => {
1259
- });
1260
- }
1261
- },
1262
- cancel
1263
- }, { highWaterMark: 0 }), wrapped = new Response(body, { status: response2.status, statusText: response2.statusText, headers: response2.headers });
1264
- for (let key of ["url", "redirected", "type"])
1265
- Object.defineProperty(wrapped, key, { value: response2[key] });
1266
- return wrapped;
1267
- } catch (error) {
1268
- throw detach(), delivery.abort(error), error;
1269
- }
1270
- }
1271
1326
  async function send(suffix, init2, descriptor, initial, parent) {
1272
1327
  let original = initial, checkCurrent = (context2 = original) => {
1273
1328
  if (parent?.aborted) throw unavailable();
@@ -1278,7 +1333,7 @@ async function send(suffix, init2, descriptor, initial, parent) {
1278
1333
  let context2 = await resolveFilesContext();
1279
1334
  checkCurrent(context2);
1280
1335
  try {
1281
- let response2 = await (async () => {
1336
+ let response2 = context2.localFiles ? await context2.localFiles(suffix, init2, parent) : await (async () => {
1282
1337
  let url = `${context2.url}${suffix}`, request2 = {
1283
1338
  ...init2,
1284
1339
  signal: parent,
@@ -1322,7 +1377,7 @@ async function send(suffix, init2, descriptor, initial, parent) {
1322
1377
  throw unavailable();
1323
1378
  }
1324
1379
  function idPath(id3) {
1325
- if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid5();
1380
+ if (typeof id3 != "string" || !FILE_ID_PATTERN.test(id3)) throw invalid6();
1326
1381
  return `/${id3}`;
1327
1382
  }
1328
1383
  async function multipartCreate(input, metadata, exchange, release = () => {
@@ -1365,18 +1420,18 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1365
1420
  if (!chunk || offset === chunk.byteLength) {
1366
1421
  chunk = void 0, offset = 0;
1367
1422
  let value2 = await next();
1368
- if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid5();
1423
+ if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid6();
1369
1424
  }
1370
1425
  let take = Math.min(length - filled, chunk.byteLength - offset);
1371
1426
  part.set(chunk.subarray(offset, offset + take), filled), filled += take, offset += take, offset === chunk.byteLength && (chunk = void 0, offset = 0);
1372
1427
  }
1373
1428
  }
1374
- if (part.byteLength !== length) throw invalid5();
1429
+ if (part.byteLength !== length) throw invalid6();
1375
1430
  if (reader && sent + length === metadata.size)
1376
1431
  for (lastProgress = Date.now(); ; ) {
1377
1432
  let value2 = await next();
1378
1433
  if (value2.done) break;
1379
- if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid5();
1434
+ if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid6();
1380
1435
  }
1381
1436
  let value = await request2((signal) => exchange(`${route}/part`, {
1382
1437
  method: "POST",
@@ -1390,7 +1445,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1390
1445
  }
1391
1446
  if (upload) for (let name of Object.keys(upload.file.enrichments)) {
1392
1447
  let bytes = await request2(() => upload.enrichment(name));
1393
- if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid5();
1448
+ if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid6();
1394
1449
  await request2((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
1395
1450
  method: "POST",
1396
1451
  headers: { "content-type": "application/octet-stream", "x-oddington-transfer": ticket },
@@ -1415,20 +1470,22 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1415
1470
  async function operation(work, initial, parent) {
1416
1471
  let context2 = initial ?? await resolveFilesContext();
1417
1472
  if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1418
- return active++, timed(async (signal) => {
1473
+ active++;
1474
+ let execute = async (signal2) => {
1419
1475
  try {
1420
- return await work(context2, signal);
1476
+ return await work(context2, signal2);
1421
1477
  } finally {
1422
1478
  active--;
1423
1479
  }
1424
- }, parent).catch((error) => {
1480
+ }, signal = context2.signal && parent ? AbortSignal.any([context2.signal, parent]) : context2.signal ?? parent;
1481
+ return context2.localFiles ? execute(signal ?? new AbortController().signal) : timed(execute, signal).catch((error) => {
1425
1482
  throw error instanceof FileOperationError ? error : unavailable();
1426
1483
  });
1427
1484
  }
1428
1485
  function contentPath(id3, name) {
1429
1486
  let path = idPath(id3);
1430
1487
  if (name === void 0) return `${path}/content`;
1431
- if (!safeEnrichmentName(name)) throw invalid5();
1488
+ if (!safeEnrichmentName(name)) throw invalid6();
1432
1489
  return `${path}/enrichments/${encodeURIComponent(name)}/content`;
1433
1490
  }
1434
1491
  async function read(id3, names) {
@@ -1437,12 +1494,12 @@ async function read(id3, names) {
1437
1494
  let path = contentPath(id3, names);
1438
1495
  return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
1439
1496
  }
1440
- if (!Array.isArray(names)) throw invalid5();
1497
+ if (!Array.isArray(names)) throw invalid6();
1441
1498
  let distinct = [], seen = /* @__PURE__ */ new Set();
1442
1499
  for (let name of names) {
1443
- if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid5();
1500
+ if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid6();
1444
1501
  if (!seen.has(name)) {
1445
- if (seen.size === 16) throw invalid5();
1502
+ if (seen.size === 16) throw invalid6();
1446
1503
  seen.add(name), distinct.push(name);
1447
1504
  }
1448
1505
  }
@@ -1477,11 +1534,11 @@ var files = {
1477
1534
  async create(input, options) {
1478
1535
  let context2 = await resolveFilesContext();
1479
1536
  if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "size", "path", "name", "storage", "csv"].includes(key)) || options !== void 0 && (!options || typeof options != "object" || Array.isArray(options) || Object.keys(options).some((key) => key !== "requestKey")))
1480
- throw invalid5();
1537
+ throw invalid6();
1481
1538
  let blob = input.file instanceof Blob, array3 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
1482
- if (!blob && !array3 && !stream) throw invalid5();
1539
+ if (!blob && !array3 && !stream) throw invalid6();
1483
1540
  let intrinsic = blob ? input.file.size : array3 ? input.file.byteLength : void 0;
1484
- if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid5();
1541
+ if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid6();
1485
1542
  let name = input.name;
1486
1543
  name === void 0 && blob && "name" in input.file && typeof input.file.name == "string" && (name = typeof globalThis.File < "u" && input.file instanceof globalThis.File ? input.file.name : input.file.name.split(/[\\/]/).at(-1));
1487
1544
  let metadata = parseFileCreateMetadata({
@@ -1493,17 +1550,38 @@ var files = {
1493
1550
  ...blob && input.file.type === "application/pdf" ? { inputMediaType: "application/pdf" } : {},
1494
1551
  requestKey: options?.requestKey === void 0 ? routineTransport()?.key("files") ?? crypto.randomUUID() : options.requestKey
1495
1552
  }, FILE_ORIGINAL_MAX_BYTES);
1496
- if (!context2.local && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
1553
+ if (!context2.local && !context2.localFiles && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
1497
1554
  let header = encodeURIComponent(JSON.stringify(metadata));
1498
- if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid5();
1555
+ if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid6();
1499
1556
  if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1500
- return active++, metadata.size > MAX_BYTES ? multipartCreate(input, metadata, (suffix, init2, kind, signal) => kind === !0 ? send(suffix, init2, !0, context2, signal) : send(suffix, init2, "control", context2, signal)) : timed(async (signal) => {
1557
+ if (active++, context2.localFiles && !routineTransport() && metadata.size > MAX_BYTES) {
1558
+ let signal = context2.signal ?? new AbortController().signal, file2 = input.file, offset = 0, body = file2 instanceof Blob ? context2.signal ? file2 : file2.stream() : file2 instanceof ReadableStream ? file2 : new ReadableStream({
1559
+ pull(controller) {
1560
+ if (offset === file2.byteLength) {
1561
+ controller.close();
1562
+ return;
1563
+ }
1564
+ let end = Math.min(offset + 256 * 1024, file2.byteLength);
1565
+ controller.enqueue(file2.subarray(offset, end)), offset = end;
1566
+ }
1567
+ }, { highWaterMark: 0 });
1568
+ try {
1569
+ return await send("", { method: "POST", headers: {
1570
+ "content-type": "application/octet-stream",
1571
+ "x-oddington-file": header
1572
+ }, body }, !0, context2, signal);
1573
+ } finally {
1574
+ active--;
1575
+ }
1576
+ }
1577
+ return metadata.size > MAX_BYTES ? multipartCreate(input, metadata, (suffix, init2, kind, signal) => kind === !0 ? send(suffix, init2, !0, context2, signal) : send(suffix, init2, "control", context2, signal)) : timed(async (signal) => {
1501
1578
  try {
1502
1579
  let bytes = array3 ? input.file.slice() : await boundedBytes(
1503
1580
  blob ? input.file.stream() : input.file,
1504
- metadata.size
1581
+ metadata.size,
1582
+ signal
1505
1583
  );
1506
- if (bytes.byteLength !== metadata.size) throw invalid5();
1584
+ if (bytes.byteLength !== metadata.size) throw invalid6();
1507
1585
  if (signal.aborted) throw unavailable();
1508
1586
  return await send("", {
1509
1587
  method: "POST",
@@ -1513,13 +1591,13 @@ var files = {
1513
1591
  } finally {
1514
1592
  active--;
1515
1593
  }
1516
- }).catch((error) => {
1594
+ }, context2.signal).catch((error) => {
1517
1595
  throw error instanceof FileOperationError ? error : unavailable();
1518
1596
  });
1519
1597
  },
1520
1598
  async enrich(input) {
1521
1599
  let context2 = await resolveFilesContext();
1522
- if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw invalid5();
1600
+ if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw invalid6();
1523
1601
  let path = `${idPath(input.file)}/enrichments`;
1524
1602
  if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
1525
1603
  throw new FileOperationError("request_too_large", 413);
@@ -1536,7 +1614,7 @@ var files = {
1536
1614
  ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
1537
1615
  ...input.replace === void 0 ? {} : { replace: input.replace }
1538
1616
  }, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
1539
- if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid5();
1617
+ if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid6();
1540
1618
  let result2 = await send(path, { method: "POST", headers: {
1541
1619
  "content-type": "application/octet-stream",
1542
1620
  "x-oddington-enrichment": header
@@ -1557,6 +1635,24 @@ function validGoogleScopes(value) {
1557
1635
 
1558
1636
  var ROUTINE_CONNECTION_CREDENTIALS_ENV = "ODDINGTON_ROUTINE_CONNECTION_CREDENTIALS";
1559
1637
  var connectionUuid = (v) => typeof v == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(v);
1638
+ function runtimeConnection(lease) {
1639
+ return lease.provider === "gmail" ? {
1640
+ id: `gmail/${lease.name}`,
1641
+ provider: lease.provider,
1642
+ name: lease.name,
1643
+ accountEmail: lease.accountEmail,
1644
+ scopes: [...lease.scopes],
1645
+ accessToken: lease.accessToken,
1646
+ expiresAt: lease.expiresAt
1647
+ } : {
1648
+ id: `airtable/${lease.name}`,
1649
+ provider: lease.provider,
1650
+ name: lease.name,
1651
+ baseId: lease.baseId,
1652
+ accessToken: lease.accessToken,
1653
+ runExpiresAt: lease.runExpiresAt
1654
+ };
1655
+ }
1560
1656
  function parseConnectionLease(raw, now = Date.now()) {
1561
1657
  let v = raw;
1562
1658
  if (!v || typeof v != "object" || Array.isArray(v) || !connectionUuid(v.connectionId) || !connectionUuid(v.runId) || typeof v.name != "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(v.name) || typeof v.accessToken != "string" || !/^[A-Za-z0-9._~+/-]{1,8192}={0,2}$/.test(v.accessToken))
@@ -1595,7 +1691,7 @@ function keys2(v, allowed, required = allowed) {
1595
1691
  function text2(v) {
1596
1692
  return typeof v == "string" && v.length > 0 && v.length <= 1024;
1597
1693
  }
1598
- function fields4(v, nonempty = !1) {
1694
+ function fields3(v, nonempty = !1) {
1599
1695
  let result2 = object3(v);
1600
1696
  (nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !text2(k))) && fail2("Invalid Airtable fields");
1601
1697
  try {
@@ -1606,7 +1702,7 @@ function fields4(v, nonempty = !1) {
1606
1702
  }
1607
1703
  function record2(v) {
1608
1704
  let r = object3(v);
1609
- return (!recordId(r.id) || r.createdTime !== void 0 && (typeof r.createdTime != "string" || !Number.isFinite(Date.parse(r.createdTime)))) && fail2("Malformed Airtable record"), { id: r.id, ...r.createdTime === void 0 ? {} : { createdTime: r.createdTime }, fields: fields4(r.fields) };
1705
+ return (!recordId(r.id) || r.createdTime !== void 0 && (typeof r.createdTime != "string" || !Number.isFinite(Date.parse(r.createdTime)))) && fail2("Malformed Airtable record"), { id: r.id, ...r.createdTime === void 0 ? {} : { createdTime: r.createdTime }, fields: fields3(r.fields) };
1610
1706
  }
1611
1707
  function equal(a, b) {
1612
1708
  if (a === b) return !0;
@@ -1618,7 +1714,9 @@ function equal(a, b) {
1618
1714
  ));
1619
1715
  }
1620
1716
  function createConnections(transport) {
1621
- return { airtable(name) {
1717
+ return { async get() {
1718
+ throw new Error("Connection unavailable");
1719
+ }, airtable(name) {
1622
1720
  (typeof name != "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(name)) && fail2("Invalid Airtable connection name");
1623
1721
  let call = (operation2, input) => transport(name, operation2, input);
1624
1722
  return {
@@ -1720,10 +1818,10 @@ async function executeAirtableOperation(authority, operation2, raw, options = {}
1720
1818
  mutation || fail2("Unsupported Airtable operation"), keys2(input, ["table", "records"]), (!Array.isArray(input.records) || !input.records.length || input.records.length > 10) && fail2("Invalid Airtable batch");
1721
1819
  let kind = operation2.slice(8), ids = /* @__PURE__ */ new Set(), records = input.records.map((value) => {
1722
1820
  let r = object3(value);
1723
- if (keys2(r, kind === "create" ? ["fields"] : kind === "update" ? ["id", "expected", "set"] : ["id", "expected"]), kind === "create") return { fields: fields4(r.fields, !0) };
1821
+ if (keys2(r, kind === "create" ? ["fields"] : kind === "update" ? ["id", "expected", "set"] : ["id", "expected"]), kind === "create") return { fields: fields3(r.fields, !0) };
1724
1822
  (!recordId(r.id) || ids.has(r.id)) && fail2("Invalid Airtable batch record ID"), ids.add(r.id);
1725
- let set = kind === "update" ? fields4(r.set, !0) : void 0;
1726
- return set && Object.values(set).some((value2) => value2 === null) && fail2("Airtable guard null cannot be an update value"), { id: r.id, expected: fields4(r.expected), ...set ? { set } : {} };
1823
+ let set = kind === "update" ? fields3(r.set, !0) : void 0;
1824
+ return set && Object.values(set).some((value2) => value2 === null) && fail2("Airtable guard null cannot be an update value"), { id: r.id, expected: fields3(r.expected), ...set ? { set } : {} };
1727
1825
  });
1728
1826
  for (let r of records) {
1729
1827
  if (!("id" in r)) continue;
@@ -1800,46 +1898,19 @@ async function reportLocalRoutineEffect(value) {
1800
1898
  await observer?.(value);
1801
1899
  }
1802
1900
 
1803
- var connections = /* @__PURE__ */ createConnections(async (name, operation2, input) => {
1804
- try {
1805
- let installed2 = routineTransport();
1806
- if (installed2) return await installed2.request("airtable", { name, operation: operation2, input: serializable(input) });
1807
- let managed = process.env[MANAGED_CONNECTION_CAPABILITY_ENV];
1808
- if (managed) {
1809
- let client = managedConnections(JSON.parse(managed)).airtable(name);
1810
- return operation2 === "tables.list" ? await client.tables.list() : await client.records[operation2.slice(8)](input);
1811
- }
1812
- let raw = JSON.parse(process.env[ROUTINE_CONNECTION_CREDENTIALS_ENV] ?? "[]");
1813
- if (!Array.isArray(raw)) throw new Error();
1814
- let leases = raw.map((value) => parseConnectionLease(value));
1815
- if (leases.some((lease2) => lease2.provider !== "airtable") || new Set(leases.map((lease2) => lease2.name)).size !== leases.length) throw new Error();
1816
- let lease = leases.find((lease2) => lease2.name === name);
1817
- if (!lease || lease.provider !== "airtable") throw new Error();
1818
- let writing = ["records.create", "records.update", "records.delete"].includes(operation2), captured = serializable(input), result2;
1819
- try {
1820
- result2 = await executeAirtableOperation(lease, operation2, captured);
1821
- } catch (error) {
1822
- throw writing && error instanceof AirtableOperationError && await reportLocalRoutineEffect({
1823
- type: "effect",
1824
- connection: `airtable/${name}`,
1825
- operation: operation2,
1826
- input: captured,
1827
- effect: error.effect,
1828
- receipts: error.receipts
1829
- }), error;
1830
- }
1831
- return writing && await reportLocalRoutineEffect({
1832
- type: "effect",
1833
- connection: `airtable/${name}`,
1834
- operation: operation2,
1835
- input: captured,
1836
- effect: "confirmed",
1837
- receipts: [result2.receipt]
1838
- }), result2;
1839
- } catch (error) {
1840
- throw error instanceof AirtableOperationError ? error : new AirtableOperationError("Airtable connection unavailable");
1841
- }
1901
+ var local;
1902
+ var airtable = /* @__PURE__ */ createConnections(async (name, operation2, input) => {
1903
+ throw new AirtableOperationError("Airtable connection unavailable");
1842
1904
  });
1905
+ function runtimeConnections() {
1906
+ return {
1907
+ ...airtable,
1908
+ async get(identity) {
1909
+ throw new Error("Connection unavailable");
1910
+ }
1911
+ };
1912
+ }
1913
+ var connections = /* @__PURE__ */ runtimeConnections();
1843
1914
 
1844
1915
  var LOCAL_ROUTINE_VALUE_BYTES = 256 * 1024;
1845
1916
 
@@ -1965,11 +2036,11 @@ function array2(value) {
1965
2036
  return !!descriptor?.enumerable && "value" in descriptor;
1966
2037
  })), value;
1967
2038
  }
1968
- function json2(value, ancestors = /* @__PURE__ */ new Set()) {
2039
+ function json(value, ancestors = /* @__PURE__ */ new Set()) {
1969
2040
  if (value === null || typeof value == "boolean" || typeof value == "string" || typeof value == "number" && Number.isFinite(value)) return value;
1970
2041
  assert(value && typeof value == "object" && !ancestors.has(value)), ancestors.add(value);
1971
2042
  try {
1972
- return Array.isArray(value) ? array2(value).map((entry) => json2(entry, ancestors)) : Object.fromEntries(Object.entries(object4(value)).map(([key, entry]) => [key, json2(entry, ancestors)]));
2043
+ return Array.isArray(value) ? array2(value).map((entry) => json(entry, ancestors)) : Object.fromEntries(Object.entries(object4(value)).map(([key, entry]) => [key, json(entry, ancestors)]));
1973
2044
  } finally {
1974
2045
  ancestors.delete(value);
1975
2046
  }
@@ -2025,7 +2096,7 @@ function inboxFile(value) {
2025
2096
  let details = object4(file2.details);
2026
2097
  details.kind === "csv" ? (keys3(details, ["kind", "encoding", "delimiter", "headerRow", "dataRows"]), assert(file2.mediaType === "text/csv" && ["utf-8", "windows-1252"].includes(String(details.encoding)) && [",", ";", " "].includes(String(details.delimiter)) && integer(details.headerRow, 0) && integer(details.dataRows, 0))) : details.kind === "pdf" ? (keys3(details, ["kind", "pages"], ["kind"]), assert(file2.mediaType === "application/pdf" && (!("pages" in details) || integer(details.pages)))) : (keys3(details, ["kind"]), assert(details.kind === "other" && !["text/csv", "application/pdf"].includes(file2.mediaType)));
2027
2098
  }
2028
- function fields5(value) {
2099
+ function fields4(value) {
2029
2100
  let labels = array2(value).map((value2) => {
2030
2101
  let field = object4(value2);
2031
2102
  return keys3(field, ["label", "value"]), assert(text3(field.label) && text3(field.value)), field.label;
@@ -2050,13 +2121,13 @@ function block(value) {
2050
2121
  ["kind", "label", entry.kind === "record" ? "record" : entry.kind === "records" ? "records" : "files"]
2051
2122
  ), assert(text3(entry.label) && (!("initiallyExpanded" in entry) || typeof entry.initiallyExpanded == "boolean") && (!("view" in entry) || text3(entry.view) && entry.view === entry.view.trim())), entry.kind === "record") {
2052
2123
  let record3 = object4(entry.record);
2053
- keys3(record3, ["ref", "title", "fields"]), assert(text3(record3.ref) && record3.ref === record3.ref.trim() && text3(record3.title)), fields5(record3.fields);
2124
+ keys3(record3, ["ref", "title", "fields"]), assert(text3(record3.ref) && record3.ref === record3.ref.trim() && text3(record3.title)), fields4(record3.fields);
2054
2125
  return;
2055
2126
  }
2056
2127
  if (entry.kind === "records") {
2057
2128
  let records = array2(entry.records), refs = records.map((value2) => {
2058
2129
  let record3 = object4(value2);
2059
- return keys3(record3, ["ref", "title", "description", "facts", "view"], ["ref", "title"]), assert(text3(record3.ref) && record3.ref === record3.ref.trim() && text3(record3.title)), "description" in record3 && assert(text3(record3.description)), "facts" in record3 && fields5(record3.facts), "view" in record3 && assert(text3(record3.view) && record3.view === record3.view.trim()), record3.ref;
2130
+ return keys3(record3, ["ref", "title", "description", "facts", "view"], ["ref", "title"]), assert(text3(record3.ref) && record3.ref === record3.ref.trim() && text3(record3.title)), "description" in record3 && assert(text3(record3.description)), "facts" in record3 && fields4(record3.facts), "view" in record3 && assert(text3(record3.view) && record3.view === record3.view.trim()), record3.ref;
2060
2131
  });
2061
2132
  assert(records.length > 0 && new Set(refs).size === refs.length);
2062
2133
  return;
@@ -2068,12 +2139,12 @@ function response(value) {
2068
2139
  let answer = object4(value);
2069
2140
  return assert(Object.keys(answer).every((key) => ["selection", "note"].includes(key))), typeof answer.selection == "string" ? assert(text3(answer.selection) && answer.selection === answer.selection.trim()) : recordReference(answer.selection), Object.hasOwn(answer, "note") && assert(text3(answer.note)), answer;
2070
2141
  }
2071
- function parseInboxRequest(value, questionListContext = "local") {
2142
+ function parseInboxRequest(value) {
2072
2143
  try {
2073
2144
  let envelope = object4(value);
2074
2145
  assert(Object.keys(envelope).sort().join(",") === "input,operation"), assert(typeof envelope.operation == "string" && Object.hasOwn(operations, envelope.operation));
2075
2146
  let operation2 = envelope.operation, input = { ...object4(envelope.input) }, required = operations[operation2];
2076
- assert(required.every((key) => Object.hasOwn(input, key)) && Object.keys(input).every((key) => required.includes(key) || operation2 === "questions.searchRecords" && key === "selected" || (operation2 === "items.list" || operation2 === "questions.list") && key === "beforeNumber" || operation2 === "questions.list" && questionListContext === "hosted" && key === "routines")), operation2 === "questions.list" && questionListContext === "hosted" && (assert(Object.hasOwn(input, "routines")), assert(array2(input.routines).every(isAppRoutineName)));
2147
+ assert(required.every((key) => Object.hasOwn(input, key)) && Object.keys(input).every((key) => required.includes(key) || operation2 === "questions.searchRecords" && key === "selected" || (operation2 === "items.list" || operation2 === "questions.list") && key === "beforeNumber" || operation2 === "questions.list" && key === "routines")), operation2 === "questions.list" && (assert(Object.hasOwn(input, "routines")), assert(array2(input.routines).every(isAppRoutineName)));
2077
2148
  for (let key of ["itemId", "personId", "fileId"]) key in input && assert(id2(input[key]));
2078
2149
  return "revision" in input && assert(integer(input.revision)), "beforeNumber" in input && assert(integer(input.beforeNumber)), "questionId" in input && assert(text3(input.questionId) && input.questionId === input.questionId.trim()), "title" in input && assert(text3(input.title)), "lifecycle" in input && assert(input.lifecycle === "open" || input.lifecycle === "closed"), "query" in input && assert(text3(input.query, !0) && input.query.length <= 256), "selected" in input && recordReference(input.selected), "response" in input && response(input.response), assert(new TextEncoder().encode(JSON.stringify(envelope)).byteLength <= INBOX_INPUT_BYTES), "routines" in input && (input.routines = [...new Set(input.routines)]), { operation: operation2, input };
2079
2150
  } catch {
@@ -2088,10 +2159,10 @@ function parseInboxCurrent(value) {
2088
2159
  };
2089
2160
  }
2090
2161
  function parseInboxItem(value) {
2091
- let item = object4(json2(value));
2092
- return assert(id2(item.id) && id2(item.workspaceId) && integer(item.number) && integer(item.revision) && integer(item.activityVersion, 0) && ["ask", "digest"].includes(String(item.kind)) && ["open", "closed"].includes(String(item.lifecycle)) && text3(item.title) && text3(item.description, !0) && text3(item.author) && date(item.publishedAt) && optionalDate(item.seenAt) && optionalDate(item.digestReadAt)), item.outcome !== null && assert(text3(object4(item.outcome).outcome)), array2(item.body).forEach(block), array2(item.views).forEach((value2) => {
2162
+ let item = object4(json(value));
2163
+ return assert(id2(item.id) && id2(item.workspaceId) && integer(item.number) && integer(item.revision) && integer(item.activityVersion, 0) && ["ask", "digest"].includes(String(item.kind)) && ["open", "closed"].includes(String(item.lifecycle)) && text3(item.title) && text3(item.description, !0) && text3(item.author) && date(item.publishedAt) && optionalDate(item.seenAt) && optionalDate(item.digestReadAt)), item.outcome !== null && assert(text3(object4(item.outcome).outcome)), "canonicalRoutineId" in item && assert(item.canonicalRoutineId === null || isAppRoutineName(item.canonicalRoutineId)), item.kind === "ask" ? askMetadata(item) : assert(!("tags" in item) && !("recordRefs" in item)), array2(item.body).forEach(block), array2(item.views).forEach((value2) => {
2093
2164
  let view = object4(value2);
2094
- assert(text3(view.id) && text3(view.view) && text3(view.implementation)), json2(view.input);
2165
+ assert(text3(view.id) && text3(view.view) && text3(view.implementation)), json(view.input);
2095
2166
  }), array2(item.people).forEach((value2) => {
2096
2167
  let person = object4(value2);
2097
2168
  assert(id2(person.id) && text3(person.name));
@@ -2127,18 +2198,26 @@ function parseInboxItem(value) {
2127
2198
  }), item;
2128
2199
  }
2129
2200
  function parseAnswerableQuestion(value) {
2130
- let entry = object4(json2(value));
2131
- keys3(entry, ["item", "origin", "question", "recordRefs"]);
2132
- let item = object4(entry.item);
2133
- keys3(item, ["id", "number", "revision", "title", "href"]), assert(id2(item.id) && integer(item.number) && integer(item.revision) && text3(item.title) && text3(item.href));
2134
- let link = new URL(item.href), slug = link.hostname.slice(0, -13);
2135
- assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && item.href === `https://${slug}.oddington.ai/inbox/${item.id}`);
2136
- let origin = object4(entry.origin);
2137
- keys3(origin, ["routine"]), assert(text3(origin.routine) && origin.routine === origin.routine.trim());
2138
- let question2 = object4(entry.question);
2139
- keys3(question2, ["id", "prompt", "instructions", "response"]), assert(text3(question2.id) && question2.id === question2.id.trim() && text3(question2.prompt) && (question2.instructions === null || text3(question2.instructions, !0))), responseDefinition(question2.response);
2140
- let refs = array2(entry.recordRefs);
2141
- return assert(refs.every((ref) => text3(ref) && ref === ref.trim()) && new Set(refs).size === refs.length), entry;
2201
+ let entry = object4(json(value));
2202
+ keys3(
2203
+ entry,
2204
+ ["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
2205
+ ["itemId", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
2206
+ ), assert(id2(entry.itemId) && integer(entry.revision) && text3(entry.title) && text3(entry.inboxUrl));
2207
+ let link = new URL(entry.inboxUrl), slug = link.hostname.slice(0, -13);
2208
+ return assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && entry.inboxUrl === `https://${slug}.oddington.ai/inbox/${entry.itemId}`), assert(isAppRoutineName(entry.routine) && text3(entry.questionId) && entry.questionId === entry.questionId.trim() && text3(entry.prompt) && (!("instructions" in entry) || text3(entry.instructions, !0)) && typeof entry.answerable == "boolean"), responseDefinition(entry.response), askMetadata(entry), entry;
2209
+ }
2210
+ function askMetadata(entry) {
2211
+ let tags = array2(entry.tags === void 0 ? [] : entry.tags);
2212
+ assert(tags.length <= 32 && tags.every((tag) => text3(tag) && new TextEncoder().encode(tag).byteLength <= 64)), assert(new Set(tags).size === tags.length);
2213
+ let refs = array2(entry.recordRefs === void 0 ? [] : entry.recordRefs);
2214
+ refs.forEach((value) => {
2215
+ let ref = object4(value);
2216
+ keys3(ref, ["repository", "id"]), recordReference({ repository: ref.repository, ref: ref.id });
2217
+ }), assert(new Set(refs.map((value) => {
2218
+ let ref = object4(value);
2219
+ return JSON.stringify([ref.repository, ref.id]);
2220
+ })).size === refs.length), entry.tags = tags, entry.recordRefs = refs;
2142
2221
  }
2143
2222
  function parseInboxAcceptance(value) {
2144
2223
  let accepted = object4(value);
@@ -2368,10 +2447,12 @@ function appContext(origin, active2) {
2368
2447
  credentials: "omit",
2369
2448
  redirect: "error",
2370
2449
  cache: "no-store",
2450
+ ...init2.body instanceof ReadableStream ? { duplex: "half" } : {},
2371
2451
  referrerPolicy: "no-referrer",
2372
2452
  signal,
2373
2453
  headers: {
2374
2454
  ...init2.body === void 0 ? {} : { "content-type": "application/json" },
2455
+ ...Object.fromEntries(new Headers(init2.headers)),
2375
2456
  authorization: `Bearer ${candidate}`
2376
2457
  }
2377
2458
  });
@@ -2537,11 +2618,37 @@ function appContext(origin, active2) {
2537
2618
  async function requestRoutine(key, suffix, init2 = {}) {
2538
2619
  return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, init2);
2539
2620
  }
2540
- async function requestChecked(path, init2, inbox2 = !1) {
2621
+ async function requestRetainedRoutine(key, suffix) {
2622
+ return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, {}, !1, !0);
2623
+ }
2624
+ async function requestFiles(suffix, init2, parent) {
2625
+ let unavailable3 = () => new FileOperationError("unsupported_context", 400);
2626
+ if (!current2() || !/^(?:|\/[0-9a-f-]{36}(?:\/(?:content|upload|enrichments(?:\/[^/?#]+\/content)?))?)$/i.test(suffix))
2627
+ throw unavailable3();
2628
+ let admitted = credential, signal = parent ? AbortSignal.any([access.signal, parent]) : access.signal, failure = () => current2() && !signal.aborted ? new FileOperationError("unavailable", 503, !0) : unavailable3();
2629
+ try {
2630
+ return await hostedContent("", init2, signal, (_url, request2) => untilAborted(
2631
+ send3(`files${suffix}`, admitted, signal, request2).then((value) => {
2632
+ if (signal.aborted)
2633
+ throw value.body?.cancel().catch(() => {
2634
+ }), unavailable3();
2635
+ return value;
2636
+ }),
2637
+ signal
2638
+ ), () => settledAccess(signal), failure);
2639
+ } catch {
2640
+ throw failure();
2641
+ }
2642
+ }
2643
+ async function requestChecked(path, init2, inbox2 = !1, retained2 = !1) {
2541
2644
  if (!current2()) throw new Error("Local app context unavailable.");
2542
- let admitted = credential, signal = access.signal, response2 = await send3(path, credential, signal, init2);
2543
- return await settledAccess(signal), (response2.status === 401 || !inbox2 && response2.status === 403) && admitted === credential && current2() && invalidate(), responseChecks.set(response2, async (value) => {
2544
- await settledAccess(signal), admitted === credential && current2() && value && typeof value == "object" && "error" in value && value.error === "authority_unavailable" && invalidate();
2645
+ let admitted = credential, signal = access.signal, response2 = await send3(path, credential, signal, init2), check = async () => {
2646
+ if (retained2) {
2647
+ if (signal.aborted || !current2()) throw new Error("Local app context unavailable.");
2648
+ } else await settledAccess(signal);
2649
+ };
2650
+ return await check(), (response2.status === 401 || !inbox2 && response2.status === 403) && admitted === credential && current2() && invalidate(), responseChecks.set(response2, async (value) => {
2651
+ await check(), admitted === credential && current2() && value && typeof value == "object" && "error" in value && value.error === "authority_unavailable" && invalidate();
2545
2652
  }), response2;
2546
2653
  }
2547
2654
  function context2() {
@@ -2558,8 +2665,10 @@ function appContext(origin, active2) {
2558
2665
  issued === credential && current2() && invalidate();
2559
2666
  },
2560
2667
  requestRoutine,
2668
+ requestRetainedRoutine,
2561
2669
  requestData,
2562
2670
  requestInbox,
2671
+ requestFiles,
2563
2672
  requestAvailability: (key) => requestRoutine(key, "availability", { method: "GET" })
2564
2673
  };
2565
2674
  }
@@ -2568,22 +2677,22 @@ function appContext(origin, active2) {
2568
2677
  try {
2569
2678
  if (!alive()) throw new Error();
2570
2679
  if (!pair) {
2571
- let candidate2 = stored(), retained2 = readPair(candidate2);
2572
- pair = retained2, binding = { ...retained2.context }, credential = retained2.credential, serialized = candidate2;
2680
+ let candidate2 = stored(), retained3 = readPair(candidate2);
2681
+ pair = retained3, binding = { ...retained3.context }, credential = retained3.credential, serialized = candidate2;
2573
2682
  }
2574
2683
  if (expireAccess(), binding.expiresAt <= Date.now()) {
2575
2684
  if (await renew(), !current2()) throw new AppRenewalUnavailable();
2576
2685
  return context2();
2577
2686
  }
2578
2687
  await synchronize();
2579
- let candidate = stored(), retained = readPair(candidate);
2688
+ let candidate = stored(), retained2 = readPair(candidate);
2580
2689
  if (attempted = candidate ?? void 0, !current2()) throw new AppRenewalUnavailable();
2581
- let value = await proof(retained.credential);
2690
+ let value = await proof(retained2.credential);
2582
2691
  if (stored() !== candidate || serialized !== candidate)
2583
2692
  return await synchronize(), context2();
2584
2693
  if (!current2()) throw new Error();
2585
2694
  if (expiry && binding && value.expiresAt > binding.expiresAt) throw new Error();
2586
- return (!expiry || value.expiresAt !== binding.expiresAt) && install(value, retained, candidate), context2();
2695
+ return (!expiry || value.expiresAt !== binding.expiresAt) && install(value, retained2, candidate), context2();
2587
2696
  } catch (error) {
2588
2697
  if (alive() && error instanceof AppRenewalUnavailable)
2589
2698
  throw new Error();
@@ -2598,7 +2707,12 @@ function appContext(origin, active2) {
2598
2707
  }, resolve = () => resolution2 || (resolution2 = resolveOnce().finally(() => {
2599
2708
  resolution2 = void 0;
2600
2709
  }), resolution2);
2601
- return { resolve, start: () => {
2710
+ return { resolve, retained: async () => {
2711
+ if (!expiry && alive() && (binding ? current2() && resolution2 : readPair(stored()).context.expiresAt > Date.now()))
2712
+ return resolve();
2713
+ if (!expiry || !current2()) throw new Error("Local app context unavailable.");
2714
+ return context2();
2715
+ }, start: () => {
2602
2716
  startup = setTimeout(() => {
2603
2717
  alive() && !resolution2 && !binding && resolve().catch(() => {
2604
2718
  });
@@ -2624,13 +2738,13 @@ function hostFailure(error, context2) {
2624
2738
  return !context2.isCurrent() || context2.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") : unavailable2();
2625
2739
  }
2626
2740
  async function send2(operation2, input) {
2627
- let envelope = operation2 === "questions.list" ? void 0 : parseInboxRequest({ operation: operation2, input }), context2;
2741
+ let envelope = parseInboxRequest({ operation: operation2, input }), context2;
2628
2742
  try {
2629
2743
  context2 = await resolveAppContext();
2630
2744
  } catch {
2631
2745
  throw stale();
2632
2746
  }
2633
- if (envelope ??= parseInboxRequest({ operation: operation2, input }, context2.kind === "local" ? "local" : "hosted"), context2.kind === "local") {
2747
+ if (context2.kind === "local") {
2634
2748
  if (!isAppQuestionOperation(operation2)) throw new InboxOperationError(403, "access_denied");
2635
2749
  let check2 = () => {
2636
2750
  if (!context2.isCurrent() || context2.signal.aborted || context2.expiresAt <= Date.now()) throw stale();
@@ -2651,16 +2765,18 @@ async function send2(operation2, input) {
2651
2765
  }
2652
2766
  if (context2.endpoint !== `https://${context2.workspace}.oddington.ai` || ["auth", "www", "api", "os"].includes(context2.workspace)) throw stale();
2653
2767
  let host;
2654
- try {
2655
- host = await resolveHostedInboxContext(context2);
2656
- } catch (error) {
2657
- throw hostFailure(error, context2);
2768
+ if (!isAppQuestionOperation(operation2)) {
2769
+ try {
2770
+ host = await resolveHostedInboxContext(context2);
2771
+ } catch (error) {
2772
+ throw hostFailure(error, context2);
2773
+ }
2774
+ if (!host) throw unavailable2();
2658
2775
  }
2659
- if (!host) throw unavailable2();
2660
2776
  let check = () => {
2661
- if (!context2.isCurrent() || !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
2777
+ if (!context2.isCurrent() || host && !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
2662
2778
  };
2663
- if (check(), host.context.kind === "focused" && !isAppQuestionOperation(operation2))
2779
+ if (check(), host?.context.kind === "focused")
2664
2780
  throw new InboxOperationError(403, "access_denied");
2665
2781
  try {
2666
2782
  let response2 = await fetch(`${context2.endpoint}/api/inbox`, {
@@ -2768,33 +2884,24 @@ var inbox = {
2768
2884
  },
2769
2885
  questions: {
2770
2886
  async list(input) {
2771
- let supplied = input === void 0 ? void 0 : parseInboxRequest({ operation: "questions.list", input }, "hosted").input;
2772
- if (supplied && Object.hasOwn(supplied, "beforeNumber")) throw new InboxOperationError(400, "invalid_input");
2773
- let routines = supplied ? Object.freeze(supplied.routines) : void 0, questions = [], beforeNumber, initial;
2887
+ let supplied = parseInboxRequest({ operation: "questions.list", input }).input;
2888
+ if (Object.hasOwn(supplied, "beforeNumber")) throw new InboxOperationError(400, "invalid_input");
2889
+ let routines = Object.freeze(supplied.routines), questions = [], beforeNumber, initial;
2774
2890
  try {
2775
2891
  initial = await resolveAppContext();
2776
2892
  } catch {
2777
2893
  throw stale();
2778
2894
  }
2779
- if (initial.kind === "local" ? input !== void 0 : routines === void 0)
2780
- throw new InboxOperationError(400, "invalid_input");
2781
- let host;
2782
- try {
2783
- host = initial.kind !== "local" && await resolveHostedInboxContext(initial);
2784
- } catch (error) {
2785
- throw hostFailure(error, initial);
2786
- }
2787
- if (initial.kind !== "local" && !host) throw unavailable2();
2788
2895
  let check = () => {
2789
- if (!initial.isCurrent() || host && !host.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
2896
+ if (!initial.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
2790
2897
  };
2791
2898
  do {
2792
2899
  check();
2793
2900
  let page = await send2("questions.list", {
2794
- ...routines === void 0 ? {} : { routines },
2901
+ routines,
2795
2902
  ...beforeNumber === void 0 ? {} : { beforeNumber }
2796
2903
  });
2797
- if (check(), page.questions.some((question2) => question2.item.href !== `https://${initial.workspace}.oddington.ai/inbox/${question2.item.id}` || routines !== void 0 && !routines.includes(question2.origin.routine)) || beforeNumber !== void 0 && (page.questions.some((question2) => question2.item.number >= beforeNumber) || page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber)) throw unavailable2();
2904
+ if (check(), page.questions.some((question2) => question2.inboxUrl !== `https://${initial.workspace}.oddington.ai/inbox/${question2.itemId}` || !routines.includes(question2.routine)) || beforeNumber !== void 0 && page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber) throw unavailable2();
2798
2905
  if (questions.push(...page.questions), page.nextBeforeNumber === null) return questions;
2799
2906
  beforeNumber = page.nextBeforeNumber;
2800
2907
  } while (!0);
@@ -2831,8 +2938,8 @@ function init({ auth: input }) {
2831
2938
  url.protocol === "https:" && !url.port && !url.username && !url.password && !url.search && !url.hash && url.pathname === "/" && /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(slug) && slug !== "auth" && (endpoint = url.origin, workspace = slug);
2832
2939
  } catch {
2833
2940
  }
2834
- let active2 = !0, revision = 0, person, token, binding = {}, local2 = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, uninstall = installMemberContext(async () => {
2835
- if (local2) return local2.resolve();
2941
+ let active2 = !0, revision = 0, person, token, binding = {}, local3 = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, resolve = async () => {
2942
+ if (local3) return local3.resolve();
2836
2943
  if (!active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
2837
2944
  let started = revision, { data: { session }, error } = await auth2.getSession();
2838
2945
  if (!active2 || globalThis.location.origin !== endpoint || started !== revision || error || !session || person !== void 0 && person !== session.user.id)
@@ -2851,13 +2958,13 @@ function init({ auth: input }) {
2851
2958
  memberId: session.user.id,
2852
2959
  binding
2853
2960
  };
2854
- }), dispose = () => {
2855
- active2 && (active2 = !1, local2?.dispose(), revision++, subscription?.unsubscribe(), stopDisposal?.(), uninstall(), installedDispose === dispose && (installedDispose = void 0));
2961
+ }, uninstall = installMemberContext(resolve, local3 ? local3.retained : resolve), dispose = () => {
2962
+ active2 && (active2 = !1, local3?.dispose(), revision++, subscription?.unsubscribe(), stopDisposal?.(), uninstall(), installedDispose === dispose && (installedDispose = void 0));
2856
2963
  };
2857
2964
  installedDispose = dispose, stopDisposal = registered?.onDispose(dispose), active2 && (subscription = auth2.onAuthStateChange((event, session) => {
2858
2965
  let next = session?.user.id ?? null;
2859
- (event === "SIGNED_OUT" || person !== void 0 && next !== person || registered && person !== void 0 && event === "SIGNED_IN" && token !== session?.access_token) && (revision++, local2?.invalidate()), person = next, token = session?.access_token;
2860
- }).data.subscription, local2?.start());
2966
+ (event === "SIGNED_OUT" || person !== void 0 && next !== person || registered && person !== void 0 && event === "SIGNED_IN" && token !== session?.access_token) && (revision++, local3?.invalidate()), person = next, token = session?.access_token;
2967
+ }).data.subscription, local3?.start());
2861
2968
  }
2862
2969
  var os = { init };
2863
2970
 
@@ -3217,9 +3324,9 @@ async function provider(configuration, guard) {
3217
3324
  let result2 = new Response(
3218
3325
  [204, 205, 304].includes(response2.status) ? null : body,
3219
3326
  { status: response2.status, statusText: response2.statusText, headers: response2.headers }
3220
- ), json3 = result2.json.bind(result2);
3327
+ ), json2 = result2.json.bind(result2);
3221
3328
  return result2.json = async () => {
3222
- let value = await json3();
3329
+ let value = await json2();
3223
3330
  return (!guard.current(revision) || request2 && !request2.current()) && rejectStale(), value && typeof value.access_token == "string" && provenance.set(value.access_token, revision), value;
3224
3331
  }, result2;
3225
3332
  }, { preconnect: fetch.preconnect })
@@ -3270,6 +3377,22 @@ async function provider(configuration, guard) {
3270
3377
  }
3271
3378
  var auth = /* @__PURE__ */ createBrowserAuth({ provider, failure: (reason) => new BrowserAuthError(reason) });
3272
3379
 
3380
+ function routineRunHandle(operations2) {
3381
+ return Object.freeze({
3382
+ current: operations2.current,
3383
+ step: operations2.step,
3384
+ ...operations2.publish ? { publish: operations2.publish } : {},
3385
+ async *watch() {
3386
+ let previous;
3387
+ for (; ; ) {
3388
+ let state = await operations2.current(), encoded = JSON.stringify(state);
3389
+ if (encoded !== previous && (previous = encoded, yield state), state.status === "succeeded" || state.status === "failed") return;
3390
+ await (operations2.wait?.() ?? new Promise((resolve) => setTimeout(resolve, 100)));
3391
+ }
3392
+ }
3393
+ });
3394
+ }
3395
+
3273
3396
  var identifier = /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/, uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}(?![\s\S])/i, SUMMARY_BYTES = 17 * 1024 * 1024, AppRoutineError = class extends Error {
3274
3397
  constructor(reason) {
3275
3398
  super(reason);
@@ -3286,16 +3409,16 @@ function current(context2) {
3286
3409
  function appDescriptors() {
3287
3410
  return globalThis[/* @__PURE__ */ Symbol.for("oddington.app.descriptor")]?.routines ?? [];
3288
3411
  }
3289
- async function local() {
3290
- let context2 = await resolveAppContext().catch(() => fail3("authority_unavailable"));
3412
+ async function local2(retained = !1) {
3413
+ let context2 = await resolveAppContext(retained).catch(() => fail3("authority_unavailable"));
3291
3414
  return context2.kind !== "local" ? fail3("execution_unavailable") : (current(context2), context2);
3292
3415
  }
3293
- async function request(key, suffix, init2, maximum = SUMMARY_BYTES, retained) {
3416
+ async function request(key, suffix, init2, maximum = SUMMARY_BYTES, retained, read2 = !1) {
3294
3417
  (!identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable");
3295
- let context2 = retained ?? await local();
3418
+ let context2 = retained ?? await local2(read2);
3296
3419
  current(context2);
3297
3420
  try {
3298
- let response2 = await context2.requestRoutine(key, suffix, init2), value = await appResponse(response2, maximum, context2.signal);
3421
+ let response2 = await (read2 ? context2.requestRetainedRoutine(key, suffix) : context2.requestRoutine(key, suffix, init2)), value = await appResponse(response2, maximum, context2.signal);
3299
3422
  if (current(context2), !response2.ok) {
3300
3423
  let reason = value?.error;
3301
3424
  reason === "authority_unavailable" && (context2.invalidate(), fail3(reason)), (reason === "invalid_input" || reason === "execution_unavailable") && fail3(reason), fail3("execution_unavailable");
@@ -3341,21 +3464,15 @@ function structure(value) {
3341
3464
  return JSON.stringify(value, (_key, item) => item && typeof item == "object" && !Array.isArray(item) ? Object.fromEntries(Object.keys(item).sort().map((key) => [key, item[key]])) : item);
3342
3465
  }
3343
3466
  function handle(key, id3, context2) {
3344
- (typeof id3 != "string" || !uuid.test(id3)) && fail3("invalid_input");
3345
- let read2 = async () => summary(await request(key, `runs/${id3}`, void 0, SUMMARY_BYTES, context2), key, id3);
3346
- return Object.freeze({
3347
- current: read2,
3348
- async *watch() {
3349
- let previous;
3350
- for (; ; ) {
3351
- let state = await read2(), encoded = JSON.stringify(state);
3352
- if (encoded !== previous && (previous = encoded, yield state), state.status === "succeeded" || state.status === "failed") return;
3353
- await new Promise((resolve) => setTimeout(resolve, 100));
3354
- }
3467
+ (!identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable"), (typeof id3 != "string" || !uuid.test(id3)) && fail3("invalid_input");
3468
+ let read2 = async () => summary(await request(key, `runs/${id3}`, void 0, SUMMARY_BYTES, context2, !0), key, id3);
3469
+ return routineRunHandle({
3470
+ async current() {
3471
+ return current(context2), read2();
3355
3472
  },
3356
3473
  async step(step) {
3357
3474
  (typeof step != "string" || !identifier.test(step)) && fail3("invalid_input");
3358
- let value = await request(key, `runs/${id3}/steps/${step}`, void 0, 514 * 1024, context2);
3475
+ let value = await request(key, `runs/${id3}/steps/${step}`, void 0, 514 * 1024, context2, !0);
3359
3476
  return (!only(value, "id,title,status,startedAt,finishedAt,summary,data") || value.id !== step || !validStep(value)) && fail3("execution_unavailable"), value;
3360
3477
  },
3361
3478
  async publish() {
@@ -3394,19 +3511,18 @@ function appRoutineBinding(key) {
3394
3511
  } catch {
3395
3512
  return fail3("invalid_input");
3396
3513
  }
3397
- let context2 = await local(), run = summary(await request(key, "runs", { method: "POST", body: encoded }, SUMMARY_BYTES, context2), key);
3514
+ let context2 = await local2(), run = summary(await request(key, "runs", { method: "POST", body: encoded }, SUMMARY_BYTES, context2), key);
3398
3515
  return handle(key, run.id, context2);
3399
3516
  },
3400
3517
  runs: Object.freeze({
3401
3518
  async list() {
3402
- let value = await request(key, "runs", void 0, 20 * SUMMARY_BYTES);
3519
+ let value = await request(key, "runs", void 0, 20 * SUMMARY_BYTES, void 0, !0);
3403
3520
  if (!Array.isArray(value) || value.length > 20) return fail3("execution_unavailable");
3404
3521
  let runs = value.map((run) => summary(run, key));
3405
3522
  return new Set(runs.map((run) => run.id)).size !== runs.length && fail3("execution_unavailable"), runs;
3406
3523
  },
3407
3524
  async get(id3) {
3408
- let run = handle(key, id3, await local());
3409
- return await run.current(), run;
3525
+ return (typeof id3 != "string" || !uuid.test(id3)) && fail3("invalid_input"), (!identifier.test(key) || !appDescriptors().some((item) => item.id === key)) && fail3("authority_unavailable"), handle(key, id3, await local2(!0));
3410
3526
  }
3411
3527
  })
3412
3528
  });
@@ -3453,7 +3569,7 @@ function routineDataEnvelope(command) {
3453
3569
  }
3454
3570
 
3455
3571
  function routinePublicationClient2(options = {}) {
3456
- let environment = {}, installed2 = routineTransport(), local2 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.ODDINGTON_ROUTINE_WORKSPACE, capability = options.capability ?? environment.ODDINGTON_ROUTINE_RUN;
3572
+ let environment = {}, installed2 = routineTransport(), local3 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.ODDINGTON_ROUTINE_WORKSPACE, capability = options.capability ?? environment.ODDINGTON_ROUTINE_RUN;
3457
3573
  if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
3458
3574
  throw new Error("A workspace and valid optional routine capability are required");
3459
3575
  let workingRoot = options.workingRoot ?? environment.ODDINGTON_INBOX_WORKING_ROOT ?? void 0, headers = capability ? { "x-oddington-run": capability } : {}, request2 = options.request ?? (capability ? async (path, init2) => {
@@ -3466,7 +3582,7 @@ function routinePublicationClient2(options = {}) {
3466
3582
  throw new Error("Member publication requires a host-supplied request");
3467
3583
  });
3468
3584
  async function send3(operation2, body) {
3469
- if (local2) return await local2(operation2, body);
3585
+ if (local3) return await local3(operation2, body);
3470
3586
  let writing = operation2 === "records/update", reading = operation2 === "records/read", response2 = await request2(writing || reading ? "/api/data" : `/api/inbox/${operation2}`, {
3471
3587
  method: "POST",
3472
3588
  headers: {
@@ -3513,7 +3629,7 @@ function routinePublicationClient2(options = {}) {
3513
3629
  files: {
3514
3630
  async add(value) {
3515
3631
  let input = validateFileAddOptions(value);
3516
- if (local2) return validateInboxFile(await local2("files/add", input));
3632
+ if (local3) return validateInboxFile(await local3("files/add", input));
3517
3633
  throw workingRoot ? new Error("Inbox file reads require a Node working root") : new Error("Inbox file reads require a working root");
3518
3634
  }
3519
3635
  },