@oddington/sdk 0.1.44 → 0.1.45

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) {
@@ -2374,48 +2438,6 @@ var files = {
2374
2438
  read
2375
2439
  };
2376
2440
 
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
2441
  var ROUTINE_CONNECTION_CREDENTIALS_ENV = "OS_ROUTINE_CONNECTION_CREDENTIALS";
2420
2442
  function parseRoutineConnectionNames(value) {
2421
2443
  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 +2925,41 @@ var source = {
2903
2925
  };
2904
2926
 
2905
2927
  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");
2928
+ constructor(status, reason, requirementsRepository) {
2929
+ 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
2930
  this.status = status;
2909
2931
  this.reason = reason;
2932
+ this.requirementsRepository = requirementsRepository;
2910
2933
  }
2911
2934
  status;
2912
2935
  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;
2936
+ requirementsRepository;
2937
+ };
2938
+ function parseQuestionAvailability(value, available = !1) {
2939
+ let state = object4(value);
2940
+ 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)), {
2941
+ unavailableReason: state.unavailableReason,
2942
+ ...state.unavailableReason === "records_need_attention" ? { requirementsRepository: state.requirementsRepository } : {}
2943
+ }) : (assert(!("requirementsRepository" in state)), {});
2944
+ }
2945
+ function questionAvailability(value, available = !1) {
2946
+ return parseQuestionAvailability({
2947
+ ..."unavailableReason" in value ? { unavailableReason: value.unavailableReason } : {},
2948
+ ..."requirementsRepository" in value ? { requirementsRepository: value.requirementsRepository } : {}
2949
+ }, available);
2950
+ }
2951
+ function parseInboxUnavailableFailure(value, status) {
2952
+ try {
2953
+ if (status !== 503) return;
2954
+ let envelope = object4(value);
2955
+ keys3(envelope, ["error", "unavailableReason", "requirementsRepository"], ["error", "unavailableReason"]), assert(text4(envelope.error));
2956
+ let state = questionAvailability(envelope);
2957
+ return new InboxOperationError(503, state.unavailableReason, state.requirementsRepository);
2958
+ } catch {
2959
+ return;
2960
+ }
2961
+ }
2962
+ 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
2963
  function isAppQuestionOperation(operation2) {
2915
2964
  return operation2 === "questions.list" || operation2 === "questions.answer" || operation2 === "questions.searchRecords";
2916
2965
  }
@@ -3090,7 +3139,7 @@ function parseInboxItem(value) {
3090
3139
  assert(id2(person.id) && text4(person.name));
3091
3140
  }), array2(item.questions).forEach((value2) => {
3092
3141
  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) {
3142
+ 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
3143
  let accepted = object4(question2.acceptedResponse);
3095
3144
  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
3145
  }
@@ -3123,11 +3172,11 @@ function parseAnswerableQuestion(value) {
3123
3172
  let entry = object4(json(value));
3124
3173
  keys3(
3125
3174
  entry,
3126
- ["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions"],
3175
+ ["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable", "tags", "recordRefs", "instructions", "unavailableReason", "requirementsRepository"],
3127
3176
  ["itemId", "number", "revision", "title", "inboxUrl", "questionId", "routine", "prompt", "response", "answerable"]
3128
3177
  ), assert(id2(entry.itemId) && integer(entry.number) && integer(entry.revision) && text4(entry.title) && text4(entry.inboxUrl));
3129
3178
  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;
3179
+ 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
3180
  }
3132
3181
  function askMetadata(entry) {
3133
3182
  let tags = array2(entry.tags === void 0 ? [] : entry.tags);
@@ -3436,7 +3485,7 @@ function appContext(origin, active2) {
3436
3485
  observation === observed && (observation = void 0);
3437
3486
  }
3438
3487
  }
3439
- async function renew() {
3488
+ async function renew(initialConnection = !1) {
3440
3489
  if (renewal) return renewal;
3441
3490
  if (!binding || !pair || !alive()) throw new Error();
3442
3491
  renewal = (async () => {
@@ -3462,7 +3511,7 @@ function appContext(origin, active2) {
3462
3511
  await synchronize(requestController.signal);
3463
3512
  return;
3464
3513
  }
3465
- if (!response2.ok) throw new Error();
3514
+ if (!response2.ok) throw response2.status === 401 || response2.status === 403 ? new AppContextDenied() : new Error();
3466
3515
  if (!alive() || !validPair(value) || !bounded3(value.context) || (/* @__PURE__ */ new Set([value.credential, value.renewalCredential, pair.credential, pair.renewalCredential])).size !== 4) throw new Error();
3467
3516
  if (stored() !== previous) {
3468
3517
  await synchronize(requestController.signal);
@@ -3471,6 +3520,7 @@ function appContext(origin, active2) {
3471
3520
  let raw = JSON.stringify(value);
3472
3521
  globalThis.localStorage.setItem(sessionKey, raw), install(value.context, value, raw);
3473
3522
  } catch (error) {
3523
+ if (initialConnection && error instanceof AppContextDenied) throw error;
3474
3524
  try {
3475
3525
  if (alive() && stored() && stored() !== previous) {
3476
3526
  await synchronize(requestController.signal);
@@ -3599,8 +3649,32 @@ function appContext(origin, active2) {
3599
3649
  try {
3600
3650
  if (!alive()) throw new Error();
3601
3651
  if (!pair) {
3602
- let candidate2 = stored(), retained3 = readPair(candidate2);
3603
- pair = retained3, binding = { ...retained3.context }, credential = retained3.credential, serialized = candidate2;
3652
+ let candidate2 = stored();
3653
+ if (candidate2)
3654
+ try {
3655
+ let retained3 = readPair(candidate2);
3656
+ if (retained3.context.expiresAt <= Date.now()) {
3657
+ if (pair = retained3, binding = { ...retained3.context }, credential = retained3.credential, serialized = candidate2, await renew(!0), !current2()) throw new AppRenewalUnavailable();
3658
+ return context();
3659
+ }
3660
+ let value3 = await proof(retained3.credential);
3661
+ return stored() !== candidate2 ? resolveOnce() : (install(value3, retained3, candidate2), context());
3662
+ } catch (error) {
3663
+ if (error instanceof AppRenewalUnavailable || error instanceof AppResponseReadError || !(error instanceof AppContextDenied) || !alive() || expiry) throw error;
3664
+ pair = void 0, binding = void 0, credential = void 0, serialized = void 0;
3665
+ }
3666
+ let response2 = await untilAborted(fetch(`${origin}/_os/app/connect`, {
3667
+ method: "POST",
3668
+ credentials: "omit",
3669
+ redirect: "error",
3670
+ cache: "no-store",
3671
+ referrerPolicy: "no-referrer",
3672
+ signal: controller.signal
3673
+ }), controller.signal), value2 = await appResponse(response2, 4096, controller.signal);
3674
+ if (!response2.ok || response2.redirected || response2.url && response2.url !== `${origin}/_os/app/connect` || !alive() || !validPair(value2) || !bounded3(value2.context)) throw new Error();
3675
+ if (stored() !== candidate2 && stored()) return resolveOnce();
3676
+ let raw = JSON.stringify(value2);
3677
+ return globalThis.localStorage.setItem(sessionKey, raw), install(value2.context, value2, raw), context();
3604
3678
  }
3605
3679
  if (expireAccess(), binding.expiresAt <= Date.now()) {
3606
3680
  if (await renew(), !current2()) throw new AppRenewalUnavailable();
@@ -3630,7 +3704,7 @@ function appContext(origin, active2) {
3630
3704
  resolution2 = void 0;
3631
3705
  }), resolution2);
3632
3706
  return { resolve, retained: async () => {
3633
- if (!expiry && alive() && (binding ? current2() && resolution2 : readPair(stored()).context.expiresAt > Date.now()))
3707
+ if (!expiry && alive() && (binding ? current2() && resolution2 : !stored() || readPair(stored()).context.expiresAt > Date.now()))
3634
3708
  return resolve();
3635
3709
  if (!expiry || !current2()) throw new Error("Local app context unavailable.");
3636
3710
  return context();
@@ -3681,7 +3755,7 @@ async function send2(operation2, input, resolved) {
3681
3755
  };
3682
3756
  try {
3683
3757
  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(
3758
+ if (check2(), !response2.ok) throw parseInboxUnavailableFailure(value, response2.status) ?? new InboxOperationError(
3685
3759
  [400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
3686
3760
  response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
3687
3761
  );
@@ -3723,12 +3797,20 @@ async function send2(operation2, input, resolved) {
3723
3797
  throw response2.body?.cancel().catch(() => {
3724
3798
  }), error;
3725
3799
  }
3726
- if (!response2.ok)
3727
- throw response2.body?.cancel().catch(() => {
3728
- }), new InboxOperationError(
3800
+ if (!response2.ok) {
3801
+ let value2;
3802
+ try {
3803
+ let bytes2 = await limitedBody(response2, 8192);
3804
+ check(), bytes2 && (value2 = JSON.parse(new TextDecoder().decode(bytes2)));
3805
+ } catch {
3806
+ check();
3807
+ }
3808
+ let refusal = parseInboxUnavailableFailure(value2, response2.status);
3809
+ throw refusal || new InboxOperationError(
3729
3810
  [400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
3730
3811
  response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
3731
3812
  );
3813
+ }
3732
3814
  if (response2.status !== 200)
3733
3815
  throw response2.body?.cancel().catch(() => {
3734
3816
  }), unavailable3();
@@ -4728,6 +4810,7 @@ export {
4728
4810
  question,
4729
4811
  recordBlock,
4730
4812
  recordsBlock,
4813
+ requireRecords,
4731
4814
  resolveAsk,
4732
4815
  respond,
4733
4816
  richTextBlock,