@oddington/sdk 0.1.44 → 0.1.46

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
@@ -319,6 +319,52 @@ function validateRoutineSchemaValue(schema2, value, rejected) {
319
319
  check(schema2, value, "$");
320
320
  }
321
321
 
322
+ function validDropboxRootPath(value) {
323
+ return typeof value == "string" && value.length <= 2048 && value.startsWith("/") && !/[\\\x00-\x1f\x7f]/.test(value) && value.slice(1).split("/").every((segment) => segment.length > 0 && segment.trim() === segment && segment !== "." && segment !== "..");
324
+ }
325
+ function validMicrosoftId(value) {
326
+ return typeof value == "string" && /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(value);
327
+ }
328
+ function validMicrosoftMailbox(value) {
329
+ return typeof value == "string" && value.length <= 254 && /^[^\s@/?#\\\x00-\x1f\x7f]+@[^\s@/?#\\\x00-\x1f\x7f]+\.[^\s@/?#\\\x00-\x1f\x7f]+$/.test(value);
330
+ }
331
+ function sharePointHost(value) {
332
+ return /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.sharepoint\.com$/.test(value);
333
+ }
334
+ function canonicalSharePointSiteUrl(value) {
335
+ if (!(typeof value != "string" || value.length > 2048 || /[\s\\?#\x00-\x1f\x7f]/.test(value) || !/^https:\/\/[^/:@]+(?:\/|$)/i.test(value)))
336
+ try {
337
+ let url = new URL(value);
338
+ if (url.protocol !== "https:" || !sharePointHost(url.hostname) || url.username || url.password || url.port) return;
339
+ let rawPath = value.replace(/^https:\/\/[^/]+/i, "") || "/", path = rawPath.endsWith("/") ? rawPath.slice(0, -1) : rawPath, segments = path.slice(1).split("/");
340
+ if (path && segments.some((segment) => !segment)) return;
341
+ let encoded = path ? segments.map((segment) => {
342
+ let decoded = decodeURIComponent(segment);
343
+ if (decoded === "." || decoded === ".." || /[/%\\?#\x00-\x1f\x7f]/.test(decoded)) throw new Error();
344
+ return encodeURIComponent(decoded);
345
+ }).join("/") : "", canonical = `https://${url.hostname}/${encoded}`;
346
+ return canonical.length <= 2048 ? canonical : void 0;
347
+ } catch {
348
+ return;
349
+ }
350
+ }
351
+ function validSharePointSiteId(value, siteUrl) {
352
+ if (typeof value != "string" || value.length > 512) return !1;
353
+ let [host, collection, site, extra] = value.split(",");
354
+ return extra === void 0 && host === new URL(siteUrl).hostname && validMicrosoftId(collection) && validMicrosoftId(site);
355
+ }
356
+ function validGoogleScopes(value) {
357
+ return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every((scope) => typeof scope == "string" && scope.length <= 256 && /^(https:\/\/www\.googleapis\.com\/auth\/[A-Za-z0-9._-]+|https:\/\/mail\.google\.com\/|openid|email|profile)$/.test(scope)) && new Set(value).size === value.length;
358
+ }
359
+ var DROPBOX_FILE_SCOPES = ["account_info.read", "files.metadata.read", "files.content.read", "files.content.write"];
360
+ function validDropboxFileScopes(value) {
361
+ return Array.isArray(value) && value.length === DROPBOX_FILE_SCOPES.length && new Set(value).size === value.length && DROPBOX_FILE_SCOPES.every((scope) => value.includes(scope));
362
+ }
363
+
364
+ function validDataRepositoryName(value) {
365
+ return typeof value == "string" && /^[a-z0-9][a-z0-9._-]{0,127}$/.test(value) && !value.includes("..");
366
+ }
367
+
322
368
  var InboxContractError = class extends Error {
323
369
  constructor(message2) {
324
370
  super(message2), this.name = "InboxContractError";
@@ -575,9 +621,26 @@ function defineHandler(value) {
575
621
  function respond(handler, input) {
576
622
  return defineHandler(handler), handlerReference({ id: handler.id, input });
577
623
  }
624
+ function recordRequirements(value) {
625
+ let source2 = object(value, "Record requirements");
626
+ keys(source2, ["repository", "records"], "Record requirements"), validDataRepositoryName(source2.repository) || fail("Invalid requirements repository");
627
+ let repository = source2.repository, records = array(source2.records, "required Records").map((entry) => {
628
+ let row = object(entry, "required Record");
629
+ keys(row, ["ref", "version"], "required Record");
630
+ let { ref } = validateRecordReference({ repository, ref: row.ref });
631
+ return (typeof row.version != "string" || !row.version.length || row.version.length > 512) && fail("Invalid required Record version"), { ref, version: row.version };
632
+ });
633
+ return new Set(records.map((record4) => record4.ref)).size !== records.length && fail("Duplicate required Record"), { repository, records };
634
+ }
635
+ function requireRecords(repository, records) {
636
+ return recordRequirements({ repository, records: array(records, "required Records").map((entry) => {
637
+ let record4 = object(entry, "Data Record");
638
+ return { ref: record4.$ref, version: record4.$version };
639
+ }) });
640
+ }
578
641
  function question(value) {
579
642
  let source2 = object(value, "question");
580
- keys(source2, ["id", "to", "allowedResponders", "prompt", "instructions", "response", "handler"], "question");
643
+ keys(source2, ["id", "to", "allowedResponders", "prompt", "instructions", "response", "handler", "requirements"], "question");
581
644
  let to = personReference(source2.to, "question assignee"), allowedResponders = source2.allowedResponders === void 0 ? [to] : distinctPeople(source2.allowedResponders, "allowed responders");
582
645
  return allowedResponders.includes(to) || fail("Allowed responders must include the assignee"), {
583
646
  id: id(source2.id, "question ID"),
@@ -586,7 +649,8 @@ function question(value) {
586
649
  prompt: text(source2.prompt, "question prompt"),
587
650
  ...source2.instructions === void 0 ? {} : { instructions: text(source2.instructions, "instructions") },
588
651
  response: validateResponseDefinition(source2.response),
589
- ...Object.hasOwn(source2, "handler") ? { handler: handlerReference(source2.handler) } : {}
652
+ ...Object.hasOwn(source2, "handler") ? { handler: handlerReference(source2.handler) } : {},
653
+ ...Object.hasOwn(source2, "requirements") ? { requirements: recordRequirements(source2.requirements) } : {}
590
654
  };
591
655
  }
592
656
  function presentation(source2) {
@@ -1274,6 +1338,7 @@ var fieldProblems = ["unknown", "missing", "invalid", "source_schema"], reasons
1274
1338
  boolean: "a boolean",
1275
1339
  date: "a date in YYYY-MM-DD format",
1276
1340
  const: "the constant declared in the schema",
1341
+ datetime: "a UTC date and time in YYYY-MM-DDTHH:mm:ss.sssZ format, for example 2026-09-15T14:30:00.000Z",
1277
1342
  enum: "one of the choices declared in the schema",
1278
1343
  link: "a link to an existing record of an allowed type",
1279
1344
  object: "an object matching the schema",
@@ -1517,14 +1582,43 @@ function captureRecordsReadRefs(value) {
1517
1582
  }
1518
1583
  function captureRecordsReadOptions(value) {
1519
1584
  if (value === void 0) return {};
1520
- let row;
1521
1585
  try {
1522
- row = Object.fromEntries(Object.entries(historyProperties(value)).map(([key, descriptor]) => [key, descriptor.value]));
1586
+ historyProperties(value);
1523
1587
  } catch {
1524
1588
  throw new DataOperationError("invalid_query");
1525
1589
  }
1526
- if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)) || Reflect.ownKeys(value).some((key) => key !== "body" || !Object.hasOwn(Object.getOwnPropertyDescriptor(value, key), "value")) || Object.hasOwn(row, "body") && typeof row.body != "boolean") throw new DataOperationError("invalid_query");
1527
- return Object.hasOwn(row, "body") ? { body: row.body } : {};
1590
+ if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)) || Reflect.ownKeys(value).length)
1591
+ throw new DataOperationError("invalid_query");
1592
+ return {};
1593
+ }
1594
+
1595
+ function capture3(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
1596
+ if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return value;
1597
+ if (!value || typeof value != "object" || ancestors.has(value) || depth > 32) throw new DataOperationError("invalid_query");
1598
+ ancestors.add(value);
1599
+ try {
1600
+ return Array.isArray(value) ? historyArray(value).map((item) => capture3(item, ancestors, depth + 1)) : Object.fromEntries(Object.entries(historyProperties(value)).map(([key, descriptor]) => [key, capture3(descriptor.value, ancestors, depth + 1)]));
1601
+ } finally {
1602
+ ancestors.delete(value);
1603
+ }
1604
+ }
1605
+ function captureRecordsAll(query, options) {
1606
+ let invalid9 = () => {
1607
+ throw new DataOperationError("invalid_query");
1608
+ };
1609
+ try {
1610
+ let properties = historyProperties(options), maxRecords = properties.maxRecords?.value;
1611
+ if (Object.keys(properties).join(",") !== "maxRecords" || !Number.isSafeInteger(maxRecords) || maxRecords < 1) return invalid9();
1612
+ let detached = capture3(query), selections = historyProperties(detached);
1613
+ if (Object.keys(selections).length < 1 || Object.keys(selections).length > 16) return invalid9();
1614
+ for (let selection2 of Object.values(selections)) {
1615
+ let fields5 = historyProperties(selection2.value);
1616
+ if (fields5.$ && Object.hasOwn(historyProperties(fields5.$.value), "after")) return invalid9();
1617
+ }
1618
+ return { query: detached, maxRecords };
1619
+ } catch {
1620
+ return invalid9();
1621
+ }
1528
1622
  }
1529
1623
 
1530
1624
  function validRecordBody(value) {
@@ -1711,19 +1805,19 @@ var invalid6 = () => {
1711
1805
  }, unavailable = () => {
1712
1806
  throw new DataOperationError("unavailable");
1713
1807
  }, text2 = (value) => typeof value == "string" && value.length > 0;
1714
- function capture3(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
1808
+ function capture4(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
1715
1809
  if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return value;
1716
1810
  if (!value || typeof value != "object" || ancestors.has(value) || depth > 32) return invalid6();
1717
1811
  ancestors.add(value);
1718
1812
  try {
1719
- return Array.isArray(value) ? historyArray(value).map((item) => capture3(item, ancestors, depth + 1)) : Object.fromEntries(Object.entries(historyProperties(value)).map(([key, descriptor]) => [key, capture3(descriptor.value, ancestors, depth + 1)]));
1813
+ return Array.isArray(value) ? historyArray(value).map((item) => capture4(item, ancestors, depth + 1)) : Object.fromEntries(Object.entries(historyProperties(value)).map(([key, descriptor]) => [key, capture4(descriptor.value, ancestors, depth + 1)]));
1720
1814
  } finally {
1721
1815
  ancestors.delete(value);
1722
1816
  }
1723
1817
  }
1724
1818
  function recordPagination(queryRecords) {
1725
1819
  function pages(query) {
1726
- let captured = capture3(query), names = Object.keys(historyProperties(captured));
1820
+ let captured = capture4(query), names = Object.keys(historyProperties(captured));
1727
1821
  for (let name2 of names) {
1728
1822
  let selection2 = historyProperties(captured[name2]);
1729
1823
  if (Object.hasOwn(selection2, "$")) {
@@ -1735,7 +1829,6 @@ function recordPagination(queryRecords) {
1735
1829
  async function* iterate() {
1736
1830
  let state = new Map(names.map((name2) => [name2, {
1737
1831
  seen: /* @__PURE__ */ new Set(),
1738
- total: 0,
1739
1832
  count: void 0,
1740
1833
  next: void 0
1741
1834
  }])), active2 = names, version;
@@ -1745,11 +1838,11 @@ function recordPagination(queryRecords) {
1745
1838
  return [name2, next === void 0 ? selection2 : { ...selection2, $: { ...selection2.$, after: next } }];
1746
1839
  })), response2 = await queryRecords(request2), page;
1747
1840
  try {
1748
- page = capture3(response2);
1841
+ page = capture4(response2);
1749
1842
  let keys4 = Object.keys(historyProperties(page));
1750
1843
  (keys4.length !== active2.length + 1 || keys4.some((key) => key !== "$meta" && !active2.includes(key))) && unavailable();
1751
1844
  let meta = page.$meta;
1752
- (Object.keys(historyProperties(meta)).sort().join(",") !== "collections,version" || !text2(meta.version) || version !== void 0 && version !== meta.version) && unavailable(), version = meta.version, Object.keys(historyProperties(meta.collections)).some((key) => !active2.includes(key)) && unavailable();
1845
+ (Object.keys(historyProperties(meta)).sort().join(",") !== "collections,version" || !text2(meta.version)) && unavailable(), version = meta.version, Object.keys(historyProperties(meta.collections)).some((key) => !active2.includes(key)) && unavailable();
1753
1846
  for (let name2 of active2) {
1754
1847
  let records = historyArray(page[name2]), metadata = Object.hasOwn(meta.collections, name2) ? meta.collections[name2] : {};
1755
1848
  (Object.keys(historyProperties(metadata)).some((key) => key !== "count" && key !== "next") || Object.hasOwn(metadata, "next") && !text2(metadata.next)) && unavailable();
@@ -1759,7 +1852,7 @@ function recordPagination(queryRecords) {
1759
1852
  (!validRecordRef(row.$ref) || !text2(row.$version)) && unavailable();
1760
1853
  }
1761
1854
  let current2 = state.get(name2);
1762
- captured[name2].$?.count === !0 ? ((!Number.isSafeInteger(metadata.count) || metadata.count < 0 || current2.count !== void 0 && current2.count !== metadata.count) && unavailable(), current2.count = metadata.count) : Object.hasOwn(metadata, "count") && unavailable(), current2.total += records.length, (!Number.isSafeInteger(current2.total) || current2.count !== void 0 && (current2.total > current2.count || metadata.next === void 0 && current2.total !== current2.count)) && unavailable(), metadata.next !== void 0 && (current2.seen.has(metadata.next) && unavailable(), current2.seen.add(metadata.next)), current2.next = metadata.next;
1855
+ captured[name2].$?.count === !0 ? ((!Number.isSafeInteger(metadata.count) || metadata.count < 0) && unavailable(), current2.count = metadata.count) : Object.hasOwn(metadata, "count") && unavailable(), metadata.next !== void 0 && (current2.seen.has(metadata.next) && unavailable(), current2.seen.add(metadata.next)), current2.next = metadata.next;
1763
1856
  }
1764
1857
  } catch {
1765
1858
  return unavailable();
@@ -1775,32 +1868,7 @@ function recordPagination(queryRecords) {
1775
1868
  } while (active2.length);
1776
1869
  }
1777
1870
  }
1778
- async function all(query, options) {
1779
- let properties = historyProperties(options), maxRecords = properties.maxRecords?.value;
1780
- (Object.keys(properties).join(",") !== "maxRecords" || !Number.isSafeInteger(maxRecords) || maxRecords < 1) && invalid6();
1781
- let captured = capture3(query), names = Object.keys(historyProperties(captured));
1782
- if (names.length === 1) {
1783
- let name2 = names[0], selection2 = historyProperties(captured[name2]), selectionNames = Object.keys(selection2), authored = selection2.$ ? historyProperties(selection2.$.value) : {};
1784
- selectionNames.every((key) => key === "$") && !Object.hasOwn(authored, "limit") && (captured[name2] = { ...captured[name2], $: { ...captured[name2].$, limit: Math.min(500, maxRecords) } });
1785
- }
1786
- let result2, total = 0;
1787
- for await (let page of pages(captured)) {
1788
- let names2 = Object.keys(page.$meta.collections), size = names2.reduce((sum, name2) => sum + page[name2].length, 0);
1789
- if (size > maxRecords - total) throw new DataOperationError("capacity", !1, void 0, void 0, {
1790
- code: "record_limit_exceeded",
1791
- maxRecords,
1792
- collections: names2
1793
- });
1794
- total += size, result2 ??= { ...Object.fromEntries(names2.map((name2) => [name2, []])), $meta: page.$meta };
1795
- for (let name2 of names2) {
1796
- let target = result2[name2];
1797
- for (let record4 of page[name2]) target.push(record4);
1798
- }
1799
- result2.$meta = page.$meta;
1800
- }
1801
- return result2;
1802
- }
1803
- return { pages, all };
1871
+ return { pages };
1804
1872
  }
1805
1873
 
1806
1874
  var genericData = {
@@ -1837,6 +1905,7 @@ var genericData = {
1837
1905
  read: read2,
1838
1906
  query: queryRecords,
1839
1907
  ...recordPagination(queryRecords),
1908
+ all: async (query, options) => send3({ operation: "records.all", ...captureRecordsAll(query, options) }),
1840
1909
  search: async (query, options) => send3({ operation: "records.search", ...captureRecordsSearchInput(query, options) })
1841
1910
  },
1842
1911
  history: {
@@ -2374,48 +2443,6 @@ var files = {
2374
2443
  read
2375
2444
  };
2376
2445
 
2377
- function validDropboxRootPath(value) {
2378
- return typeof value == "string" && value.length <= 2048 && value.startsWith("/") && !/[\\\x00-\x1f\x7f]/.test(value) && value.slice(1).split("/").every((segment) => segment.length > 0 && segment.trim() === segment && segment !== "." && segment !== "..");
2379
- }
2380
- function validMicrosoftId(value) {
2381
- return typeof value == "string" && /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(value);
2382
- }
2383
- function validMicrosoftMailbox(value) {
2384
- return typeof value == "string" && value.length <= 254 && /^[^\s@/?#\\\x00-\x1f\x7f]+@[^\s@/?#\\\x00-\x1f\x7f]+\.[^\s@/?#\\\x00-\x1f\x7f]+$/.test(value);
2385
- }
2386
- function sharePointHost(value) {
2387
- return /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.sharepoint\.com$/.test(value);
2388
- }
2389
- function canonicalSharePointSiteUrl(value) {
2390
- if (!(typeof value != "string" || value.length > 2048 || /[\s\\?#\x00-\x1f\x7f]/.test(value) || !/^https:\/\/[^/:@]+(?:\/|$)/i.test(value)))
2391
- try {
2392
- let url = new URL(value);
2393
- if (url.protocol !== "https:" || !sharePointHost(url.hostname) || url.username || url.password || url.port) return;
2394
- let rawPath = value.replace(/^https:\/\/[^/]+/i, "") || "/", path = rawPath.endsWith("/") ? rawPath.slice(0, -1) : rawPath, segments = path.slice(1).split("/");
2395
- if (path && segments.some((segment) => !segment)) return;
2396
- let encoded = path ? segments.map((segment) => {
2397
- let decoded = decodeURIComponent(segment);
2398
- if (decoded === "." || decoded === ".." || /[/%\\?#\x00-\x1f\x7f]/.test(decoded)) throw new Error();
2399
- return encodeURIComponent(decoded);
2400
- }).join("/") : "", canonical = `https://${url.hostname}/${encoded}`;
2401
- return canonical.length <= 2048 ? canonical : void 0;
2402
- } catch {
2403
- return;
2404
- }
2405
- }
2406
- function validSharePointSiteId(value, siteUrl) {
2407
- if (typeof value != "string" || value.length > 512) return !1;
2408
- let [host, collection, site, extra] = value.split(",");
2409
- return extra === void 0 && host === new URL(siteUrl).hostname && validMicrosoftId(collection) && validMicrosoftId(site);
2410
- }
2411
- function validGoogleScopes(value) {
2412
- return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every((scope) => typeof scope == "string" && scope.length <= 256 && /^(https:\/\/www\.googleapis\.com\/auth\/[A-Za-z0-9._-]+|https:\/\/mail\.google\.com\/|openid|email|profile)$/.test(scope)) && new Set(value).size === value.length;
2413
- }
2414
- var DROPBOX_FILE_SCOPES = ["account_info.read", "files.metadata.read", "files.content.read", "files.content.write"];
2415
- function validDropboxFileScopes(value) {
2416
- return Array.isArray(value) && value.length === DROPBOX_FILE_SCOPES.length && new Set(value).size === value.length && DROPBOX_FILE_SCOPES.every((scope) => value.includes(scope));
2417
- }
2418
-
2419
2446
  var ROUTINE_CONNECTION_CREDENTIALS_ENV = "OS_ROUTINE_CONNECTION_CREDENTIALS";
2420
2447
  function parseRoutineConnectionNames(value) {
2421
2448
  if (!Array.isArray(value) || value.some((name2) => typeof name2 != "string" || !/^(gmail|airtable|dropbox|outlook|sharepoint)\/[a-z0-9][a-z0-9-]{0,62}$/.test(name2)) || new Set(value).size !== value.length)
@@ -2903,14 +2930,41 @@ var source = {
2903
2930
  };
2904
2931
 
2905
2932
  var InboxOperationError = class extends Error {
2906
- constructor(status, reason) {
2907
- super(reason === "conflict" ? "This question already has an accepted answer" : reason === "unavailable" ? "Inbox request unavailable. Retry the same action." : reason === "invalid_input" ? "Invalid Inbox request" : "Inbox access unavailable");
2933
+ constructor(status, reason, requirementsRepository) {
2934
+ super(reason === "records_need_attention" ? "Records need to be pushed or reviewed." : reason === "records_unavailable" ? "Records temporarily unavailable. Try again shortly." : reason === "handler_unavailable" ? "Deploy the routine that owns this question\u2019s response handler." : reason === "conflict" ? "This question already has an accepted answer" : reason === "unavailable" ? "Inbox request unavailable. Retry the same action." : reason === "invalid_input" ? "Invalid Inbox request" : "Inbox access unavailable");
2908
2935
  this.status = status;
2909
2936
  this.reason = reason;
2937
+ this.requirementsRepository = requirementsRepository;
2910
2938
  }
2911
2939
  status;
2912
2940
  reason;
2913
- }, INBOX_RESULT_BYTES = 8 * 1024 * 1024, INBOX_INPUT_BYTES = 8192, INBOX_LOCAL_INPUT_BYTES = 256 * 1024, INBOX_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
2941
+ requirementsRepository;
2942
+ };
2943
+ function parseQuestionAvailability(value, available = !1) {
2944
+ let state = object4(value);
2945
+ return keys3(state, ["unavailableReason", "requirementsRepository"], []), "unavailableReason" in state ? (assert(!available && typeof state.unavailableReason == "string" && ["handler_unavailable", "records_need_attention", "records_unavailable"].includes(String(state.unavailableReason))), state.unavailableReason === "records_need_attention" ? assert(validDataRepositoryName(state.requirementsRepository)) : assert(!("requirementsRepository" in state)), {
2946
+ unavailableReason: state.unavailableReason,
2947
+ ...state.unavailableReason === "records_need_attention" ? { requirementsRepository: state.requirementsRepository } : {}
2948
+ }) : (assert(!("requirementsRepository" in state)), {});
2949
+ }
2950
+ function questionAvailability(value, available = !1) {
2951
+ return parseQuestionAvailability({
2952
+ ..."unavailableReason" in value ? { unavailableReason: value.unavailableReason } : {},
2953
+ ..."requirementsRepository" in value ? { requirementsRepository: value.requirementsRepository } : {}
2954
+ }, available);
2955
+ }
2956
+ function parseInboxUnavailableFailure(value, status) {
2957
+ try {
2958
+ if (status !== 503) return;
2959
+ let envelope = object4(value);
2960
+ keys3(envelope, ["error", "unavailableReason", "requirementsRepository"], ["error", "unavailableReason"]), assert(text4(envelope.error));
2961
+ let state = questionAvailability(envelope);
2962
+ return new InboxOperationError(503, state.unavailableReason, state.requirementsRepository);
2963
+ } catch {
2964
+ return;
2965
+ }
2966
+ }
2967
+ var INBOX_RESULT_BYTES = 8 * 1024 * 1024, INBOX_INPUT_BYTES = 8192, INBOX_LOCAL_INPUT_BYTES = 256 * 1024, INBOX_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
2914
2968
  function isAppQuestionOperation(operation2) {
2915
2969
  return operation2 === "questions.list" || operation2 === "questions.answer" || operation2 === "questions.searchRecords";
2916
2970
  }
@@ -3090,7 +3144,7 @@ function parseInboxItem(value) {
3090
3144
  assert(id2(person.id) && text4(person.name));
3091
3145
  }), array2(item.questions).forEach((value2) => {
3092
3146
  let question2 = object4(value2);
3093
- if (assert(text4(question2.id) && id2(question2.to) && text4(question2.prompt) && (question2.instructions === null || text4(question2.instructions, !0)) && typeof question2.available == "boolean"), responseDefinition(question2.response), assert(array2(question2.allowedResponders).every(id2)), question2.acceptedResponse !== null) {
3147
+ if (assert(text4(question2.id) && id2(question2.to) && text4(question2.prompt) && (question2.instructions === null || text4(question2.instructions, !0)) && typeof question2.available == "boolean"), questionAvailability(question2, question2.available), assert(!("requirements" in question2) && !("handler" in question2)), responseDefinition(question2.response), assert(array2(question2.allowedResponders).every(id2)), question2.acceptedResponse !== null) {
3094
3148
  let accepted = object4(question2.acceptedResponse);
3095
3149
  assert(id2(accepted.id) && id2(accepted.userId) && date(accepted.acceptedAt)), response(accepted.response), accepted.label === null ? delete accepted.label : "label" in accepted && assert(text4(accepted.label)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder));
3096
3150
  }
@@ -3123,11 +3177,11 @@ function parseAnswerableQuestion(value) {
3123
3177
  let entry = object4(json(value));
3124
3178
  keys3(
3125
3179
  entry,
3126
- ["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
3180
+ ["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions", "unavailableReason", "requirementsRepository"],
3127
3181
  ["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
3128
3182
  ), assert(id2(entry.itemId) && integer(entry.number) && integer(entry.revision) && text4(entry.title) && text4(entry.inboxUrl));
3129
3183
  let link = new URL(entry.inboxUrl), slug = link.hostname.slice(0, -13);
3130
- 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) && text4(entry.questionId) && entry.questionId === entry.questionId.trim() && text4(entry.prompt) && (!("instructions" in entry) || text4(entry.instructions, !0)) && typeof entry.answerable == "boolean"), responseDefinition(entry.response), askMetadata(entry), entry;
3184
+ 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) && text4(entry.questionId) && entry.questionId === entry.questionId.trim() && text4(entry.prompt) && (!("instructions" in entry) || text4(entry.instructions, !0)) && typeof entry.answerable == "boolean"), questionAvailability(entry, entry.answerable), responseDefinition(entry.response), askMetadata(entry), entry;
3131
3185
  }
3132
3186
  function askMetadata(entry) {
3133
3187
  let tags = array2(entry.tags === void 0 ? [] : entry.tags);
@@ -3332,7 +3386,7 @@ function isAppOrigin(value) {
3332
3386
  return !1;
3333
3387
  }
3334
3388
  }
3335
- function appContext(origin, active2) {
3389
+ function appContext(origin, active2, changed) {
3336
3390
  let binding, credential, pair, serialized, denied = !1, controller = new AbortController(), access = new AbortController(), expiry, startup, renewalTimer, renewal, observation, resolution2, disposed = !1, stored = () => globalThis.localStorage.getItem(sessionKey), alive = () => {
3337
3391
  try {
3338
3392
  return !denied && !disposed && active2() && globalThis.location.origin === origin;
@@ -3342,12 +3396,20 @@ function appContext(origin, active2) {
3342
3396
  }, cancel = () => {
3343
3397
  controller.abort(), access.abort(), clearTimeout(expiry), clearTimeout(startup), clearTimeout(renewalTimer), clearInterval(monitor), globalThis.removeEventListener?.("storage", storageChanged);
3344
3398
  for (let event of ["pageshow", "focus", "visibilitychange"]) globalThis.removeEventListener?.(event, wake);
3345
- }, invalidate = () => {
3346
- denied = !0, cancel();
3399
+ }, notify = (state) => {
3347
3400
  try {
3348
- !disposed && active2() && globalThis.location.origin === origin && (!serialized || globalThis.localStorage.getItem(sessionKey) === serialized) && globalThis.localStorage.removeItem(sessionKey);
3401
+ changed?.(state);
3349
3402
  } catch {
3350
3403
  }
3404
+ }, invalidate = (state = "unavailable") => {
3405
+ if (!denied) {
3406
+ denied = !0, cancel();
3407
+ try {
3408
+ !disposed && active2() && globalThis.location.origin === origin && (!serialized || globalThis.localStorage.getItem(sessionKey) === serialized) && globalThis.localStorage.removeItem(sessionKey);
3409
+ } catch {
3410
+ }
3411
+ notify(state);
3412
+ }
3351
3413
  }, current2 = () => {
3352
3414
  try {
3353
3415
  return alive() && !!binding && binding.expiresAt > Date.now() && stored() === serialized;
@@ -3359,10 +3421,10 @@ function appContext(origin, active2) {
3359
3421
  if (!validPair(value) || value.context.expiresAt > Date.now() + 6e5 || !sameSession(value.context)) throw new Error();
3360
3422
  return value;
3361
3423
  }, expireAccess = () => {
3362
- binding && binding.expiresAt <= Date.now() && access.abort();
3424
+ binding && binding.expiresAt <= Date.now() && !access.signal.aborted && (access.abort(), notify("expired"));
3363
3425
  };
3364
3426
  async function send3(path, candidate, signal, init2 = {}) {
3365
- let url = `${origin}/_os/app/${path}`, response2;
3427
+ let url = path === "auth" ? `${origin}/api/auth` : `${origin}/_os/app/${path}`, response2;
3366
3428
  try {
3367
3429
  response2 = await fetch(url, {
3368
3430
  ...init2,
@@ -3400,7 +3462,7 @@ function appContext(origin, active2) {
3400
3462
  expiry = setTimeout(expireAccess, remaining), renewalTimer = setTimeout(() => {
3401
3463
  renew().catch(() => {
3402
3464
  });
3403
- }, remaining - Math.min(6e4, remaining / 5));
3465
+ }, remaining - Math.min(6e4, remaining / 5)), notify("connected");
3404
3466
  }
3405
3467
  async function synchronize(signal = controller.signal) {
3406
3468
  if (!alive()) throw new Error();
@@ -3436,7 +3498,7 @@ function appContext(origin, active2) {
3436
3498
  observation === observed && (observation = void 0);
3437
3499
  }
3438
3500
  }
3439
- async function renew() {
3501
+ async function renew(initialConnection = !1) {
3440
3502
  if (renewal) return renewal;
3441
3503
  if (!binding || !pair || !alive()) throw new Error();
3442
3504
  renewal = (async () => {
@@ -3462,7 +3524,7 @@ function appContext(origin, active2) {
3462
3524
  await synchronize(requestController.signal);
3463
3525
  return;
3464
3526
  }
3465
- if (!response2.ok) throw new Error();
3527
+ if (!response2.ok) throw response2.status === 401 || response2.status === 403 ? new AppContextDenied() : new Error();
3466
3528
  if (!alive() || !validPair(value) || !bounded3(value.context) || (/* @__PURE__ */ new Set([value.credential, value.renewalCredential, pair.credential, pair.renewalCredential])).size !== 4) throw new Error();
3467
3529
  if (stored() !== previous) {
3468
3530
  await synchronize(requestController.signal);
@@ -3471,6 +3533,7 @@ function appContext(origin, active2) {
3471
3533
  let raw = JSON.stringify(value);
3472
3534
  globalThis.localStorage.setItem(sessionKey, raw), install(value.context, value, raw);
3473
3535
  } catch (error) {
3536
+ if (initialConnection && error instanceof AppContextDenied) throw error;
3474
3537
  try {
3475
3538
  if (alive() && stored() && stored() !== previous) {
3476
3539
  await synchronize(requestController.signal);
@@ -3520,28 +3583,28 @@ function appContext(origin, active2) {
3520
3583
  for (await synchronize(); alive() && stored() !== serialized; ) await synchronize();
3521
3584
  if (signal.aborted || !current2()) throw new Error();
3522
3585
  }
3523
- async function requestData(operation2, input) {
3586
+ async function requestData(operation2, input, parent) {
3524
3587
  try {
3525
3588
  if (operation2 !== "data/query" || !current2()) throw new Error();
3526
- let admitted = credential, signal = access.signal, response2 = await send3("data", credential, signal, { method: "POST", body: JSON.stringify(input) });
3589
+ let admitted = credential, signal = parent ? AbortSignal.any([access.signal, parent]) : access.signal, response2 = await send3("data", credential, signal, { method: "POST", body: JSON.stringify(input) });
3527
3590
  if (await settledAccess(signal), response2.status === 401 || response2.status === 403)
3528
3591
  throw admitted === credential && current2() && invalidate(), new DataOperationError("access_denied");
3529
3592
  let result2 = await appResponse(response2, Number.MAX_SAFE_INTEGER, signal);
3530
3593
  if (await settledAccess(signal), !response2.ok) throw dataTransportError(response2.status, result2);
3531
3594
  return result2;
3532
3595
  } catch (error) {
3533
- throw error instanceof DataOperationError ? error : !current2() || controller.signal.aborted ? new DataOperationError("context_unavailable") : new DataOperationError("unavailable", !0);
3596
+ throw error instanceof DataOperationError ? error : !current2() || controller.signal.aborted || parent?.aborted ? new DataOperationError("context_unavailable") : new DataOperationError("unavailable", !0);
3534
3597
  }
3535
3598
  }
3536
- async function requestInbox(operation2, input) {
3599
+ async function requestInbox(operation2, input, signal) {
3537
3600
  if (!["questions.list", "questions.answer", "questions.searchRecords"].includes(operation2)) throw new Error("Inbox operation unavailable");
3538
- return requestChecked("inbox", { method: "POST", body: JSON.stringify({ operation: operation2, input }) }, !0);
3601
+ return requestChecked("inbox", { method: "POST", body: JSON.stringify({ operation: operation2, input }), signal }, !0);
3539
3602
  }
3540
3603
  async function requestRoutine(key, suffix, init2 = {}) {
3541
3604
  return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, init2);
3542
3605
  }
3543
- async function requestRetainedRoutine(key, suffix) {
3544
- return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, {}, !1, !0);
3606
+ async function requestRetainedRoutine(key, suffix, signal) {
3607
+ return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, { signal }, !1, !0);
3545
3608
  }
3546
3609
  async function requestFiles(suffix, init2, parent) {
3547
3610
  let unavailable5 = () => new FileOperationError("unsupported_context", 400);
@@ -3564,7 +3627,7 @@ function appContext(origin, active2) {
3564
3627
  }
3565
3628
  async function requestChecked(path, init2, inbox2 = !1, retained2 = !1) {
3566
3629
  if (!current2()) throw new Error("Local app context unavailable.");
3567
- let admitted = credential, signal = access.signal, response2 = await send3(path, credential, signal, init2), check = async () => {
3630
+ let admitted = credential, signal = init2.signal ? AbortSignal.any([access.signal, init2.signal]) : access.signal, response2 = await send3(path, credential, signal, init2), check = async () => {
3568
3631
  if (retained2) {
3569
3632
  if (signal.aborted || !current2()) throw new Error("Local app context unavailable.");
3570
3633
  } else await settledAccess(signal);
@@ -3599,8 +3662,32 @@ function appContext(origin, active2) {
3599
3662
  try {
3600
3663
  if (!alive()) throw new Error();
3601
3664
  if (!pair) {
3602
- let candidate2 = stored(), retained3 = readPair(candidate2);
3603
- pair = retained3, binding = { ...retained3.context }, credential = retained3.credential, serialized = candidate2;
3665
+ let candidate2 = stored();
3666
+ if (candidate2)
3667
+ try {
3668
+ let retained3 = readPair(candidate2);
3669
+ if (retained3.context.expiresAt <= Date.now()) {
3670
+ if (pair = retained3, binding = { ...retained3.context }, credential = retained3.credential, serialized = candidate2, await renew(!0), !current2()) throw new AppRenewalUnavailable();
3671
+ return context();
3672
+ }
3673
+ let value3 = await proof(retained3.credential);
3674
+ return stored() !== candidate2 ? resolveOnce() : (install(value3, retained3, candidate2), context());
3675
+ } catch (error) {
3676
+ if (error instanceof AppRenewalUnavailable || error instanceof AppResponseReadError || !(error instanceof AppContextDenied) || !alive() || expiry) throw error;
3677
+ pair = void 0, binding = void 0, credential = void 0, serialized = void 0;
3678
+ }
3679
+ let response2 = await untilAborted(fetch(`${origin}/_os/app/connect`, {
3680
+ method: "POST",
3681
+ credentials: "omit",
3682
+ redirect: "error",
3683
+ cache: "no-store",
3684
+ referrerPolicy: "no-referrer",
3685
+ signal: controller.signal
3686
+ }), controller.signal), value2 = await appResponse(response2, 4096, controller.signal);
3687
+ if (!response2.ok || response2.redirected || response2.url && response2.url !== `${origin}/_os/app/connect` || !alive() || !validPair(value2) || !bounded3(value2.context)) throw new Error();
3688
+ if (stored() !== candidate2 && stored()) return resolveOnce();
3689
+ let raw = JSON.stringify(value2);
3690
+ return globalThis.localStorage.setItem(sessionKey, raw), install(value2.context, value2, raw), context();
3604
3691
  }
3605
3692
  if (expireAccess(), binding.expiresAt <= Date.now()) {
3606
3693
  if (await renew(), !current2()) throw new AppRenewalUnavailable();
@@ -3629,17 +3716,41 @@ function appContext(origin, active2) {
3629
3716
  }, resolve = () => resolution2 || (resolution2 = resolveOnce().finally(() => {
3630
3717
  resolution2 = void 0;
3631
3718
  }), resolution2);
3632
- return { resolve, retained: async () => {
3633
- if (!expiry && alive() && (binding ? current2() && resolution2 : readPair(stored()).context.expiresAt > Date.now()))
3634
- return resolve();
3635
- if (!expiry || !current2()) throw new Error("Local app context unavailable.");
3636
- return context();
3637
- }, start: () => {
3638
- startup = setTimeout(() => {
3639
- alive() && !resolution2 && !binding && resolve().catch(() => {
3640
- });
3641
- }, 0);
3642
- }, invalidate, dispose };
3719
+ return {
3720
+ resolve,
3721
+ retained: async () => {
3722
+ if (!expiry && alive() && (binding ? current2() && resolution2 : !stored() || readPair(stored()).context.expiresAt > Date.now()))
3723
+ return resolve();
3724
+ if (!expiry || !current2()) throw new Error("Local app context unavailable.");
3725
+ return context();
3726
+ },
3727
+ start: () => {
3728
+ startup = setTimeout(() => {
3729
+ alive() && !resolution2 && !binding && resolve().catch(() => {
3730
+ });
3731
+ }, 0);
3732
+ },
3733
+ invalidate,
3734
+ dispose,
3735
+ account: async () => {
3736
+ await resolve();
3737
+ let signal = access.signal, response2 = await requestChecked("auth", { method: "GET" }), value = await appResponse(response2, 4096, signal);
3738
+ if (!response2.ok || !current2() || !value || Object.keys(value).join(",") !== "account" || !value.account || Object.keys(value.account).sort().join(",") !== "displayName,email" || typeof value.account.email != "string" || value.account.email.length > 320 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.account.email) || typeof value.account.displayName != "string" || !value.account.displayName.trim() || value.account.displayName.length > 320)
3739
+ throw new Error("Local app account unavailable.");
3740
+ return Object.freeze({ email: value.account.email, displayName: value.account.displayName });
3741
+ },
3742
+ signOut: async () => {
3743
+ if (current2() || await resolve(), !current2()) throw new Error("Local app context unavailable.");
3744
+ let signal = AbortSignal.timeout(2e4), pending = send3("sign-out", credential, signal, { method: "POST" });
3745
+ invalidate("signed_out");
3746
+ let response2 = await pending, value = await appResponse(response2, 4096, signal);
3747
+ if (!response2.ok || !value || Object.keys(value).join(",") !== "signedOut" || value.signedOut !== !0)
3748
+ throw new Error("Local app sign-out unavailable.");
3749
+ },
3750
+ isCurrent() {
3751
+ return expireAccess(), current2();
3752
+ }
3753
+ };
3643
3754
  }
3644
3755
  function validProof(value) {
3645
3756
  return typeof value == "string" && /^[A-Za-z0-9_-]{43}$/.test(value);
@@ -3681,7 +3792,7 @@ async function send2(operation2, input, resolved) {
3681
3792
  };
3682
3793
  try {
3683
3794
  let response2 = await context.requestInbox(operation2, envelope.input), value = await appResponse(response2, INBOX_RESULT_BYTES, context.signal);
3684
- if (check2(), !response2.ok) throw new InboxOperationError(
3795
+ if (check2(), !response2.ok) throw parseInboxUnavailableFailure(value, response2.status) ?? new InboxOperationError(
3685
3796
  [400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
3686
3797
  response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
3687
3798
  );
@@ -3723,12 +3834,20 @@ async function send2(operation2, input, resolved) {
3723
3834
  throw response2.body?.cancel().catch(() => {
3724
3835
  }), error;
3725
3836
  }
3726
- if (!response2.ok)
3727
- throw response2.body?.cancel().catch(() => {
3728
- }), new InboxOperationError(
3837
+ if (!response2.ok) {
3838
+ let value2;
3839
+ try {
3840
+ let bytes2 = await limitedBody(response2, 8192);
3841
+ check(), bytes2 && (value2 = JSON.parse(new TextDecoder().decode(bytes2)));
3842
+ } catch {
3843
+ check();
3844
+ }
3845
+ let refusal = parseInboxUnavailableFailure(value2, response2.status);
3846
+ throw refusal || new InboxOperationError(
3729
3847
  [400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
3730
3848
  response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
3731
3849
  );
3850
+ }
3732
3851
  if (response2.status !== 200)
3733
3852
  throw response2.body?.cancel().catch(() => {
3734
3853
  }), unavailable3();
@@ -3839,8 +3958,37 @@ function init({ auth: input }) {
3839
3958
  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);
3840
3959
  } catch {
3841
3960
  }
3842
- let active2 = !0, revision = 0, person, token, binding = {}, local2 = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, resolve = async () => {
3843
- if (local2) return local2.resolve();
3961
+ let active2 = !0, revision = 0, person, token, binding = {}, installation = new AbortController(), sharedLocal = localOrigin && registered?.localContext?.origin === localOrigin ? registered.localContext.connection : void 0, local2 = sharedLocal ?? (localOrigin ? appContext(localOrigin, () => active2) : void 0), subscription, stopDisposal, owned = (context) => {
3962
+ let signal = AbortSignal.any([context.signal, installation.signal]);
3963
+ return {
3964
+ ...context,
3965
+ get expiresAt() {
3966
+ return context.expiresAt;
3967
+ },
3968
+ signal,
3969
+ isCurrent: () => active2 && !signal.aborted && context.isCurrent(),
3970
+ requestData: (operation2, input2) => context.requestData(operation2, input2, signal),
3971
+ requestInbox: (operation2, input2) => context.requestInbox(operation2, input2, signal),
3972
+ requestFiles: (suffix, init2, parent) => context.requestFiles(
3973
+ suffix,
3974
+ init2,
3975
+ parent ? AbortSignal.any([signal, parent]) : signal
3976
+ ),
3977
+ requestRoutine: (key, suffix, init2 = {}) => context.requestRoutine(
3978
+ key,
3979
+ suffix,
3980
+ { ...init2, signal: init2.signal ? AbortSignal.any([signal, init2.signal]) : signal }
3981
+ ),
3982
+ requestRetainedRoutine: (key, suffix) => context.requestRetainedRoutine(key, suffix, signal),
3983
+ requestAvailability: (key) => context.requestRoutine(key, "availability", { method: "GET", signal })
3984
+ };
3985
+ }, resolve = async () => {
3986
+ if (local2) {
3987
+ if (!active2) throw new Error("Local app context unavailable.");
3988
+ let context = await local2.resolve();
3989
+ if (!active2) throw new Error("Local app context unavailable.");
3990
+ return owned(context);
3991
+ }
3844
3992
  if (registered && await registered.ready(), !active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
3845
3993
  let started = revision, { data: { session }, error } = await auth2.getSession();
3846
3994
  if (!active2 || globalThis.location.origin !== endpoint || started !== revision || error || !session || person !== void 0 && person !== session.user.id)
@@ -3860,13 +4008,18 @@ function init({ auth: input }) {
3860
4008
  memberId: session.user.id,
3861
4009
  binding
3862
4010
  };
3863
- }, uninstall = installMemberContext(resolve, local2 ? local2.retained : resolve), dispose = () => {
3864
- active2 && (active2 = !1, local2?.dispose(), revision++, subscription?.unsubscribe(), stopDisposal?.(), uninstall(), installedDispose === dispose && (installedDispose = void 0));
4011
+ }, uninstall = installMemberContext(resolve, local2 ? async () => {
4012
+ if (!active2 || !local2) throw new Error("Local app context unavailable.");
4013
+ let context = await local2.retained();
4014
+ if (!active2) throw new Error("Local app context unavailable.");
4015
+ return owned(context);
4016
+ } : resolve), dispose = () => {
4017
+ active2 && (active2 = !1, installation.abort(), sharedLocal || local2?.dispose(), revision++, subscription?.unsubscribe(), stopDisposal?.(), uninstall(), installedDispose === dispose && (installedDispose = void 0));
3865
4018
  };
3866
- installedDispose = dispose, stopDisposal = registered?.onDispose(dispose), active2 && (subscription = auth2.onAuthStateChange((event, session) => {
4019
+ installedDispose = dispose, stopDisposal = registered?.onDispose(dispose), active2 && (sharedLocal || (subscription = auth2.onAuthStateChange((event, session) => {
3867
4020
  let next = session?.user.id ?? null;
3868
4021
  (event === "SIGNED_OUT" || person !== void 0 && next !== person || person !== void 0 && event === "SIGNED_IN" && token !== session?.access_token) && (revision++, local2?.invalidate()), person = next, token = session?.access_token;
3869
- }).data.subscription, local2?.start());
4022
+ }).data.subscription), sharedLocal || local2?.start());
3870
4023
  }
3871
4024
  var os = { init };
3872
4025
 
@@ -3906,9 +4059,127 @@ function authorizationFailure(error) {
3906
4059
  return Object.freeze({ status: status === 404 || status === 410 || status === 400 ? "expired" : status === 401 ? "signed_out" : status === 403 || status === 422 ? "invalid" : "unavailable" });
3907
4060
  }
3908
4061
 
4062
+ var coordinators = /* @__PURE__ */ new Map(), publish = (c, state) => {
4063
+ c.state = Object.freeze(state);
4064
+ for (let listener of c.listeners)
4065
+ try {
4066
+ listener(c.state);
4067
+ } catch {
4068
+ }
4069
+ };
4070
+ function refresh(c) {
4071
+ let revision = c.revision;
4072
+ if (c.loading?.revision === revision) return c.loading.promise;
4073
+ let promise = (async () => {
4074
+ try {
4075
+ let account = await c.context.account();
4076
+ c.active && !c.closed && c.revision === revision && publish(c, { status: "signed_in", account });
4077
+ } catch {
4078
+ c.active && !c.closed && c.revision === revision && publish(c, { status: "unavailable", error: "unavailable" });
4079
+ }
4080
+ })().finally(() => {
4081
+ c.loading?.promise === promise && (c.loading = void 0);
4082
+ });
4083
+ return c.loading = { revision, promise }, promise;
4084
+ }
4085
+ function createLocalBrowserAuth(origin, failure) {
4086
+ let c = coordinators.get(origin);
4087
+ if (!c) {
4088
+ let coordinator2 = {
4089
+ context: void 0,
4090
+ state: Object.freeze({ status: "initializing" }),
4091
+ active: !0,
4092
+ closed: !1,
4093
+ refs: 0,
4094
+ revision: 0,
4095
+ listeners: /* @__PURE__ */ new Set(),
4096
+ ready: Promise.resolve()
4097
+ };
4098
+ coordinator2.context = appContext(origin, () => coordinator2.active, (state) => {
4099
+ !coordinator2.active || coordinator2.closed || (state === "connected" ? coordinator2.state.status !== "initializing" && (coordinator2.revision++, refresh(coordinator2)) : (coordinator2.revision++, publish(coordinator2, { status: state === "expired" ? "expired" : state === "signed_out" ? "signed_out" : "unavailable" })));
4100
+ }), c = coordinator2, coordinators.set(origin, c), c.ready = Promise.resolve().then(() => refresh(coordinator2));
4101
+ }
4102
+ let coordinator = c;
4103
+ coordinator.refs++;
4104
+ let active2 = !0, lastState = coordinator.state, listeners = /* @__PURE__ */ new Set(), disposals = /* @__PURE__ */ new Set(), observe = (state) => {
4105
+ lastState = state;
4106
+ for (let listener of listeners)
4107
+ try {
4108
+ listener(state);
4109
+ } catch {
4110
+ }
4111
+ };
4112
+ coordinator.listeners.add(observe);
4113
+ let assertActive = () => {
4114
+ if (!active2) throw failure("disposed");
4115
+ }, unavailable5 = async () => Object.freeze({
4116
+ status: active2 ? coordinator.state.status === "signed_out" ? "signed_out" : "unavailable" : "disposed"
4117
+ }), handle2 = Object.freeze({
4118
+ authorization: Object.freeze({ get: unavailable5, approve: unavailable5, deny: unavailable5 }),
4119
+ getState() {
4120
+ return active2 && !coordinator.state.pending && coordinator.state.status === "signed_in" && !coordinator.context.isCurrent() && coordinator.state.status === "signed_in" && publish(coordinator, { status: "unavailable", error: "unavailable" }), lastState;
4121
+ },
4122
+ subscribe(listener) {
4123
+ return assertActive(), listeners.add(listener), () => {
4124
+ listeners.delete(listener);
4125
+ };
4126
+ },
4127
+ async sendCode() {
4128
+ throw assertActive(), failure("unavailable");
4129
+ },
4130
+ async verifyCode() {
4131
+ throw assertActive(), failure("unavailable");
4132
+ },
4133
+ async signOut() {
4134
+ if (assertActive(), coordinator.state.pending === "sign_out") throw failure("busy");
4135
+ if (coordinator.closed) throw failure("unavailable");
4136
+ coordinator.closed = !0, coordinator.revision++, publish(coordinator, { status: coordinator.state.status, pending: "sign_out" });
4137
+ try {
4138
+ await coordinator.context.signOut();
4139
+ } catch {
4140
+ throw coordinator.context.invalidate(), coordinator.active && publish(coordinator, { status: "unavailable", error: "unavailable" }), failure(active2 ? "unavailable" : "disposed");
4141
+ }
4142
+ coordinator.active && publish(coordinator, { status: "signed_out" }), assertActive();
4143
+ },
4144
+ dispose() {
4145
+ if (active2) {
4146
+ active2 = !1, coordinator.listeners.delete(observe), listeners.clear();
4147
+ for (let callback of disposals)
4148
+ try {
4149
+ callback();
4150
+ } catch {
4151
+ }
4152
+ disposals.clear(), --coordinator.refs === 0 && (coordinator.active = !1, coordinator.revision++, coordinator.context.dispose(), coordinator.listeners.clear(), coordinators.delete(origin));
4153
+ }
4154
+ }
4155
+ });
4156
+ return registerBrowserAuth(handle2, {
4157
+ localContext: { origin, connection: coordinator.context },
4158
+ async ready() {
4159
+ assertActive(), await coordinator.ready, assertActive();
4160
+ },
4161
+ async checkWorkspaceAccess() {
4162
+ assertActive(), await coordinator.context.resolve(), assertActive();
4163
+ },
4164
+ onDispose(callback) {
4165
+ return active2 ? (disposals.add(callback), () => {
4166
+ disposals.delete(callback);
4167
+ }) : (callback(), () => {
4168
+ });
4169
+ },
4170
+ async getSession() {
4171
+ return assertActive(), { data: { session: null }, error: null };
4172
+ },
4173
+ onAuthStateChange(callback) {
4174
+ return callback("INITIAL_SESSION", null), { data: { subscription: { unsubscribe() {
4175
+ } } } };
4176
+ }
4177
+ }), handle2;
4178
+ }
4179
+
3909
4180
  function createBrowserAuth(runtime) {
3910
- let coordinators = /* @__PURE__ */ new Map();
3911
- function publish(c, state) {
4181
+ let coordinators2 = /* @__PURE__ */ new Map();
4182
+ function publish2(c, state) {
3912
4183
  c.state = Object.freeze(state);
3913
4184
  for (let listener of c.listeners)
3914
4185
  try {
@@ -3924,7 +4195,7 @@ function createBrowserAuth(runtime) {
3924
4195
  }
3925
4196
  }
3926
4197
  function expire(c) {
3927
- !c.active || !c.session && c.state.status === "expired" || (c.revision++, c.timer && clearTimeout(c.timer), c.session = null, publish(c, { status: "expired" }), notify(c, "SIGNED_OUT"));
4198
+ !c.active || !c.session && c.state.status === "expired" || (c.revision++, c.timer && clearTimeout(c.timer), c.session = null, publish2(c, { status: "expired" }), notify(c, "SIGNED_OUT"));
3928
4199
  }
3929
4200
  function accept(c, event, session) {
3930
4201
  if (!c.active || event === "INITIAL_SESSION" && c.state.status !== "initializing" || event === "TOKEN_REFRESHED" && !c.session && c.state.status !== "initializing") return;
@@ -3932,7 +4203,7 @@ function createBrowserAuth(runtime) {
3932
4203
  replaced && c.revision++, c.timer && clearTimeout(c.timer);
3933
4204
  let pending = c.state.pending;
3934
4205
  if (!session) {
3935
- c.session = null, publish(c, { status: c.state.status === "expired" ? "expired" : "signed_out", ...pending ? { pending } : {} }), notify(c, "SIGNED_OUT");
4206
+ c.session = null, publish2(c, { status: c.state.status === "expired" ? "expired" : "signed_out", ...pending ? { pending } : {} }), notify(c, "SIGNED_OUT");
3936
4207
  return;
3937
4208
  }
3938
4209
  if (!validSession(session)) {
@@ -3941,7 +4212,7 @@ function createBrowserAuth(runtime) {
3941
4212
  }
3942
4213
  c.session = session;
3943
4214
  let email = typeof session.user.email == "string" ? session.user.email.trim() : "", metadata = session.user.user_metadata, name2 = ["name", "full_name", "first_name"].map((key) => metadata?.[key]).find((value) => typeof value == "string" && value.trim())?.trim() || email, account = !replaced && c.state.account?.email === email && c.state.account.displayName === name2 ? c.state.account : Object.freeze({ email, displayName: name2 });
3944
- notify(c, event), publish(c, { status: "signed_in", account, ...pending ? { pending } : {} });
4215
+ notify(c, event), publish2(c, { status: "signed_in", account, ...pending ? { pending } : {} });
3945
4216
  let checkExpiry = () => {
3946
4217
  if (!c.active || !c.session) return;
3947
4218
  let remaining = c.session.expires_at * 1e3 - Date.now();
@@ -3988,9 +4259,9 @@ function createBrowserAuth(runtime) {
3988
4259
  c.unsubscribe = () => subscription.unsubscribe();
3989
4260
  let started = c.revision, { data: data3, error } = await c.provider.getSession();
3990
4261
  if (!current2(c, origin, started)) return;
3991
- error ? terminalSessionFailure(error) ? expire(c) : (!c.session || !validSession(c.session)) && publish(c, { status: "unavailable", error: "unavailable" }) : c.state.pending !== "sign_out" && accept(c, "INITIAL_SESSION", data3.session);
4262
+ error ? terminalSessionFailure(error) ? expire(c) : (!c.session || !validSession(c.session)) && publish2(c, { status: "unavailable", error: "unavailable" }) : c.state.pending !== "sign_out" && accept(c, "INITIAL_SESSION", data3.session);
3992
4263
  } catch {
3993
- current2(c, origin, revision) && publish(c, { status: "unavailable", error: "unavailable" });
4264
+ current2(c, origin, revision) && publish2(c, { status: "unavailable", error: "unavailable" });
3994
4265
  }
3995
4266
  })(), c;
3996
4267
  }
@@ -4028,8 +4299,10 @@ function createBrowserAuth(runtime) {
4028
4299
  if (await c.workspaceAccess.result, !current2(c, origin, revision)) throw runtime.failure("stale");
4029
4300
  }
4030
4301
  return { create() {
4031
- let origin = globalThis.location?.origin ?? "", c = coordinators.get(origin);
4032
- c || (c = createCoordinator(origin), coordinators.set(origin, c));
4302
+ let origin = globalThis.location?.origin ?? "";
4303
+ if (isAppOrigin(origin) && origin !== "http://127.0.0.1:5176") return createLocalBrowserAuth(origin, runtime.failure);
4304
+ let c = coordinators2.get(origin);
4305
+ c || (c = createCoordinator(origin), coordinators2.set(origin, c));
4033
4306
  let coordinator = c;
4034
4307
  coordinator.refs++;
4035
4308
  let active2 = !0, ownedAction, authorizationId, authorizationGeneration = 0, inspected, observers = /* @__PURE__ */ new Set(), sessionObservers = /* @__PURE__ */ new Set(), disposalObservers = /* @__PURE__ */ new Set(), lastState = coordinator.state, observation = (state) => {
@@ -4050,15 +4323,15 @@ function createBrowserAuth(runtime) {
4050
4323
  let marker = {};
4051
4324
  coordinator.action = marker, ownedAction = marker;
4052
4325
  let revision = coordinator.revision;
4053
- publish(coordinator, { ...coordinator.state, error: void 0, pending: kind });
4326
+ publish2(coordinator, { ...coordinator.state, error: void 0, pending: kind });
4054
4327
  try {
4055
4328
  if (await coordinator.ready, assertActive(), !coordinator.provider || !coordinator.active || globalThis.location?.origin !== origin) throw runtime.failure("unavailable");
4056
4329
  if (!current2(coordinator, origin, revision) || coordinator.action !== marker || (await work(coordinator.provider), assertActive(), coordinator.action !== marker) || !current2(coordinator, origin, revision) && kind !== "verify_code" && kind !== "sign_out") throw runtime.failure("stale");
4057
4330
  } catch (error) {
4058
4331
  let reason = active2 ? current2(coordinator, origin, revision) ? safeReason(error) ?? "unavailable" : "stale" : "disposed";
4059
- throw active2 && current2(coordinator, origin, revision) && publish(coordinator, { ...coordinator.state, error: reason }), runtime.failure(reason);
4332
+ throw active2 && current2(coordinator, origin, revision) && publish2(coordinator, { ...coordinator.state, error: reason }), runtime.failure(reason);
4060
4333
  } finally {
4061
- coordinator.action === marker && (coordinator.action = void 0, coordinator.active && (publish(coordinator, { ...coordinator.state, pending: void 0 }), kind === "sign_out" && coordinator.session && notify(coordinator, "TOKEN_REFRESHED"))), ownedAction === marker && (ownedAction = void 0);
4334
+ coordinator.action === marker && (coordinator.action = void 0, coordinator.active && (publish2(coordinator, { ...coordinator.state, pending: void 0 }), kind === "sign_out" && coordinator.session && notify(coordinator, "TOKEN_REFRESHED"))), ownedAction === marker && (ownedAction = void 0);
4062
4335
  }
4063
4336
  }
4064
4337
  async function authorize(kind, id3) {
@@ -4155,7 +4428,7 @@ function createBrowserAuth(runtime) {
4155
4428
  }
4156
4429
  disposalObservers.clear();
4157
4430
  for (let listener of sessionObservers) coordinator.sessions.delete(listener);
4158
- sessionObservers.clear(), --coordinator.refs === 0 && (coordinator.active = !1, coordinator.revision++, coordinator.timer && clearTimeout(coordinator.timer), coordinator.unsubscribe?.(), coordinator.provider?.dispose(), coordinator.provider = void 0, coordinator.session = null, coordinator.listeners.clear(), coordinator.sessions.clear(), coordinators.delete(origin));
4431
+ sessionObservers.clear(), --coordinator.refs === 0 && (coordinator.active = !1, coordinator.revision++, coordinator.timer && clearTimeout(coordinator.timer), coordinator.unsubscribe?.(), coordinator.provider?.dispose(), coordinator.provider = void 0, coordinator.session = null, coordinator.listeners.clear(), coordinator.sessions.clear(), coordinators2.delete(origin));
4159
4432
  }
4160
4433
  }
4161
4434
  });
@@ -4728,6 +5001,7 @@ export {
4728
5001
  question,
4729
5002
  recordBlock,
4730
5003
  recordsBlock,
5004
+ requireRecords,
4731
5005
  resolveAsk,
4732
5006
  respond,
4733
5007
  richTextBlock,