@oddington/sdk 0.1.11 → 0.1.12

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
@@ -131,8 +131,8 @@ function validateBlock(value) {
131
131
  });
132
132
  return (!records.length || new Set(records.map((r) => r.ref)).size !== records.length) && fail("Empty or duplicate records"), { kind: "records", label, records, ...target, ...expanded };
133
133
  }
134
- let files2 = array(b.files, "files").map(validateInboxFile);
135
- return (!files2.length || new Set(files2.map((file) => file.id)).size !== files2.length) && fail("Empty or duplicate files"), { kind: "files", label, files: files2, ...expanded };
134
+ let files3 = array(b.files, "files").map(validateInboxFile);
135
+ return (!files3.length || new Set(files3.map((file2) => file2.id)).size !== files3.length) && fail("Empty or duplicate files"), { kind: "files", label, files: files3, ...expanded };
136
136
  }
137
137
  function richTextBlock(value) {
138
138
  return validateBlock({ ...value, kind: "rich-text" });
@@ -161,8 +161,8 @@ function validateAuthoredSource(value) {
161
161
  keys(option, ["value", "label", "description", "note"], "choice");
162
162
  let note;
163
163
  if (option.note !== void 0) {
164
- let declaration = object(option.note, "choice note");
165
- keys(declaration, ["placeholder"], "choice note"), note = { placeholder: text(declaration.placeholder, "note placeholder") };
164
+ let declaration2 = object(option.note, "choice note");
165
+ keys(declaration2, ["placeholder"], "choice note"), note = { placeholder: text(declaration2.placeholder, "note placeholder") };
166
166
  }
167
167
  return {
168
168
  value: id(option.value, "choice value"),
@@ -208,8 +208,8 @@ function validateRecordSource(value) {
208
208
  let suggestions = array(source.suggestions ?? [], "suggestions").map((value2) => {
209
209
  let entry = object(value2, "suggestion");
210
210
  keys(entry, ["record", "reason"], "suggestion");
211
- let record2 = validateRecordReference(entry.record);
212
- return record2.repository !== repository && fail("Suggestion belongs to another repository"), { record: record2, ...entry.reason === void 0 ? {} : { reason: text(entry.reason, "suggestion reason") } };
211
+ let record3 = validateRecordReference(entry.record);
212
+ return record3.repository !== repository && fail("Suggestion belongs to another repository"), { record: record3, ...entry.reason === void 0 ? {} : { reason: text(entry.reason, "suggestion reason") } };
213
213
  });
214
214
  return (suggestions.length > 8 || new Set(suggestions.map((entry) => entry.record.ref)).size !== suggestions.length) && fail("Record selection permits at most eight unique suggestions"), {
215
215
  type: "records",
@@ -239,7 +239,11 @@ function handlerReference(value) {
239
239
  }
240
240
  function defineHandler(value) {
241
241
  let source = object(value, "handler");
242
- return keys(source, ["id", "run"], "handler"), id(source.id, "handler ID"), typeof source.run != "function" && fail("Handler requires a run function"), Object.freeze({ id: value.id, run: value.run });
242
+ keys(source, ["id", "results", "run"], "handler");
243
+ let stable = (value2) => typeof value2 == "string" && /^[a-zA-Z0-9][a-zA-Z0-9_./-]{0,127}$/.test(value2);
244
+ stable(source.id) || fail("Handler ID must be stable");
245
+ let results = source.results === void 0 ? void 0 : distinctIds(source.results, "handler results", !1);
246
+ return results && (results.length > 64 || results.some((result2) => !stable(result2))) && fail("Handler results must be stable IDs"), typeof source.run != "function" && fail("Handler requires a run function"), Object.freeze({ id: value.id, ...results === void 0 ? {} : { results: Object.freeze(results.sort()) }, run: value.run });
243
247
  }
244
248
  function respond(handler, input) {
245
249
  return defineHandler(handler), handlerReference({ id: handler.id, input });
@@ -266,7 +270,7 @@ function presentation(source) {
266
270
  new Set(views.map((view) => view.id)).size !== views.length && fail("Duplicate view ID");
267
271
  let body2 = source.body === void 0 ? [] : array(source.body, "body").map(validateBlock);
268
272
  for (let block of body2) {
269
- let targets = block.kind === "record" ? [block.view] : block.kind === "records" ? [block.view, ...block.records.map((record2) => record2.view)] : [];
273
+ let targets = block.kind === "record" ? [block.view] : block.kind === "records" ? [block.view, ...block.records.map((record3) => record3.view)] : [];
270
274
  for (let target of targets) target !== void 0 && !views.some((view) => view.id === target) && fail(`Unknown Block View target: ${target}`);
271
275
  }
272
276
  return { title: text(source.title, "title"), description: text(source.description, "description"), views, body: body2 };
@@ -375,331 +379,323 @@ function validateRecordRead(value) {
375
379
  };
376
380
  }
377
381
 
378
- var RECORD_WRITE_INPUT_LIMIT = 8 * 1024 * 1024, RoutineRecordWriteError = class extends Error {
379
- constructor(message, effect) {
380
- super(message);
381
- this.effect = effect;
382
- this.name = "RoutineRecordWriteError";
382
+ var FileOperationError = class extends Error {
383
+ constructor(code, status, retryable = !1) {
384
+ super(code);
385
+ this.code = code;
386
+ this.status = status;
387
+ this.retryable = retryable;
383
388
  }
384
- effect;
385
- };
386
- function validateRecordWrite(value) {
387
- let input = serializable(value);
388
- if (!input || Array.isArray(input) || typeof input != "object" || Object.keys(input).sort().join(",") !== "records,repository" || !validRepositoryAlias(input.repository) || !Array.isArray(input.records) || !input.records.length || input.records.length > 1e4 || new Set(input.records.map((edit) => edit?.ref)).size !== input.records.length)
389
- throw new InboxContractError("Invalid record update batch");
390
- for (let edit of input.records) {
391
- if (!edit || Array.isArray(edit) || typeof edit != "object" || !validRecordRef(edit.ref))
392
- throw new InboxContractError("Invalid record edit");
393
- if ("expectedVersion" in edit) {
394
- if (Object.keys(edit).sort().join(",") !== "expectedVersion,ref,set" || typeof edit.expectedVersion != "string" || !/^record-v1:[0-9a-f]{64}$/.test(edit.expectedVersion) || !edit.set || Array.isArray(edit.set) || typeof edit.set != "object" || !Object.keys(edit.set).length)
395
- throw new InboxContractError("Invalid record edit");
396
- continue;
397
- }
398
- if (Object.keys(edit).sort().join(",") !== "fields,path,ref" || typeof edit.path != "string" || !validCreatePath(edit.path) || !edit.fields || Array.isArray(edit.fields) || typeof edit.fields != "object" || !Object.keys(edit.fields).length)
399
- throw new InboxContractError("Invalid record creation");
389
+ code;
390
+ status;
391
+ retryable;
392
+ }, 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
+ function parseFileDescriptor(value) {
394
+ let invalid5 = () => {
395
+ throw new FileOperationError("unavailable", 503, !0);
396
+ };
397
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid5();
398
+ 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 invalid5();
400
+ let d = f.details;
401
+ if (d.kind === "other") {
402
+ if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid5();
403
+ } 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 invalid5();
405
+ } 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 invalid5();
407
+ } else return invalid5();
408
+ for (let [name, descriptor2] of Object.entries(f.enrichments)) {
409
+ if (!safeEnrichmentName(name)) return invalid5();
410
+ parseEnrichmentDescriptor(descriptor2);
400
411
  }
401
- return structuredClone(input);
402
- }
403
- function validateRecordUpdate(value) {
404
- let input = validateRecordWrite(value);
405
- if (input.records.some((record2) => !("expectedVersion" in record2)))
406
- throw new InboxContractError("Record creation is unavailable for this operation");
407
- return input;
412
+ return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid5() : f;
408
413
  }
409
- function validateRecordDelete(value) {
410
- let input = serializable(value);
411
- if (!input || Array.isArray(input) || typeof input != "object" || Object.keys(input).sort().join(",") !== "records,repository" || !validRepositoryAlias(input.repository) || !Array.isArray(input.records) || !input.records.length || input.records.length > 1e4 || new Set(input.records.map((record2) => record2?.ref)).size !== input.records.length)
412
- throw new InboxContractError("Invalid record deletion batch");
413
- for (let record2 of input.records)
414
- if (!record2 || Array.isArray(record2) || typeof record2 != "object" || Object.keys(record2).sort().join(",") !== "expectedVersion,ref" || !validRecordRef(record2.ref) || typeof record2.expectedVersion != "string" || !/^record-v1:[0-9a-f]{64}$/.test(record2.expectedVersion))
415
- throw new InboxContractError("Invalid record deletion");
416
- return structuredClone(input);
414
+ function parseEnrichmentDescriptor(value) {
415
+ let invalid5 = () => {
416
+ throw new FileOperationError("unavailable", 503, !0);
417
+ };
418
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid5();
419
+ 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) ? invalid5() : d;
417
421
  }
418
- function validateRecordChange(value) {
419
- let input = serializable(value);
420
- if (!input || Array.isArray(input) || typeof input != "object" || Object.keys(input).sort().join(",") !== "records,repository" || !validRepositoryAlias(input.repository) || !Array.isArray(input.records) || !input.records.length || input.records.length > 1e4 || new Set(input.records.map((record2) => record2?.ref)).size !== input.records.length || new TextEncoder().encode(JSON.stringify(input)).byteLength > RECORD_WRITE_INPUT_LIMIT)
421
- throw new InboxContractError("Invalid record change batch");
422
- let writes = [], deletes = [];
423
- for (let record2 of input.records) {
424
- if (!record2 || typeof record2 != "object" || Array.isArray(record2))
425
- throw new InboxContractError("Invalid record change");
426
- "set" in record2 || "fields" in record2 ? writes.push(record2) : deletes.push(record2);
427
- }
428
- return writes.length && validateRecordWrite({ repository: input.repository, records: writes }), deletes.length && validateRecordDelete({ repository: input.repository, records: deletes }), structuredClone(input);
422
+ function safeEnrichmentName(value) {
423
+ return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
429
424
  }
430
- function validateRoutineRecordWrite(value) {
431
- let body2 = serializable(value);
432
- if (!body2 || typeof body2 != "object" || Array.isArray(body2) || Object.keys(body2).sort().join(",") !== "input,requestKey" || typeof body2.requestKey != "string" || !body2.requestKey.trim() || body2.requestKey !== body2.requestKey.trim() || body2.requestKey.length > 512)
433
- throw new InboxContractError("A stable routine request key is required");
434
- return { input: validateRecordChange(body2.input), requestKey: body2.requestKey };
425
+ function parseFileEnrichMetadata(value, maxBytes) {
426
+ let invalid5 = () => {
427
+ throw new FileOperationError("invalid_input", 400);
428
+ };
429
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid5();
430
+ 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 invalid5();
432
+ if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
433
+ return d;
435
434
  }
436
- function validCreatePath(value) {
437
- return value === value.trim() && value.endsWith(".md") && !value.startsWith("/") && value.split("/").every((segment) => !!segment && ![".", ".."].includes(segment) && /^[a-zA-Z0-9_.-]+$/.test(segment));
435
+ function safeFileName(value) {
436
+ return typeof value == "string" && value.length > 0 && value.length <= 255 && value === value.trim() && value !== "." && value !== ".." && !/[\u0000-\u001f\u007f-\u009f/\\:*?"<>|]/u.test(value) && !/[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/.test(value) && !/[. ]$/.test(value) && !/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(value);
438
437
  }
439
-
440
- function validGoogleScopes(value) {
441
- 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;
438
+ function safeFilePath(value) {
439
+ return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
442
440
  }
443
-
444
- var ROUTINE_CONNECTION_CREDENTIALS_ENV = "ODDINGTON_ROUTINE_CONNECTION_CREDENTIALS";
445
- 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);
446
- function parseConnectionLease(raw, now = Date.now()) {
447
- let v = raw;
448
- 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))
449
- throw new Error("Invalid connection credential");
450
- if (v.provider === "gmail") {
451
- if (Object.keys(v).sort().join(",") !== "accessToken,accountEmail,connectionId,expiresAt,name,provider,runId,scopes" || typeof v.accountEmail != "string" || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.accountEmail) || !validGoogleScopes(v.scopes) || typeof v.expiresAt != "string" || !Number.isFinite(Date.parse(v.expiresAt)) || Date.parse(v.expiresAt) <= now + 6e4 || Date.parse(v.expiresAt) > now + 36e5)
452
- throw new Error("Invalid connection credential");
453
- return v;
441
+ function parseFileCreateMetadata(value, maxBytes) {
442
+ let invalid5 = () => {
443
+ throw new FileOperationError("invalid_input", 400);
444
+ };
445
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid5();
446
+ let input = value;
447
+ if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "inputMediaType", "size", "requestKey"].includes(key))) return invalid5();
448
+ 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 invalid5();
450
+ 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 invalid5();
452
+ let csv;
453
+ if (input.csv !== void 0) {
454
+ if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid5();
455
+ let hints = input.csv;
456
+ if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid5();
457
+ 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 invalid5();
459
+ csv = { encoding, delimiter, headerRow };
454
460
  }
455
- if (v.provider === "airtable" && Object.keys(v).sort().join(",") === "accessToken,baseId,connectionId,name,provider,runExpiresAt,runId" && typeof v.baseId == "string" && /^app[A-Za-z0-9]+$/.test(v.baseId) && typeof v.runExpiresAt == "string" && Number.isFinite(Date.parse(v.runExpiresAt)) && Date.parse(v.runExpiresAt) > now + 6e4 && Date.parse(v.runExpiresAt) <= now + 15 * 6e4)
456
- return v;
457
- throw new Error("Invalid connection credential");
461
+ return {
462
+ name: input.name,
463
+ path,
464
+ ...input.storage ? { storage: input.storage } : {},
465
+ ...input.inputMediaType === "application/pdf" ? { inputMediaType: input.inputMediaType } : {},
466
+ ...csv ? { csv } : {},
467
+ size: input.size,
468
+ requestKey: input.requestKey
469
+ };
458
470
  }
459
471
 
460
- var AirtableOperationError = class extends Error {
461
- constructor(message, effect = "unapplied", receipts = []) {
462
- super(message);
463
- this.effect = effect;
464
- this.receipts = receipts;
465
- this.name = "AirtableOperationError";
472
+ var AppRoutineContractError = class extends Error {
473
+ constructor(code) {
474
+ super(code);
475
+ this.code = code;
466
476
  }
467
- effect;
468
- receipts;
477
+ code;
478
+ }, propertyName = /^[a-z][A-Za-z0-9]*(?![\s\S])/, stepId = /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/, routineName = /^[a-z0-9][a-z0-9-]{0,62}(?![\s\S])/, owns = (value, key) => Object.hasOwn(value, key), invalidContract = () => {
479
+ throw new AppRoutineContractError("invalid_contract");
480
+ }, invalidValue = () => {
481
+ throw new AppRoutineContractError("invalid_value");
469
482
  };
470
-
471
- var recordId = (v) => typeof v == "string" && /^rec[A-Za-z0-9]+$/.test(v), tableId = (v) => typeof v == "string" && /^tbl[A-Za-z0-9]+$/.test(v);
472
- function fail2(message) {
473
- throw new AirtableOperationError(message);
474
- }
475
- function object2(v) {
476
- return (!v || typeof v != "object" || Array.isArray(v) || ![null, Object.prototype].includes(Object.getPrototypeOf(v))) && fail2("Invalid Airtable data"), v;
477
- }
478
- function keys2(v, allowed, required = allowed) {
479
- (Object.keys(v).some((k) => !allowed.includes(k)) || required.some((k) => !Object.hasOwn(v, k))) && fail2("Invalid Airtable input");
483
+ function record(value) {
484
+ return value !== null && typeof value == "object" && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
485
+ }
486
+ function fields2(value, required, optional = []) {
487
+ return required.every((key) => owns(value, key)) && Object.keys(value).every((key) => required.includes(key) || optional.includes(key));
488
+ }
489
+ function denseArray(value) {
490
+ return Array.isArray(value) && Object.keys(value).length === value.length && Array.from({ length: value.length }, (_, index) => owns(value, String(index))).every(Boolean);
491
+ }
492
+ function parseAppRoutineContract(value) {
493
+ let properties = 0;
494
+ function schema2(value2, depth = 1) {
495
+ if (depth > 8 || !record(value2)) return invalidContract();
496
+ switch (value2.type) {
497
+ case "object": {
498
+ if (!fields2(value2, ["type", "properties", "additionalProperties"], ["required"]) || value2.additionalProperties !== !1 || !record(value2.properties)) return invalidContract();
499
+ let entries = Object.entries(value2.properties);
500
+ if (properties += entries.length, properties > 64 || entries.some(([key]) => !propertyName.test(key))) return invalidContract();
501
+ let required;
502
+ if (owns(value2, "required")) {
503
+ if (!denseArray(value2.required) || value2.required.some((key) => typeof key != "string" || !owns(value2.properties, key)) || new Set(value2.required).size !== value2.required.length) return invalidContract();
504
+ required = [...value2.required];
505
+ }
506
+ return {
507
+ type: "object",
508
+ properties: Object.fromEntries(entries.map(([key, child]) => [key, schema2(child, depth + 1)])),
509
+ ...required === void 0 ? {} : { required },
510
+ additionalProperties: !1
511
+ };
512
+ }
513
+ case "array":
514
+ 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 };
515
+ case "boolean":
516
+ case "file":
517
+ return fields2(value2, ["type"]) ? { type: value2.type } : invalidContract();
518
+ case "string":
519
+ 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 } : {} };
520
+ case "integer":
521
+ case "number": {
522
+ let validNumber = value2.type === "integer" ? Number.isSafeInteger : Number.isFinite;
523
+ return !fields2(value2, ["type"], ["minimum", "maximum"]) || owns(value2, "minimum") && !validNumber(value2.minimum) || owns(value2, "maximum") && !validNumber(value2.maximum) || owns(value2, "minimum") && owns(value2, "maximum") && value2.minimum > value2.maximum ? invalidContract() : {
524
+ type: value2.type,
525
+ ...owns(value2, "minimum") ? { minimum: value2.minimum } : {},
526
+ ...owns(value2, "maximum") ? { maximum: value2.maximum } : {}
527
+ };
528
+ }
529
+ default:
530
+ return invalidContract();
531
+ }
532
+ }
533
+ if (!record(value) || !fields2(value, ["routine", "input", "steps"], ["result"]) || typeof value.routine != "string" || !routineName.test(value.routine) || !denseArray(value.steps) || value.steps.length < 1 || value.steps.length > 64) return invalidContract();
534
+ let input = schema2(value.input), result2 = owns(value, "result") ? schema2(value.result) : void 0, ids = /* @__PURE__ */ new Set(), steps = value.steps.map((step) => !record(step) || !fields2(step, ["id"], ["summary"]) || typeof step.id != "string" || !stepId.test(step.id) || ids.has(step.id) ? invalidContract() : (ids.add(step.id), { id: step.id, ...owns(step, "summary") ? { summary: schema2(step.summary) } : {} }));
535
+ return { routine: value.routine, input, steps, ...result2 === void 0 ? {} : { result: result2 } };
480
536
  }
481
- function text2(v) {
482
- return typeof v == "string" && v.length > 0 && v.length <= 1024;
537
+ function jsonData(value, ancestors = /* @__PURE__ */ new Set()) {
538
+ if (!(value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value))) {
539
+ if (!record(value) && !denseArray(value) || ancestors.has(value)) return invalidValue();
540
+ ancestors.add(value);
541
+ for (let child of Object.values(value)) jsonData(child, ancestors);
542
+ ancestors.delete(value);
543
+ }
483
544
  }
484
- function fields2(v, nonempty = !1) {
485
- let result2 = object2(v);
486
- (nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !text2(k))) && fail2("Invalid Airtable fields");
487
- try {
488
- return serializable(result2);
489
- } catch {
490
- return fail2("Invalid Airtable fields");
545
+ function validateRoutineSchemaValue(schema2, value) {
546
+ switch (schema2.type) {
547
+ case "object":
548
+ if (!record(value) || (schema2.required ?? []).some((key) => !owns(value, key)) || Object.keys(value).some((key) => !owns(schema2.properties, key))) return invalidValue();
549
+ for (let [key, child] of Object.entries(value)) validateRoutineSchemaValue(schema2.properties[key], child);
550
+ return;
551
+ case "array":
552
+ if (!denseArray(value) || value.length > schema2.maxItems) return invalidValue();
553
+ for (let child of value) validateRoutineSchemaValue(schema2.items, child);
554
+ return;
555
+ case "boolean":
556
+ return typeof value != "boolean" ? invalidValue() : void 0;
557
+ case "string":
558
+ return typeof value != "string" || Array.from(value).length > (schema2.maxLength ?? 4096) ? invalidValue() : void 0;
559
+ case "integer":
560
+ case "number":
561
+ return typeof value != "number" || !(schema2.type === "integer" ? Number.isSafeInteger(value) : Number.isFinite(value)) || schema2.minimum !== void 0 && value < schema2.minimum || schema2.maximum !== void 0 && value > schema2.maximum ? invalidValue() : void 0;
562
+ case "file":
563
+ try {
564
+ jsonData(value), parseFileDescriptor(value);
565
+ } catch {
566
+ return invalidValue();
567
+ }
491
568
  }
492
569
  }
493
- function record(v) {
494
- let r = object2(v);
495
- 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: fields2(r.fields) };
570
+
571
+ var LIMIT = 256 * 1024, invalid = () => {
572
+ throw new AppRoutineContractError("invalid_value");
573
+ }, invalidContract2 = () => {
574
+ throw new AppRoutineContractError("invalid_contract");
575
+ }, empty = { type: "object", properties: {}, required: [], additionalProperties: !1 };
576
+ function freeze(value) {
577
+ if (value !== null && typeof value == "object") {
578
+ for (let child of Object.values(value)) freeze(child);
579
+ Object.freeze(value);
580
+ }
581
+ return value;
496
582
  }
497
- function equal(a, b) {
498
- if (a === b) return !0;
499
- if (!a || !b || typeof a != "object" || typeof b != "object" || Array.isArray(a) !== Array.isArray(b)) return !1;
500
- let left = Object.keys(a), right = Object.keys(b);
501
- return left.length === right.length && left.every((k) => Object.hasOwn(b, k) && equal(
502
- a[k],
503
- b[k]
504
- ));
583
+ function json(value, ancestors = /* @__PURE__ */ new Set()) {
584
+ if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return;
585
+ if (!value || typeof value != "object" || ancestors.has(value)) return invalid();
586
+ let array2 = Array.isArray(value);
587
+ if (!array2 && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return invalid();
588
+ let keys4 = Reflect.ownKeys(value);
589
+ if (array2 && (keys4.length !== value.length + 1 || !Array.from({ length: value.length }, (_, index) => Object.hasOwn(value, index)).every(Boolean))) return invalid();
590
+ ancestors.add(value);
591
+ for (let key of keys4) {
592
+ if (array2 && key === "length") continue;
593
+ if (typeof key != "string") return invalid();
594
+ let descriptor2 = Object.getOwnPropertyDescriptor(value, key);
595
+ if (!descriptor2.enumerable || !Object.hasOwn(descriptor2, "value")) return invalid();
596
+ json(descriptor2.value, ancestors);
597
+ }
598
+ ancestors.delete(value);
505
599
  }
506
- function createConnections(transport) {
507
- return { airtable(name) {
508
- (typeof name != "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(name)) && fail2("Invalid Airtable connection name");
509
- let call = (operation2, input) => transport(name, operation2, input);
510
- return {
511
- tables: { list: async () => await call("tables.list", {}) },
512
- records: {
513
- list: async (input) => await call("records.list", input),
514
- get: async (input) => await call("records.get", input),
515
- create: async (input) => await call("records.create", input),
516
- update: async (input) => await call("records.update", input),
517
- delete: async (input) => await call("records.delete", input)
518
- }
519
- };
520
- } };
600
+ function capture(schema2, value) {
601
+ json(value), validateRoutineSchemaValue(schema2, value);
602
+ let encoded = JSON.stringify(value);
603
+ return new TextEncoder().encode(encoded).byteLength > LIMIT ? invalid() : freeze(JSON.parse(encoded));
521
604
  }
522
- async function executeAirtableOperation(authority, operation2, raw, options = {}) {
523
- let { name, baseId, accessToken } = authority;
524
- (!/^[a-z0-9][a-z0-9-]{0,62}$/.test(name) || !/^app[A-Za-z0-9]+$/.test(baseId) || !/^[A-Za-z0-9._~+/-]{1,8192}={0,2}$/.test(accessToken)) && fail2("Airtable connection unavailable");
525
- let input;
605
+ function declaration(value) {
526
606
  try {
527
- input = object2(serializable(raw));
607
+ json(value);
528
608
  } catch {
529
- return fail2("Invalid Airtable input");
609
+ return invalidContract2();
530
610
  }
531
- let mutation = ["records.create", "records.update", "records.delete"].includes(operation2), receipt = (ids2) => ({
532
- provider: "airtable",
533
- connection: `airtable/${name}`,
534
- baseId,
535
- table: input.table,
536
- operation: operation2.slice(8),
537
- records: ids2.map((id2) => ({ id: id2 }))
611
+ return freeze(parseAppRoutineContract({ routine: "definition", input: value, steps: [{ id: "inspect" }] }).input);
612
+ }
613
+ var schema = {
614
+ object(properties) {
615
+ return declaration({ type: "object", properties, required: Object.keys(properties), additionalProperties: !1 });
616
+ },
617
+ array(items, options) {
618
+ return declaration({ type: "array", items, maxItems: options.maxItems });
619
+ },
620
+ string(options = {}) {
621
+ return declaration({ type: "string", ...options });
622
+ },
623
+ integer(options = {}) {
624
+ return declaration({ type: "integer", ...options });
625
+ },
626
+ number(options = {}) {
627
+ return declaration({ type: "number", ...options });
628
+ },
629
+ boolean() {
630
+ return declaration({ type: "boolean" });
631
+ }
632
+ }, file = () => declaration({ type: "file" }), definitions = /* @__PURE__ */ new WeakMap(), defineRoutine = (definition) => {
633
+ if (!definition || typeof definition != "object" || Object.getPrototypeOf(definition) !== Object.prototype || Reflect.ownKeys(definition).some((key) => typeof key != "string" || !["input", "steps", "result", "run"].includes(key) || !Object.getOwnPropertyDescriptor(definition, key).enumerable || !Object.hasOwn(Object.getOwnPropertyDescriptor(definition, key), "value")) || typeof definition.run != "function") return invalidContract2();
634
+ try {
635
+ for (let key of ["input", "steps", "result"])
636
+ definition[key] !== void 0 && json(definition[key]);
637
+ } catch {
638
+ return invalidContract2();
639
+ }
640
+ if (definition.steps !== void 0 && (!definition.steps || typeof definition.steps != "object" || Array.isArray(definition.steps))) return invalidContract2();
641
+ let steps = definition.steps === void 0 ? [] : Object.entries(definition.steps).map(([id2, summary]) => ({ id: id2, ...summary === null ? {} : { summary } })), parsed = parseAppRoutineContract({
642
+ routine: "definition",
643
+ input: definition.input === void 0 ? empty : definition.input,
644
+ steps: steps.length ? steps : [{ id: "inspect" }],
645
+ ...definition.result === void 0 ? {} : { result: definition.result }
646
+ }), contract = freeze({
647
+ input: parsed.input,
648
+ steps: steps.length ? parsed.steps : [],
649
+ ...parsed.result === void 0 ? {} : { result: parsed.result }
650
+ }), captured = Object.freeze({
651
+ ...definition,
652
+ ...definition.input === void 0 ? {} : { input: contract.input },
653
+ ...definition.steps === void 0 ? {} : { steps: freeze(Object.fromEntries(contract.steps.map((step) => [step.id, step.summary ?? null]))) },
654
+ ...definition.result === void 0 ? {} : { result: contract.result },
655
+ // Only this authored definition is callable; no generic runner is exported.
656
+ run: (input, os2) => executeRoutineDefinition(captured, input, os2)
538
657
  });
539
- async function request(path2, init2 = {}, write = !1) {
540
- let response;
541
- try {
542
- response = await (options.fetch ?? fetch)(`https://api.airtable.com/v0/${path2}`, {
543
- ...init2,
544
- headers: { authorization: `Bearer ${accessToken}`, "content-type": "application/json" },
545
- redirect: "manual",
546
- signal: options.signal ? AbortSignal.any([options.signal, AbortSignal.timeout(15e3)]) : AbortSignal.timeout(15e3)
547
- });
548
- } catch {
549
- throw new AirtableOperationError("Airtable request acknowledgment unavailable", write ? "uncertain" : "unapplied");
550
- }
551
- if (!response.ok)
552
- throw await response.body?.cancel().catch(() => {
553
- }), new AirtableOperationError("Airtable request rejected", write && (response.status >= 500 || response.status === 408 || response.status < 400) ? "uncertain" : "unapplied");
554
- try {
555
- if (!response.headers.get("content-type")?.toLowerCase().includes("application/json")) throw new Error();
556
- let value = object2(await response.json()), safe = serializable(value);
557
- if (Object.hasOwn(value, "error") || JSON.stringify(safe).includes(accessToken)) throw new Error();
558
- return value;
559
- } catch {
560
- throw new AirtableOperationError("Malformed Airtable acknowledgment", write ? "uncertain" : "unapplied");
658
+ return definitions.set(captured, { contract, run: definition.run }), captured;
659
+ };
660
+ function inspectRoutineDefinition(definition) {
661
+ if (!definition || typeof definition != "object") return invalidContract2();
662
+ let registered = definitions.get(definition);
663
+ return registered ? registered.contract : invalidContract2();
664
+ }
665
+ function captureRoutineInput(definition, input) {
666
+ return capture(inspectRoutineDefinition(definition).input, input);
667
+ }
668
+ async function executeRoutineDefinition(definition, input, runtime) {
669
+ let captured = captureRoutineInput(definition, input), { contract, run } = definitions.get(definition), active2 = !0, broken = !1, reports = Promise.resolve(), os2 = Object.freeze({
670
+ ...runtime,
671
+ run: freeze({ ...runtime.run }),
672
+ step(id2, ...summary) {
673
+ if (!active2 || broken || summary.length > 1)
674
+ return broken = !0, Promise.reject(new AppRoutineContractError("invalid_value"));
675
+ let value;
676
+ try {
677
+ let step = contract.steps.find((step2) => step2.id === id2);
678
+ if (!step) return invalid();
679
+ if (step.summary === void 0) {
680
+ if (summary.length) return invalid();
681
+ } else value = capture(step.summary, summary[0]);
682
+ } catch (error) {
683
+ return broken = !0, Promise.reject(error);
684
+ }
685
+ let report = reports.then(() => broken ? invalid() : runtime.step(id2, value));
686
+ return reports = report.catch(() => {
687
+ broken = !0;
688
+ }), report;
561
689
  }
690
+ });
691
+ try {
692
+ let result2 = await run(captured, os2);
693
+ return active2 = !1, await reports, broken ? invalid() : contract.result !== void 0 ? capture(contract.result, result2) : result2 !== void 0 ? invalid() : void 0;
694
+ } finally {
695
+ active2 = !1;
562
696
  }
563
- if (operation2 === "tables.list") {
564
- keys2(input, []);
565
- let tables = [], seen = /* @__PURE__ */ new Set(), offset;
566
- do {
567
- let query2 = new URLSearchParams(offset ? { offset } : {}), page = await request(`meta/bases/${baseId}/tables?${query2}`);
568
- Array.isArray(page.tables) || fail2("Malformed Airtable tables");
569
- for (let value of page.tables) {
570
- let t = object2(value);
571
- (!tableId(t.id) || !text2(t.name) || !text2(t.primaryFieldId) || !Array.isArray(t.fields) || tables.some((existing) => existing.id === t.id)) && fail2("Malformed Airtable table");
572
- let metadata = t.fields.map((value2) => {
573
- let f = object2(value2);
574
- return (typeof f.id != "string" || !/^fld[A-Za-z0-9]+$/.test(f.id) || !text2(f.name) || !text2(f.type)) && fail2("Malformed Airtable field"), { id: f.id, name: f.name, type: f.type, ...f.options === void 0 ? {} : { options: serializable(f.options) } };
575
- });
576
- (!metadata.some((f) => f.id === t.primaryFieldId) || new Set(metadata.map((f) => f.id)).size !== metadata.length) && fail2("Malformed Airtable fields"), tables.push({ id: t.id, name: t.name, primaryFieldId: t.primaryFieldId, fields: metadata });
577
- }
578
- offset = nextOffset(page.offset, seen);
579
- } while (offset);
580
- return tables;
581
- }
582
- (!text2(input.table) || input.table === "." || input.table === "..") && fail2("Invalid Airtable table"), mutation && !tableId(input.table) && fail2("Airtable writes require a stable table ID");
583
- let path = `${baseId}/${encodeURIComponent(input.table)}`;
584
- if (operation2 === "records.get") {
585
- keys2(input, ["table", "id"]), recordId(input.id) || fail2("Invalid Airtable record ID");
586
- let result3 = record(await request(`${path}/${input.id}`));
587
- return result3.id !== input.id && fail2("Malformed Airtable record"), result3;
588
- }
589
- if (operation2 === "records.list") {
590
- keys2(input, ["table", "fields"], ["table"]), input.fields !== void 0 && (!Array.isArray(input.fields) || !input.fields.length || input.fields.some((f) => !text2(f)) || new Set(input.fields).size !== input.fields.length) && fail2("Invalid Airtable field selection");
591
- let records2 = [], ids2 = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set(), offset;
592
- do {
593
- let query2 = new URLSearchParams();
594
- for (let field of input.fields ?? []) query2.append("fields[]", field);
595
- offset && query2.set("offset", offset);
596
- let page = await request(`${path}?${query2}`);
597
- Array.isArray(page.records) || fail2("Malformed Airtable records");
598
- for (let value of page.records) {
599
- let r = record(value);
600
- ids2.has(r.id) && fail2("Malformed Airtable pagination"), ids2.add(r.id), records2.push(r);
601
- }
602
- offset = nextOffset(page.offset, seen);
603
- } while (offset);
604
- return records2;
605
- }
606
- mutation || fail2("Unsupported Airtable operation"), keys2(input, ["table", "records"]), (!Array.isArray(input.records) || !input.records.length || input.records.length > 10) && fail2("Invalid Airtable batch");
607
- let kind = operation2.slice(8), ids = /* @__PURE__ */ new Set(), records = input.records.map((value) => {
608
- let r = object2(value);
609
- if (keys2(r, kind === "create" ? ["fields"] : kind === "update" ? ["id", "expected", "set"] : ["id", "expected"]), kind === "create") return { fields: fields2(r.fields, !0) };
610
- (!recordId(r.id) || ids.has(r.id)) && fail2("Invalid Airtable batch record ID"), ids.add(r.id);
611
- let set = kind === "update" ? fields2(r.set, !0) : void 0;
612
- return set && Object.values(set).some((value2) => value2 === null) && fail2("Airtable guard null cannot be an update value"), { id: r.id, expected: fields2(r.expected), ...set ? { set } : {} };
613
- });
614
- for (let r of records) {
615
- if (!("id" in r)) continue;
616
- let current2 = record(await request(`${path}/${r.id}`));
617
- current2.id !== r.id && fail2("Malformed Airtable record");
618
- for (let [key, value] of Object.entries(r.expected))
619
- (value === null ? Object.hasOwn(current2.fields, key) : !Object.hasOwn(current2.fields, key) || !equal(current2.fields[key], value)) && fail2("Airtable reviewed values are stale");
620
- }
621
- await options.beforeMutation?.();
622
- let query = new URLSearchParams();
623
- if (kind === "delete") for (let id2 of ids) query.append("records[]", id2);
624
- let result2 = await request(`${path}${kind === "delete" ? `?${query}` : ""}`, {
625
- method: kind === "create" ? "POST" : kind === "update" ? "PATCH" : "DELETE",
626
- ...kind === "delete" ? {} : { body: JSON.stringify({ records: records.map((r) => "id" in r ? { id: r.id, fields: r.set } : r) }) }
627
- }, !0), acknowledged = [], returned = [];
628
- try {
629
- if (!Array.isArray(result2.records)) throw new Error();
630
- for (let value of result2.records) {
631
- let r = object2(value);
632
- if (!recordId(r.id) || acknowledged.includes(r.id) || kind !== "create" && !ids.has(r.id) || kind === "delete" && r.deleted !== !0) throw new Error();
633
- acknowledged.push(r.id), kind !== "delete" && returned.push(record(r));
634
- }
635
- if (acknowledged.length !== records.length) throw new Error();
636
- } catch {
637
- throw new AirtableOperationError(
638
- "Incomplete Airtable mutation acknowledgment",
639
- acknowledged.length ? "partial" : "uncertain",
640
- acknowledged.length ? [receipt(acknowledged)] : []
641
- );
642
- }
643
- return { receipt: receipt(acknowledged), ...kind === "delete" ? {} : { records: returned } };
644
- }
645
- function nextOffset(value, seen) {
646
- if (value !== void 0)
647
- return (!text2(value) || seen.has(value)) && fail2("Malformed Airtable pagination"), seen.add(value), value;
648
- }
649
-
650
- var MANAGED_CONNECTION_CAPABILITY_ENV = "ODDINGTON_MANAGED_CONNECTION_CAPABILITY";
651
- function managedConnections(capability) {
652
- let endpoint = new URL(capability.endpoint);
653
- if (endpoint.protocol !== "http:" || endpoint.hostname !== "127.0.0.1" || !endpoint.port || endpoint.pathname !== "/" || endpoint.search || endpoint.hash || endpoint.username || endpoint.password || !/^[0-9a-f-]{36}$/.test(capability.token)) throw new AirtableOperationError("Airtable capability unavailable");
654
- return createConnections(async (name, operation2, input) => {
655
- let safeInput;
656
- try {
657
- safeInput = serializable(input);
658
- } catch {
659
- safeInput = null;
660
- }
661
- try {
662
- let response = await fetch(new URL("airtable", endpoint), {
663
- method: "POST",
664
- redirect: "error",
665
- headers: { authorization: `Bearer ${capability.token}`, "content-type": "application/json" },
666
- body: JSON.stringify({ name, operation: operation2, input: safeInput }),
667
- signal: AbortSignal.timeout(125e3)
668
- }), value = await response.json();
669
- if (!response.ok) throw new AirtableOperationError(
670
- "Airtable operation failed; the execution retains its evidence",
671
- value.effect === "partial" || value.effect === "uncertain" ? value.effect : "unapplied",
672
- value.receipts ?? []
673
- );
674
- return value;
675
- } catch (error) {
676
- throw error instanceof AirtableOperationError ? error : new AirtableOperationError(
677
- "Airtable parent acknowledgment unavailable",
678
- ["records.create", "records.update", "records.delete"].includes(operation2) ? "uncertain" : "unapplied"
679
- );
680
- }
681
- });
682
697
  }
683
698
 
684
- var connections = /* @__PURE__ */ createConnections(async (name, operation2, input) => {
685
- try {
686
- let managed = process.env[MANAGED_CONNECTION_CAPABILITY_ENV];
687
- if (managed) {
688
- let client = managedConnections(JSON.parse(managed)).airtable(name);
689
- return operation2 === "tables.list" ? await client.tables.list() : await client.records[operation2.slice(8)](input);
690
- }
691
- let raw = JSON.parse(process.env[ROUTINE_CONNECTION_CREDENTIALS_ENV] ?? "[]");
692
- if (!Array.isArray(raw)) throw new Error();
693
- let leases = raw.map((value) => parseConnectionLease(value));
694
- if (leases.some((lease2) => lease2.provider !== "airtable") || new Set(leases.map((lease2) => lease2.name)).size !== leases.length) throw new Error();
695
- let lease = leases.find((lease2) => lease2.name === name);
696
- if (!lease || lease.provider !== "airtable") throw new Error();
697
- return await executeAirtableOperation(lease, operation2, input);
698
- } catch (error) {
699
- throw error instanceof AirtableOperationError ? error : new AirtableOperationError("Airtable connection unavailable");
700
- }
701
- });
702
-
703
699
  var DataOperationError = class extends Error {
704
700
  constructor(code, retryable = !1, effect, component) {
705
701
  super(`Data operation failed: ${code}`);
@@ -715,26 +711,26 @@ var DataOperationError = class extends Error {
715
711
  component;
716
712
  };
717
713
 
718
- var invalid = () => {
714
+ var invalid2 = () => {
719
715
  throw new DataOperationError("invalid_query");
720
716
  }, historyText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
721
717
  function historyVersion(value) {
722
718
  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);
723
719
  }
724
720
  function historyProperties(value) {
725
- if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return invalid();
721
+ if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return invalid2();
726
722
  let descriptors = Object.getOwnPropertyDescriptors(value);
727
- return Reflect.ownKeys(value).some((key) => typeof key != "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")) ? invalid() : descriptors;
723
+ return Reflect.ownKeys(value).some((key) => typeof key != "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")) ? invalid2() : descriptors;
728
724
  }
729
725
  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);
730
726
  function historyArray(value) {
731
- if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return invalid();
727
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return invalid2();
732
728
  let descriptors = Object.getOwnPropertyDescriptors(value);
733
- if (Reflect.ownKeys(value).length !== value.length + 1) return invalid();
729
+ if (Reflect.ownKeys(value).length !== value.length + 1) return invalid2();
734
730
  let result2 = [];
735
731
  for (let i = 0; i < value.length; i++) {
736
732
  let descriptor2 = descriptors[i];
737
- if (!descriptor2?.enumerable || !Object.hasOwn(descriptor2, "value")) return invalid();
733
+ if (!descriptor2?.enumerable || !Object.hasOwn(descriptor2, "value")) return invalid2();
738
734
  result2.push(descriptor2.value);
739
735
  }
740
736
  return result2;
@@ -742,19 +738,19 @@ function historyArray(value) {
742
738
  function captureOptions(value, changes) {
743
739
  if (value === void 0) return {};
744
740
  let descriptors = historyProperties(value), result2 = {}, allowed = changes ? ["collections", "refs", "from", "through", "limit", "after"] : ["limit", "before"];
745
- if (Object.keys(descriptors).some((key) => !allowed.includes(key))) return invalid();
741
+ if (Object.keys(descriptors).some((key) => !allowed.includes(key))) return invalid2();
746
742
  for (let key of allowed) {
747
743
  if (!Object.hasOwn(descriptors, key)) continue;
748
744
  let scalar = descriptors[key].value;
749
745
  if (key === "collections" || key === "refs") {
750
746
  let values = historyArray(scalar);
751
- if (!values.length || values.length > (key === "collections" ? 16 : 100) || !values.every(key === "collections" ? historyCollection : validRecordRef) || new Set(values).size !== values.length) return invalid();
747
+ if (!values.length || values.length > (key === "collections" ? 16 : 100) || !values.every(key === "collections" ? historyCollection : validRecordRef) || new Set(values).size !== values.length) return invalid2();
752
748
  result2[key] = values;
753
749
  } else if (key === "limit") {
754
- if (!Number.isInteger(scalar) || scalar < 1 || scalar > (changes ? 500 : 100)) return invalid();
750
+ if (!Number.isInteger(scalar) || scalar < 1 || scalar > (changes ? 500 : 100)) return invalid2();
755
751
  result2.limit = scalar;
756
752
  } else {
757
- if (!(key === "after" ? historyCursor(scalar) : historyVersion(scalar))) return invalid();
753
+ if (!(key === "after" ? historyCursor(scalar) : historyVersion(scalar))) return invalid2();
758
754
  result2[key] = scalar;
759
755
  }
760
756
  }
@@ -762,39 +758,39 @@ function captureOptions(value, changes) {
762
758
  }
763
759
  var captureHistoryListOptions = (value) => captureOptions(value, !1), captureHistoryChangesOptions = (value) => captureOptions(value, !0);
764
760
  function captureHistoryInstant(value) {
765
- if (!historyText(value) || value.length > 1024) return invalid();
761
+ if (!historyText(value) || value.length > 1024) return invalid2();
766
762
  let match = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?([Zz]|([+-])(\d{2}):(\d{2}))$/.exec(value);
767
- if (!match) return invalid();
763
+ if (!match) return invalid2();
768
764
  let [year, month, day, hour, minute, second] = match.slice(1, 7).map(Number), days = new Date(Date.UTC(year, month, 0));
769
- 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 ? invalid() : value;
765
+ 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 ? invalid2() : value;
770
766
  }
771
767
 
772
- var invalid2 = () => {
768
+ var invalid3 = () => {
773
769
  throw new DataOperationError("invalid_query");
774
770
  };
775
771
  function captureRecordsSearchInput(query, options) {
776
- if (!historyText(query)) return invalid2();
772
+ if (!historyText(query)) return invalid3();
777
773
  let length = [...query.trim()].length;
778
- if (length < 1 || length > 256) return invalid2();
774
+ if (length < 1 || length > 256) return invalid3();
779
775
  if (options === void 0) return { query };
780
776
  let descriptors = historyProperties(options);
781
- if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key))) return invalid2();
777
+ if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key))) return invalid3();
782
778
  let captured = {};
783
779
  if (Object.hasOwn(descriptors, "collections")) {
784
780
  let supplied = descriptors.collections.value;
785
- if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return invalid2();
781
+ if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return invalid3();
786
782
  let collections = [];
787
783
  for (let index = 0; index < supplied.length; index++) {
788
784
  let descriptor2 = Object.getOwnPropertyDescriptor(supplied, String(index));
789
- if (!descriptor2?.enumerable || !Object.hasOwn(descriptor2, "value") || !historyText(descriptor2.value)) return invalid2();
785
+ if (!descriptor2?.enumerable || !Object.hasOwn(descriptor2, "value") || !historyText(descriptor2.value)) return invalid3();
790
786
  collections.push(descriptor2.value);
791
787
  }
792
- if (new Set(collections).size !== collections.length) return invalid2();
788
+ if (new Set(collections).size !== collections.length) return invalid3();
793
789
  captured.collections = collections;
794
790
  }
795
791
  if (Object.hasOwn(descriptors, "limit")) {
796
792
  let supplied = descriptors.limit.value;
797
- if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return invalid2();
793
+ if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return invalid3();
798
794
  captured.limit = supplied;
799
795
  }
800
796
  return { query, options: captured };
@@ -820,13 +816,13 @@ function captureValue(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
820
816
  ancestors.delete(value);
821
817
  }
822
818
  }
823
- function captureDataDelete(record2) {
824
- let identity = mapping(record2);
819
+ function captureDataDelete(record3) {
820
+ let identity = mapping(record3);
825
821
  return !validRecordRef(identity.$ref) || typeof identity.$version != "string" || !identity.$version.length || identity.$version.length > 512 ? invalidChange() : { ref: identity.$ref, expectedVersion: identity.$version };
826
822
  }
827
- function captureDataUpdate(record2, set) {
828
- let identity = captureDataDelete(record2), fields3 = mapping(set);
829
- return !Object.keys(fields3).length || Object.keys(fields3).some((key) => key.startsWith("$") || ["id", "type"].includes(key)) ? invalidChange() : { ...identity, set: captureValue(fields3) };
823
+ function captureDataUpdate(record3, set) {
824
+ let identity = captureDataDelete(record3), fields4 = mapping(set);
825
+ return !Object.keys(fields4).length || Object.keys(fields4).some((key) => key.startsWith("$") || ["id", "type"].includes(key)) ? invalidChange() : { ...identity, set: captureValue(fields4) };
830
826
  }
831
827
  function captureIdentities(value, update, allowEmpty = !0) {
832
828
  if (!Array.isArray(value) || !allowEmpty && !value.length || value.length > 1e4) return invalidChange();
@@ -845,14 +841,14 @@ function captureDataCreate(value) {
845
841
  let row = mapping(value);
846
842
  if (!validRecordRef(row.$ref) || Object.keys(row).some((key) => key.startsWith("$") && !["$ref", "$filing"].includes(key)))
847
843
  return invalidChange();
848
- let { $ref: ref, $filing, ...fields3 } = row, filing;
844
+ let { $ref: ref, $filing, ...fields4 } = row, filing;
849
845
  if ($filing !== void 0) {
850
846
  let components = mapping($filing);
851
847
  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)))
852
848
  return invalidChange();
853
849
  filing = { ...components };
854
850
  }
855
- return { ref, fields: captureValue(fields3), ...filing ? { filing } : {} };
851
+ return { ref, fields: captureValue(fields4), ...filing ? { filing } : {} };
856
852
  }
857
853
  function captureDataChanges(updatesValue, createsValue = [], deletesValue = []) {
858
854
  let updates = captureDataUpdates(updatesValue, !0);
@@ -860,8 +856,8 @@ function captureDataChanges(updatesValue, createsValue = [], deletesValue = [])
860
856
  let creates = createsValue.map((item) => {
861
857
  let row = mapping(item);
862
858
  if (Object.keys(row).some((key) => !["ref", "fields", "filing"].includes(key)) || !Object.hasOwn(row, "ref") || !Object.hasOwn(row, "fields")) return invalidChange();
863
- let fields3 = mapping(row.fields);
864
- return Object.keys(fields3).some((key) => key.startsWith("$")) ? invalidChange() : captureDataCreate({ ...fields3, $ref: row.ref, ...Object.hasOwn(row, "filing") ? { $filing: row.filing } : {} });
859
+ let fields4 = mapping(row.fields);
860
+ return Object.keys(fields4).some((key) => key.startsWith("$")) ? invalidChange() : captureDataCreate({ ...fields4, $ref: row.ref, ...Object.hasOwn(row, "filing") ? { $filing: row.filing } : {} });
865
861
  }), deletes = captureIdentities(deletesValue, !1), refs = [...updates, ...creates, ...deletes].map((item) => item.ref);
866
862
  return !refs.length || refs.length > 1e4 || new Set(refs).size !== refs.length ? invalidChange() : { updates, creates, deletes };
867
863
  }
@@ -887,96 +883,9 @@ function dataTransportError(status, value) {
887
883
  );
888
884
  }
889
885
 
890
- var FileOperationError = class extends Error {
891
- constructor(code, status, retryable = !1) {
892
- super(code);
893
- this.code = code;
894
- this.status = status;
895
- this.retryable = retryable;
896
- }
897
- code;
898
- status;
899
- retryable;
900
- }, 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;
901
- function parseFileDescriptor(value) {
902
- let invalid4 = () => {
903
- throw new FileOperationError("unavailable", 503, !0);
904
- };
905
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
906
- let f = value;
907
- 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 invalid4();
908
- let d = f.details;
909
- if (d.kind === "other") {
910
- if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid4();
911
- } else if (d.kind === "csv") {
912
- 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 invalid4();
913
- } else return invalid4();
914
- for (let [name, descriptor2] of Object.entries(f.enrichments)) {
915
- if (!safeEnrichmentName(name)) return invalid4();
916
- parseEnrichmentDescriptor(descriptor2);
917
- }
918
- return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid4() : f;
919
- }
920
- function parseEnrichmentDescriptor(value) {
921
- let invalid4 = () => {
922
- throw new FileOperationError("unavailable", 503, !0);
923
- };
924
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
925
- let d = value;
926
- 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) ? invalid4() : d;
927
- }
928
- function safeEnrichmentName(value) {
929
- return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
930
- }
931
- function parseFileEnrichMetadata(value, maxBytes) {
932
- let invalid4 = () => {
933
- throw new FileOperationError("invalid_input", 400);
934
- };
935
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
936
- let d = value;
937
- 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 invalid4();
938
- if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
939
- return d;
940
- }
941
- function safeFileName(value) {
942
- return typeof value == "string" && value.length > 0 && value.length <= 255 && value === value.trim() && value !== "." && value !== ".." && !/[\u0000-\u001f\u007f-\u009f/\\:*?"<>|]/u.test(value) && !/[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/.test(value) && !/[. ]$/.test(value) && !/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(value);
943
- }
944
- function safeFilePath(value) {
945
- return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
946
- }
947
- function parseFileCreateMetadata(value, maxBytes) {
948
- let invalid4 = () => {
949
- throw new FileOperationError("invalid_input", 400);
950
- };
951
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
952
- let input = value;
953
- if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "size", "requestKey"].includes(key))) return invalid4();
954
- let path = input.path === void 0 ? "Files" : input.path;
955
- if (!safeFileName(input.name) || !safeFilePath(path) || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || !Number.isSafeInteger(input.size) || input.size < 0) return invalid4();
956
- if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
957
- 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 invalid4();
958
- let csv;
959
- if (input.csv !== void 0) {
960
- if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid4();
961
- let hints = input.csv;
962
- if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid4();
963
- 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;
964
- if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid4();
965
- csv = { encoding, delimiter, headerRow };
966
- }
967
- return {
968
- name: input.name,
969
- path,
970
- ...input.storage ? { storage: input.storage } : {},
971
- ...csv ? { csv } : {},
972
- size: input.size,
973
- requestKey: input.requestKey
974
- };
975
- }
976
-
977
- var DEFAULT_ORIGIN = "https://auth.oddington.ai";
886
+ var AUTH_ORIGIN = "https://auth.oddington.ai";
978
887
  function oddingtonOrigin(environment = process.env) {
979
- let value = environment.ODDINGTON_OS_ORIGIN ?? DEFAULT_ORIGIN, url = new URL(value);
888
+ let value = environment.ODDINGTON_OS_ORIGIN ?? AUTH_ORIGIN, url = new URL(value);
980
889
  if (url.protocol !== "https:" && url.hostname !== "127.0.0.1")
981
890
  throw new Error("ODDINGTON_OS_ORIGIN must use HTTPS");
982
891
  return url.origin;
@@ -992,9 +901,7 @@ async function resolveAppContext() {
992
901
  let host = memberContext;
993
902
  if (!host) throw new Error("App context unavailable.");
994
903
  let context2 = await host();
995
- if (host !== memberContext || !context2.isCurrent() || context2.expiresAt <= Date.now())
996
- throw new Error("App context unavailable.");
997
- if (context2.kind !== "local" && (typeof context2.accessToken != "string" || !/^[^\s]{1,8192}$/.test(context2.accessToken)))
904
+ if (host !== memberContext || !context2.isCurrent() || context2.expiresAt <= Date.now() || context2.kind !== "local" && (typeof context2.accessToken != "string" || !/^[^\s]{1,8192}$/.test(context2.accessToken)))
998
905
  throw new Error("App context unavailable.");
999
906
  return context2;
1000
907
  }
@@ -1092,19 +999,19 @@ var data = {
1092
999
  }), input;
1093
1000
  };
1094
1001
  return {
1095
- create(record2) {
1002
+ create(record3) {
1096
1003
  assertMutable();
1097
- let next = [...creates, captureDataCreate(record2)];
1004
+ let next = [...creates, captureDataCreate(record3)];
1098
1005
  snapshot(updates, next, deletes), creates = next;
1099
1006
  },
1100
- update(record2, set) {
1007
+ update(record3, set) {
1101
1008
  assertMutable();
1102
- let next = [...updates, captureDataUpdate(record2, set)];
1009
+ let next = [...updates, captureDataUpdate(record3, set)];
1103
1010
  snapshot(next, creates, deletes), updates = next;
1104
1011
  },
1105
- delete(record2) {
1012
+ delete(record3) {
1106
1013
  assertMutable();
1107
- let next = [...deletes, captureDataDelete(record2)];
1014
+ let next = [...deletes, captureDataDelete(record3)];
1108
1015
  snapshot(updates, creates, next), deletes = next;
1109
1016
  },
1110
1017
  async validate() {
@@ -1138,7 +1045,7 @@ var data = {
1138
1045
  }
1139
1046
  };
1140
1047
 
1141
- 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, invalid3 = () => new FileOperationError("invalid_input", 400), unavailable = () => new FileOperationError("unavailable", 503, !0), failures = {
1048
+ 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, invalid4 = () => new FileOperationError("invalid_input", 400), unavailable = () => new FileOperationError("unavailable", 503, !0), failures = {
1142
1049
  400: ["invalid_input", "unsupported_context"],
1143
1050
  401: ["unauthenticated"],
1144
1051
  403: ["access_denied"],
@@ -1155,7 +1062,7 @@ async function boundedBytes(stream, limit) {
1155
1062
  for (; ; ) {
1156
1063
  let { done, value } = await reader.read();
1157
1064
  if (done) break;
1158
- if (!(value instanceof Uint8Array)) throw invalid3();
1065
+ if (!(value instanceof Uint8Array)) throw invalid4();
1159
1066
  if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
1160
1067
  bytes.set(value, size - value.byteLength);
1161
1068
  }
@@ -1229,52 +1136,51 @@ async function hostedContent(url, init2, parent, upstream = fetch) {
1229
1136
  }
1230
1137
  }
1231
1138
  async function send(suffix, init2, descriptor2, initial, parent) {
1232
- let original = initial, checkCurrent = () => {
1139
+ let original = initial, checkCurrent = (context2 = original) => {
1233
1140
  if (parent?.aborted) throw unavailable();
1234
- if (!original.isCurrent()) throw new FileOperationError("unsupported_context", 400);
1141
+ if (!original.isCurrent() || context2.url !== original.url) throw new FileOperationError("unsupported_context", 400);
1235
1142
  };
1236
1143
  for (let attempt = 0; attempt < ATTEMPTS; attempt++) {
1237
1144
  checkCurrent();
1238
1145
  let context2 = await resolveFilesContext();
1239
- if (checkCurrent(), context2.url !== original.url) throw new FileOperationError("unsupported_context", 400);
1146
+ checkCurrent(context2);
1240
1147
  try {
1241
- return await (async () => {
1242
- let response = context2.localFiles ? await context2.localFiles(suffix, init2, parent) : await (async () => {
1243
- let url = `${context2.url}${suffix}`, request = {
1244
- ...init2,
1245
- signal: parent,
1246
- headers: { ...context2.headers, ...init2.headers },
1247
- redirect: "error",
1248
- cache: "no-store"
1249
- };
1250
- return descriptor2 ? fetch(url, request) : hostedContent(url, request, parent);
1251
- })();
1252
- if (!response.ok) {
1253
- let value2 = await result(response), error = value2 && typeof value2 == "object" && "error" in value2 ? value2.error : void 0, received = error && typeof error == "object" && "code" in error ? error.code : void 0, code = failures[response.status]?.find((code2) => code2 === received);
1254
- throw code ? new FileOperationError(code, response.status, code === "capacity" || code === "unavailable") : unavailable();
1255
- }
1256
- if (response.status !== 200)
1257
- throw response.body?.cancel().catch(() => {
1258
- }), unavailable();
1259
- try {
1260
- checkCurrent();
1261
- } catch (error) {
1262
- throw response.body?.cancel().catch(() => {
1263
- }), error;
1264
- }
1265
- if (!descriptor2) return response;
1266
- let value = await result(response, descriptor2 === "control" ? CONTROL_RESULT_BYTES : RESULT_BYTES);
1267
- if (descriptor2 === "control")
1268
- return checkCurrent(), value;
1269
- let parsed;
1270
- if (descriptor2 === "enrichment") {
1271
- if (!value || typeof value != "object" || Array.isArray(value)) throw unavailable();
1272
- let { name, ...metadata } = value;
1273
- if (!safeEnrichmentName(name)) throw unavailable();
1274
- parsed = { name, ...parseEnrichmentDescriptor(metadata) };
1275
- } else parsed = parseFileDescriptor(value);
1276
- return checkCurrent(), parsed;
1148
+ let response = await (async () => {
1149
+ let url = `${context2.url}${suffix}`, request = {
1150
+ ...init2,
1151
+ signal: parent,
1152
+ headers: { ...context2.headers, ...init2.headers },
1153
+ redirect: "error",
1154
+ cache: "no-store"
1155
+ };
1156
+ return descriptor2 ? fetch(url, request) : hostedContent(url, request, parent);
1277
1157
  })();
1158
+ if (!response.ok) {
1159
+ let value2 = await result(response), error = value2 && typeof value2 == "object" && "error" in value2 ? value2.error : void 0, received = error && typeof error == "object" && "code" in error ? error.code : void 0, code = failures[response.status]?.find((code2) => code2 === received);
1160
+ throw code ? new FileOperationError(code, response.status, code === "capacity" || code === "unavailable") : unavailable();
1161
+ }
1162
+ if (response.status !== (descriptor2 === 204 ? 204 : 200) || descriptor2 === 204 && response.body !== null)
1163
+ throw response.body?.cancel().catch(() => {
1164
+ }), unavailable();
1165
+ try {
1166
+ checkCurrent();
1167
+ } catch (error) {
1168
+ throw response.body?.cancel().catch(() => {
1169
+ }), error;
1170
+ }
1171
+ if (descriptor2 === 204) return;
1172
+ if (!descriptor2) return response;
1173
+ let value = await result(response, descriptor2 === "control" ? CONTROL_RESULT_BYTES : RESULT_BYTES);
1174
+ if (descriptor2 === "control")
1175
+ return checkCurrent(), value;
1176
+ let parsed;
1177
+ if (descriptor2 === "enrichment") {
1178
+ if (!value || typeof value != "object" || Array.isArray(value)) throw unavailable();
1179
+ let { name, ...metadata } = value;
1180
+ if (!safeEnrichmentName(name)) throw unavailable();
1181
+ parsed = { name, ...parseEnrichmentDescriptor(metadata) };
1182
+ } else parsed = parseFileDescriptor(value);
1183
+ return checkCurrent(), parsed;
1278
1184
  } catch (error) {
1279
1185
  let failure = error instanceof FileOperationError ? error : unavailable();
1280
1186
  if (init2.body instanceof ReadableStream || !failure.retryable || attempt + 1 === ATTEMPTS) throw failure;
@@ -1283,7 +1189,7 @@ async function send(suffix, init2, descriptor2, initial, parent) {
1283
1189
  throw unavailable();
1284
1190
  }
1285
1191
  function idPath(id2) {
1286
- if (typeof id2 != "string" || !FILE_ID_PATTERN.test(id2)) throw invalid3();
1192
+ if (typeof id2 != "string" || !FILE_ID_PATTERN.test(id2)) throw invalid4();
1287
1193
  return `/${id2}`;
1288
1194
  }
1289
1195
  async function multipartCreate(input, metadata, exchange, release = () => {
@@ -1326,18 +1232,18 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1326
1232
  if (!chunk || offset === chunk.byteLength) {
1327
1233
  chunk = void 0, offset = 0;
1328
1234
  let value2 = await next();
1329
- if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid3();
1235
+ if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid4();
1330
1236
  }
1331
1237
  let take = Math.min(length - filled, chunk.byteLength - offset);
1332
1238
  part.set(chunk.subarray(offset, offset + take), filled), filled += take, offset += take, offset === chunk.byteLength && (chunk = void 0, offset = 0);
1333
1239
  }
1334
1240
  }
1335
- if (part.byteLength !== length) throw invalid3();
1241
+ if (part.byteLength !== length) throw invalid4();
1336
1242
  if (reader && sent + length === metadata.size)
1337
1243
  for (lastProgress = Date.now(); ; ) {
1338
1244
  let value2 = await next();
1339
1245
  if (value2.done) break;
1340
- if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid3();
1246
+ if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid4();
1341
1247
  }
1342
1248
  let value = await request((signal) => exchange(`${route}/part`, {
1343
1249
  method: "POST",
@@ -1351,7 +1257,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1351
1257
  }
1352
1258
  if (upload) for (let name of Object.keys(upload.file.enrichments)) {
1353
1259
  let bytes = await request(() => upload.enrichment(name));
1354
- if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid3();
1260
+ if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid4();
1355
1261
  await request((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
1356
1262
  method: "POST",
1357
1263
  headers: { "content-type": "application/octet-stream", "x-oddington-transfer": ticket },
@@ -1373,166 +1279,504 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1373
1279
  chunk = void 0, reader?.releaseLock(), pending.size ? Promise.allSettled([...pending]).then(release) : release();
1374
1280
  }
1375
1281
  }
1376
- async function operation(work, initial, parent) {
1377
- let context2 = initial ?? await resolveFilesContext();
1378
- if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1379
- if (active++, context2.localFiles)
1380
- try {
1381
- return await work(context2, parent ?? new AbortController().signal);
1382
- } finally {
1383
- active--;
1384
- }
1385
- return timed(async (signal) => {
1386
- try {
1387
- return await work(context2, signal);
1388
- } finally {
1389
- active--;
1390
- }
1391
- }, parent).catch((error) => {
1392
- throw error instanceof FileOperationError ? error : unavailable();
1393
- });
1282
+ async function operation(work, initial, parent) {
1283
+ let context2 = initial ?? await resolveFilesContext();
1284
+ if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1285
+ return active++, timed(async (signal) => {
1286
+ try {
1287
+ return await work(context2, signal);
1288
+ } finally {
1289
+ active--;
1290
+ }
1291
+ }, parent).catch((error) => {
1292
+ throw error instanceof FileOperationError ? error : unavailable();
1293
+ });
1294
+ }
1295
+ function contentPath(id2, name) {
1296
+ let path = idPath(id2);
1297
+ if (name === void 0) return `${path}/content`;
1298
+ if (!safeEnrichmentName(name)) throw invalid4();
1299
+ return `${path}/enrichments/${encodeURIComponent(name)}/content`;
1300
+ }
1301
+ async function read(id2, names) {
1302
+ let context2 = await resolveFilesContext();
1303
+ if (idPath(id2), names === void 0 || typeof names == "string") {
1304
+ let path = contentPath(id2, names);
1305
+ return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
1306
+ }
1307
+ if (!Array.isArray(names)) throw invalid4();
1308
+ let distinct = [], seen = /* @__PURE__ */ new Set();
1309
+ for (let name of names) {
1310
+ if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid4();
1311
+ if (!seen.has(name)) {
1312
+ if (seen.size === 16) throw invalid4();
1313
+ seen.add(name), distinct.push(name);
1314
+ }
1315
+ }
1316
+ let paths = distinct.map((name) => contentPath(id2, name));
1317
+ return timed(async (parent) => {
1318
+ let responses = {};
1319
+ try {
1320
+ for (let i = 0; i < paths.length; i++) {
1321
+ let response = await operation((context3, signal) => send(paths[i], { method: "GET" }, !1, context3, signal), context2, parent);
1322
+ Object.defineProperty(responses, distinct[i], { value: response, enumerable: !0 });
1323
+ }
1324
+ if (!context2.isCurrent()) throw new FileOperationError("unsupported_context", 400);
1325
+ return responses;
1326
+ } catch (error) {
1327
+ for (let response of Object.values(responses)) response.body?.cancel().catch(() => {
1328
+ });
1329
+ throw error;
1330
+ }
1331
+ });
1332
+ }
1333
+ var files = {
1334
+ delete(id2) {
1335
+ return operation((context2, signal) => send(idPath(id2), { method: "DELETE" }, 204, context2, signal));
1336
+ },
1337
+ async upload(id2) {
1338
+ return operation(async (context2, signal) => {
1339
+ let file2 = await send(`${idPath(id2)}/upload`, { method: "POST" }, !0, context2, signal);
1340
+ if (file2.id !== id2) throw unavailable();
1341
+ return file2;
1342
+ });
1343
+ },
1344
+ async create(input, options) {
1345
+ let context2 = await resolveFilesContext();
1346
+ 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")))
1347
+ throw invalid4();
1348
+ let blob = input.file instanceof Blob, array2 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
1349
+ if (!blob && !array2 && !stream) throw invalid4();
1350
+ let intrinsic = blob ? input.file.size : array2 ? input.file.byteLength : void 0;
1351
+ if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid4();
1352
+ let name = input.name;
1353
+ 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));
1354
+ let metadata = parseFileCreateMetadata({
1355
+ name,
1356
+ size: intrinsic ?? input.size,
1357
+ path: input.path,
1358
+ storage: input.storage,
1359
+ csv: input.csv,
1360
+ ...blob && input.file.type === "application/pdf" ? { inputMediaType: "application/pdf" } : {},
1361
+ requestKey: options?.requestKey === void 0 ? crypto.randomUUID() : options.requestKey
1362
+ }, FILE_ORIGINAL_MAX_BYTES);
1363
+ if (!context2.local && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
1364
+ let header = encodeURIComponent(JSON.stringify(metadata));
1365
+ if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid4();
1366
+ if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1367
+ 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) => {
1368
+ try {
1369
+ let bytes = array2 ? input.file.slice() : await boundedBytes(
1370
+ blob ? input.file.stream() : input.file,
1371
+ metadata.size
1372
+ );
1373
+ if (bytes.byteLength !== metadata.size) throw invalid4();
1374
+ if (signal.aborted) throw unavailable();
1375
+ return await send("", {
1376
+ method: "POST",
1377
+ headers: { "content-type": "application/octet-stream", "x-oddington-file": header },
1378
+ body: bytes.buffer
1379
+ }, !0, context2, signal);
1380
+ } finally {
1381
+ active--;
1382
+ }
1383
+ }).catch((error) => {
1384
+ throw error instanceof FileOperationError ? error : unavailable();
1385
+ });
1386
+ },
1387
+ async enrich(input) {
1388
+ let context2 = await resolveFilesContext();
1389
+ 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 invalid4();
1390
+ let path = `${idPath(input.file)}/enrichments`;
1391
+ if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
1392
+ throw new FileOperationError("request_too_large", 413);
1393
+ return operation(async (context3, signal) => {
1394
+ let bytes;
1395
+ if (typeof input.content == "string") {
1396
+ let buffer = new Uint8Array(Math.min(MAX_BYTES, input.content.length * 3)), encoded = new TextEncoder().encodeInto(input.content, buffer);
1397
+ if (encoded.read !== input.content.length) throw new FileOperationError("request_too_large", 413);
1398
+ bytes = buffer.slice(0, encoded.written);
1399
+ } else bytes = input.content.slice();
1400
+ let metadata = parseFileEnrichMetadata({
1401
+ name: input.name,
1402
+ size: bytes.byteLength,
1403
+ ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
1404
+ ...input.replace === void 0 ? {} : { replace: input.replace }
1405
+ }, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
1406
+ if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid4();
1407
+ let result2 = await send(path, { method: "POST", headers: {
1408
+ "content-type": "application/octet-stream",
1409
+ "x-oddington-enrichment": header
1410
+ }, body: bytes.buffer }, "enrichment", context3, signal);
1411
+ if (result2.name !== metadata.name) throw unavailable();
1412
+ return result2;
1413
+ }, context2);
1414
+ },
1415
+ async get(id2) {
1416
+ return operation((context2, signal) => send(idPath(id2), { method: "GET" }, !0, context2, signal));
1417
+ },
1418
+ read
1419
+ };
1420
+
1421
+ function validGoogleScopes(value) {
1422
+ 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;
1423
+ }
1424
+
1425
+ var ROUTINE_CONNECTION_CREDENTIALS_ENV = "ODDINGTON_ROUTINE_CONNECTION_CREDENTIALS";
1426
+ 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);
1427
+ function parseConnectionLease(raw, now = Date.now()) {
1428
+ let v = raw;
1429
+ 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))
1430
+ throw new Error("Invalid connection credential");
1431
+ if (v.provider === "gmail") {
1432
+ if (Object.keys(v).sort().join(",") !== "accessToken,accountEmail,connectionId,expiresAt,name,provider,runId,scopes" || typeof v.accountEmail != "string" || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.accountEmail) || !validGoogleScopes(v.scopes) || typeof v.expiresAt != "string" || !Number.isFinite(Date.parse(v.expiresAt)) || Date.parse(v.expiresAt) <= now + 6e4 || Date.parse(v.expiresAt) > now + 36e5)
1433
+ throw new Error("Invalid connection credential");
1434
+ return v;
1435
+ }
1436
+ if (v.provider === "airtable" && Object.keys(v).sort().join(",") === "accessToken,baseId,connectionId,name,provider,runExpiresAt,runId" && typeof v.baseId == "string" && /^app[A-Za-z0-9]+$/.test(v.baseId) && typeof v.runExpiresAt == "string" && Number.isFinite(Date.parse(v.runExpiresAt)) && Date.parse(v.runExpiresAt) > now + 6e4 && Date.parse(v.runExpiresAt) <= now + 15 * 6e4)
1437
+ return v;
1438
+ throw new Error("Invalid connection credential");
1439
+ }
1440
+
1441
+ var AirtableOperationError = class extends Error {
1442
+ constructor(message, effect = "unapplied", receipts = []) {
1443
+ super(message);
1444
+ this.effect = effect;
1445
+ this.receipts = receipts;
1446
+ this.name = "AirtableOperationError";
1447
+ }
1448
+ effect;
1449
+ receipts;
1450
+ };
1451
+
1452
+ var recordId = (v) => typeof v == "string" && /^rec[A-Za-z0-9]+$/.test(v), tableId = (v) => typeof v == "string" && /^tbl[A-Za-z0-9]+$/.test(v);
1453
+ function fail2(message) {
1454
+ throw new AirtableOperationError(message);
1455
+ }
1456
+ function object2(v) {
1457
+ return (!v || typeof v != "object" || Array.isArray(v) || ![null, Object.prototype].includes(Object.getPrototypeOf(v))) && fail2("Invalid Airtable data"), v;
1458
+ }
1459
+ function keys2(v, allowed, required = allowed) {
1460
+ (Object.keys(v).some((k) => !allowed.includes(k)) || required.some((k) => !Object.hasOwn(v, k))) && fail2("Invalid Airtable input");
1461
+ }
1462
+ function text2(v) {
1463
+ return typeof v == "string" && v.length > 0 && v.length <= 1024;
1464
+ }
1465
+ function fields3(v, nonempty = !1) {
1466
+ let result2 = object2(v);
1467
+ (nonempty && !Object.keys(result2).length || Object.keys(result2).some((k) => !text2(k))) && fail2("Invalid Airtable fields");
1468
+ try {
1469
+ return serializable(result2);
1470
+ } catch {
1471
+ return fail2("Invalid Airtable fields");
1472
+ }
1473
+ }
1474
+ function record2(v) {
1475
+ let r = object2(v);
1476
+ 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) };
1477
+ }
1478
+ function equal(a, b) {
1479
+ if (a === b) return !0;
1480
+ if (!a || !b || typeof a != "object" || typeof b != "object" || Array.isArray(a) !== Array.isArray(b)) return !1;
1481
+ let left = Object.keys(a), right = Object.keys(b);
1482
+ return left.length === right.length && left.every((k) => Object.hasOwn(b, k) && equal(
1483
+ a[k],
1484
+ b[k]
1485
+ ));
1486
+ }
1487
+ function createConnections(transport) {
1488
+ return { airtable(name) {
1489
+ (typeof name != "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(name)) && fail2("Invalid Airtable connection name");
1490
+ let call = (operation2, input) => transport(name, operation2, input);
1491
+ return {
1492
+ tables: { list: async () => await call("tables.list", {}) },
1493
+ records: {
1494
+ list: async (input) => await call("records.list", input),
1495
+ get: async (input) => await call("records.get", input),
1496
+ create: async (input) => await call("records.create", input),
1497
+ update: async (input) => await call("records.update", input),
1498
+ delete: async (input) => await call("records.delete", input)
1499
+ }
1500
+ };
1501
+ } };
1502
+ }
1503
+ async function executeAirtableOperation(authority, operation2, raw, options = {}) {
1504
+ let { name, baseId, accessToken } = authority;
1505
+ (!/^[a-z0-9][a-z0-9-]{0,62}$/.test(name) || !/^app[A-Za-z0-9]+$/.test(baseId) || !/^[A-Za-z0-9._~+/-]{1,8192}={0,2}$/.test(accessToken)) && fail2("Airtable connection unavailable");
1506
+ let input;
1507
+ try {
1508
+ input = object2(serializable(raw));
1509
+ } catch {
1510
+ return fail2("Invalid Airtable input");
1511
+ }
1512
+ let mutation = ["records.create", "records.update", "records.delete"].includes(operation2), receipt = (ids2) => ({
1513
+ provider: "airtable",
1514
+ connection: `airtable/${name}`,
1515
+ baseId,
1516
+ table: input.table,
1517
+ operation: operation2.slice(8),
1518
+ records: ids2.map((id2) => ({ id: id2 }))
1519
+ });
1520
+ async function request(path2, init2 = {}, write = !1) {
1521
+ let response;
1522
+ try {
1523
+ response = await (options.fetch ?? fetch)(`https://api.airtable.com/v0/${path2}`, {
1524
+ ...init2,
1525
+ headers: { authorization: `Bearer ${accessToken}`, "content-type": "application/json" },
1526
+ redirect: "manual",
1527
+ signal: options.signal ? AbortSignal.any([options.signal, AbortSignal.timeout(15e3)]) : AbortSignal.timeout(15e3)
1528
+ });
1529
+ } catch {
1530
+ throw new AirtableOperationError("Airtable request acknowledgment unavailable", write ? "uncertain" : "unapplied");
1531
+ }
1532
+ if (!response.ok)
1533
+ throw await response.body?.cancel().catch(() => {
1534
+ }), new AirtableOperationError("Airtable request rejected", write && (response.status >= 500 || response.status === 408 || response.status < 400) ? "uncertain" : "unapplied");
1535
+ try {
1536
+ if (!response.headers.get("content-type")?.toLowerCase().includes("application/json")) throw new Error();
1537
+ let value = object2(await response.json()), safe = serializable(value);
1538
+ if (Object.hasOwn(value, "error") || JSON.stringify(safe).includes(accessToken)) throw new Error();
1539
+ return value;
1540
+ } catch {
1541
+ throw new AirtableOperationError("Malformed Airtable acknowledgment", write ? "uncertain" : "unapplied");
1542
+ }
1543
+ }
1544
+ if (operation2 === "tables.list") {
1545
+ keys2(input, []);
1546
+ let tables = [], seen = /* @__PURE__ */ new Set(), offset;
1547
+ do {
1548
+ let query2 = new URLSearchParams(offset ? { offset } : {}), page = await request(`meta/bases/${baseId}/tables?${query2}`);
1549
+ Array.isArray(page.tables) || fail2("Malformed Airtable tables");
1550
+ for (let value of page.tables) {
1551
+ let t = object2(value);
1552
+ (!tableId(t.id) || !text2(t.name) || !text2(t.primaryFieldId) || !Array.isArray(t.fields) || tables.some((existing) => existing.id === t.id)) && fail2("Malformed Airtable table");
1553
+ let metadata = t.fields.map((value2) => {
1554
+ let f = object2(value2);
1555
+ return (typeof f.id != "string" || !/^fld[A-Za-z0-9]+$/.test(f.id) || !text2(f.name) || !text2(f.type)) && fail2("Malformed Airtable field"), { id: f.id, name: f.name, type: f.type, ...f.options === void 0 ? {} : { options: serializable(f.options) } };
1556
+ });
1557
+ (!metadata.some((f) => f.id === t.primaryFieldId) || new Set(metadata.map((f) => f.id)).size !== metadata.length) && fail2("Malformed Airtable fields"), tables.push({ id: t.id, name: t.name, primaryFieldId: t.primaryFieldId, fields: metadata });
1558
+ }
1559
+ offset = nextOffset(page.offset, seen);
1560
+ } while (offset);
1561
+ return tables;
1562
+ }
1563
+ (!text2(input.table) || input.table === "." || input.table === "..") && fail2("Invalid Airtable table"), mutation && !tableId(input.table) && fail2("Airtable writes require a stable table ID");
1564
+ let path = `${baseId}/${encodeURIComponent(input.table)}`;
1565
+ if (operation2 === "records.get") {
1566
+ keys2(input, ["table", "id"]), recordId(input.id) || fail2("Invalid Airtable record ID");
1567
+ let result3 = record2(await request(`${path}/${input.id}`));
1568
+ return result3.id !== input.id && fail2("Malformed Airtable record"), result3;
1569
+ }
1570
+ if (operation2 === "records.list") {
1571
+ keys2(input, ["table", "fields"], ["table"]), input.fields !== void 0 && (!Array.isArray(input.fields) || !input.fields.length || input.fields.some((f) => !text2(f)) || new Set(input.fields).size !== input.fields.length) && fail2("Invalid Airtable field selection");
1572
+ let records2 = [], ids2 = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set(), offset;
1573
+ do {
1574
+ let query2 = new URLSearchParams();
1575
+ for (let field of input.fields ?? []) query2.append("fields[]", field);
1576
+ offset && query2.set("offset", offset);
1577
+ let page = await request(`${path}?${query2}`);
1578
+ Array.isArray(page.records) || fail2("Malformed Airtable records");
1579
+ for (let value of page.records) {
1580
+ let r = record2(value);
1581
+ ids2.has(r.id) && fail2("Malformed Airtable pagination"), ids2.add(r.id), records2.push(r);
1582
+ }
1583
+ offset = nextOffset(page.offset, seen);
1584
+ } while (offset);
1585
+ return records2;
1586
+ }
1587
+ mutation || fail2("Unsupported Airtable operation"), keys2(input, ["table", "records"]), (!Array.isArray(input.records) || !input.records.length || input.records.length > 10) && fail2("Invalid Airtable batch");
1588
+ let kind = operation2.slice(8), ids = /* @__PURE__ */ new Set(), records = input.records.map((value) => {
1589
+ let r = object2(value);
1590
+ if (keys2(r, kind === "create" ? ["fields"] : kind === "update" ? ["id", "expected", "set"] : ["id", "expected"]), kind === "create") return { fields: fields3(r.fields, !0) };
1591
+ (!recordId(r.id) || ids.has(r.id)) && fail2("Invalid Airtable batch record ID"), ids.add(r.id);
1592
+ let set = kind === "update" ? fields3(r.set, !0) : void 0;
1593
+ 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 } : {} };
1594
+ });
1595
+ for (let r of records) {
1596
+ if (!("id" in r)) continue;
1597
+ let current2 = record2(await request(`${path}/${r.id}`));
1598
+ current2.id !== r.id && fail2("Malformed Airtable record");
1599
+ for (let [key, value] of Object.entries(r.expected))
1600
+ (value === null ? Object.hasOwn(current2.fields, key) : !Object.hasOwn(current2.fields, key) || !equal(current2.fields[key], value)) && fail2("Airtable reviewed values are stale");
1601
+ }
1602
+ await options.beforeMutation?.();
1603
+ let query = new URLSearchParams();
1604
+ if (kind === "delete") for (let id2 of ids) query.append("records[]", id2);
1605
+ let result2 = await request(`${path}${kind === "delete" ? `?${query}` : ""}`, {
1606
+ method: kind === "create" ? "POST" : kind === "update" ? "PATCH" : "DELETE",
1607
+ ...kind === "delete" ? {} : { body: JSON.stringify({ records: records.map((r) => "id" in r ? { id: r.id, fields: r.set } : r) }) }
1608
+ }, !0), acknowledged = [], returned = [];
1609
+ try {
1610
+ if (!Array.isArray(result2.records)) throw new Error();
1611
+ for (let value of result2.records) {
1612
+ let r = object2(value);
1613
+ if (!recordId(r.id) || acknowledged.includes(r.id) || kind !== "create" && !ids.has(r.id) || kind === "delete" && r.deleted !== !0) throw new Error();
1614
+ acknowledged.push(r.id), kind !== "delete" && returned.push(record2(r));
1615
+ }
1616
+ if (acknowledged.length !== records.length) throw new Error();
1617
+ } catch {
1618
+ throw new AirtableOperationError(
1619
+ "Incomplete Airtable mutation acknowledgment",
1620
+ acknowledged.length ? "partial" : "uncertain",
1621
+ acknowledged.length ? [receipt(acknowledged)] : []
1622
+ );
1623
+ }
1624
+ return { receipt: receipt(acknowledged), ...kind === "delete" ? {} : { records: returned } };
1625
+ }
1626
+ function nextOffset(value, seen) {
1627
+ if (value !== void 0)
1628
+ return (!text2(value) || seen.has(value)) && fail2("Malformed Airtable pagination"), seen.add(value), value;
1629
+ }
1630
+
1631
+ var MANAGED_CONNECTION_CAPABILITY_ENV = "ODDINGTON_MANAGED_CONNECTION_CAPABILITY";
1632
+ function managedConnections(capability) {
1633
+ let endpoint = new URL(capability.endpoint);
1634
+ if (endpoint.protocol !== "http:" || endpoint.hostname !== "127.0.0.1" || !endpoint.port || endpoint.pathname !== "/" || endpoint.search || endpoint.hash || endpoint.username || endpoint.password || !/^[0-9a-f-]{36}$/.test(capability.token)) throw new AirtableOperationError("Airtable capability unavailable");
1635
+ return createConnections(async (name, operation2, input) => {
1636
+ let safeInput;
1637
+ try {
1638
+ safeInput = serializable(input);
1639
+ } catch {
1640
+ safeInput = null;
1641
+ }
1642
+ try {
1643
+ let response = await fetch(new URL("airtable", endpoint), {
1644
+ method: "POST",
1645
+ redirect: "error",
1646
+ headers: { authorization: `Bearer ${capability.token}`, "content-type": "application/json" },
1647
+ body: JSON.stringify({ name, operation: operation2, input: safeInput }),
1648
+ signal: AbortSignal.timeout(125e3)
1649
+ }), value = await response.json();
1650
+ if (!response.ok) throw new AirtableOperationError(
1651
+ "Airtable operation failed; the execution retains its evidence",
1652
+ value.effect === "partial" || value.effect === "uncertain" ? value.effect : "unapplied",
1653
+ value.receipts ?? []
1654
+ );
1655
+ return value;
1656
+ } catch (error) {
1657
+ throw error instanceof AirtableOperationError ? error : new AirtableOperationError(
1658
+ "Airtable parent acknowledgment unavailable",
1659
+ ["records.create", "records.update", "records.delete"].includes(operation2) ? "uncertain" : "unapplied"
1660
+ );
1661
+ }
1662
+ });
1663
+ }
1664
+
1665
+ var observer;
1666
+ async function reportLocalRoutineEffect(value) {
1667
+ await observer?.(value);
1668
+ }
1669
+
1670
+ var connections = /* @__PURE__ */ createConnections(async (name, operation2, input) => {
1671
+ try {
1672
+ let managed = process.env[MANAGED_CONNECTION_CAPABILITY_ENV];
1673
+ if (managed) {
1674
+ let client = managedConnections(JSON.parse(managed)).airtable(name);
1675
+ return operation2 === "tables.list" ? await client.tables.list() : await client.records[operation2.slice(8)](input);
1676
+ }
1677
+ let raw = JSON.parse(process.env[ROUTINE_CONNECTION_CREDENTIALS_ENV] ?? "[]");
1678
+ if (!Array.isArray(raw)) throw new Error();
1679
+ let leases = raw.map((value) => parseConnectionLease(value));
1680
+ if (leases.some((lease2) => lease2.provider !== "airtable") || new Set(leases.map((lease2) => lease2.name)).size !== leases.length) throw new Error();
1681
+ let lease = leases.find((lease2) => lease2.name === name);
1682
+ if (!lease || lease.provider !== "airtable") throw new Error();
1683
+ let writing = ["records.create", "records.update", "records.delete"].includes(operation2), captured = serializable(input), result2;
1684
+ try {
1685
+ result2 = await executeAirtableOperation(lease, operation2, captured);
1686
+ } catch (error) {
1687
+ throw writing && error instanceof AirtableOperationError && await reportLocalRoutineEffect({
1688
+ type: "effect",
1689
+ connection: `airtable/${name}`,
1690
+ operation: operation2,
1691
+ input: captured,
1692
+ effect: error.effect,
1693
+ receipts: error.receipts
1694
+ }), error;
1695
+ }
1696
+ return writing && await reportLocalRoutineEffect({
1697
+ type: "effect",
1698
+ connection: `airtable/${name}`,
1699
+ operation: operation2,
1700
+ input: captured,
1701
+ effect: "confirmed",
1702
+ receipts: [result2.receipt]
1703
+ }), result2;
1704
+ } catch (error) {
1705
+ throw error instanceof AirtableOperationError ? error : new AirtableOperationError("Airtable connection unavailable");
1706
+ }
1707
+ });
1708
+
1709
+ var LOCAL_ROUTINE_VALUE_BYTES = 256 * 1024;
1710
+
1711
+ var RECORD_WRITE_INPUT_LIMIT = 8 * 1024 * 1024, RoutineRecordWriteError = class extends Error {
1712
+ constructor(message, effect) {
1713
+ super(message);
1714
+ this.effect = effect;
1715
+ this.name = "RoutineRecordWriteError";
1716
+ }
1717
+ effect;
1718
+ };
1719
+ function validateRecordWrite(value) {
1720
+ let input = serializable(value);
1721
+ if (!input || Array.isArray(input) || typeof input != "object" || Object.keys(input).sort().join(",") !== "records,repository" || !validRepositoryAlias(input.repository) || !Array.isArray(input.records) || !input.records.length || input.records.length > 1e4 || new Set(input.records.map((edit) => edit?.ref)).size !== input.records.length)
1722
+ throw new InboxContractError("Invalid record update batch");
1723
+ for (let edit of input.records) {
1724
+ if (!edit || Array.isArray(edit) || typeof edit != "object" || !validRecordRef(edit.ref))
1725
+ throw new InboxContractError("Invalid record edit");
1726
+ if ("expectedVersion" in edit) {
1727
+ if (Object.keys(edit).sort().join(",") !== "expectedVersion,ref,set" || typeof edit.expectedVersion != "string" || !/^record-v1:[0-9a-f]{64}$/.test(edit.expectedVersion) || !edit.set || Array.isArray(edit.set) || typeof edit.set != "object" || !Object.keys(edit.set).length)
1728
+ throw new InboxContractError("Invalid record edit");
1729
+ continue;
1730
+ }
1731
+ if (Object.keys(edit).sort().join(",") !== "fields,path,ref" || typeof edit.path != "string" || !validCreatePath(edit.path) || !edit.fields || Array.isArray(edit.fields) || typeof edit.fields != "object" || !Object.keys(edit.fields).length)
1732
+ throw new InboxContractError("Invalid record creation");
1733
+ }
1734
+ return structuredClone(input);
1735
+ }
1736
+ function validateRecordUpdate(value) {
1737
+ let input = validateRecordWrite(value);
1738
+ if (input.records.some((record3) => !("expectedVersion" in record3)))
1739
+ throw new InboxContractError("Record creation is unavailable for this operation");
1740
+ return input;
1394
1741
  }
1395
- function contentPath(id2, name) {
1396
- let path = idPath(id2);
1397
- if (name === void 0) return `${path}/content`;
1398
- if (!safeEnrichmentName(name)) throw invalid3();
1399
- return `${path}/enrichments/${encodeURIComponent(name)}/content`;
1742
+ function validateRecordDelete(value) {
1743
+ let input = serializable(value);
1744
+ if (!input || Array.isArray(input) || typeof input != "object" || Object.keys(input).sort().join(",") !== "records,repository" || !validRepositoryAlias(input.repository) || !Array.isArray(input.records) || !input.records.length || input.records.length > 1e4 || new Set(input.records.map((record3) => record3?.ref)).size !== input.records.length)
1745
+ throw new InboxContractError("Invalid record deletion batch");
1746
+ for (let record3 of input.records)
1747
+ if (!record3 || Array.isArray(record3) || typeof record3 != "object" || Object.keys(record3).sort().join(",") !== "expectedVersion,ref" || !validRecordRef(record3.ref) || typeof record3.expectedVersion != "string" || !/^record-v1:[0-9a-f]{64}$/.test(record3.expectedVersion))
1748
+ throw new InboxContractError("Invalid record deletion");
1749
+ return structuredClone(input);
1400
1750
  }
1401
- async function read(id2, names) {
1402
- let context2 = await resolveFilesContext();
1403
- if (idPath(id2), names === void 0 || typeof names == "string") {
1404
- let path = contentPath(id2, names);
1405
- return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
1406
- }
1407
- if (!Array.isArray(names)) throw invalid3();
1408
- let distinct = [], seen = /* @__PURE__ */ new Set();
1409
- for (let name of names) {
1410
- if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid3();
1411
- if (!seen.has(name)) {
1412
- if (seen.size === 16) throw invalid3();
1413
- seen.add(name), distinct.push(name);
1414
- }
1751
+ function validateRecordChange(value) {
1752
+ let input = serializable(value);
1753
+ if (!input || Array.isArray(input) || typeof input != "object" || Object.keys(input).sort().join(",") !== "records,repository" || !validRepositoryAlias(input.repository) || !Array.isArray(input.records) || !input.records.length || input.records.length > 1e4 || new Set(input.records.map((record3) => record3?.ref)).size !== input.records.length || new TextEncoder().encode(JSON.stringify(input)).byteLength > RECORD_WRITE_INPUT_LIMIT)
1754
+ throw new InboxContractError("Invalid record change batch");
1755
+ let writes = [], deletes = [];
1756
+ for (let record3 of input.records) {
1757
+ if (!record3 || typeof record3 != "object" || Array.isArray(record3))
1758
+ throw new InboxContractError("Invalid record change");
1759
+ "set" in record3 || "fields" in record3 ? writes.push(record3) : deletes.push(record3);
1415
1760
  }
1416
- let paths = distinct.map((name) => contentPath(id2, name));
1417
- return timed(async (parent) => {
1418
- let responses = {};
1419
- try {
1420
- for (let i = 0; i < paths.length; i++) {
1421
- let response = await operation((context3, signal) => send(paths[i], { method: "GET" }, !1, context3, signal), context2, parent);
1422
- Object.defineProperty(responses, distinct[i], { value: response, enumerable: !0 });
1423
- }
1424
- if (!context2.isCurrent()) throw new FileOperationError("unsupported_context", 400);
1425
- return responses;
1426
- } catch (error) {
1427
- for (let response of Object.values(responses)) response.body?.cancel().catch(() => {
1428
- });
1429
- throw error;
1430
- }
1431
- });
1761
+ return writes.length && validateRecordWrite({ repository: input.repository, records: writes }), deletes.length && validateRecordDelete({ repository: input.repository, records: deletes }), structuredClone(input);
1762
+ }
1763
+ function validateRoutineRecordWrite(value) {
1764
+ let body2 = serializable(value);
1765
+ if (!body2 || typeof body2 != "object" || Array.isArray(body2) || Object.keys(body2).sort().join(",") !== "input,requestKey" || typeof body2.requestKey != "string" || !body2.requestKey.trim() || body2.requestKey !== body2.requestKey.trim() || body2.requestKey.length > 512)
1766
+ throw new InboxContractError("A stable routine request key is required");
1767
+ return { input: validateRecordChange(body2.input), requestKey: body2.requestKey };
1768
+ }
1769
+ function validCreatePath(value) {
1770
+ return value === value.trim() && value.endsWith(".md") && !value.startsWith("/") && value.split("/").every((segment) => !!segment && ![".", ".."].includes(segment) && /^[a-zA-Z0-9_.-]+$/.test(segment));
1771
+ }
1772
+
1773
+ var sources = /* @__PURE__ */ new WeakMap();
1774
+ function registerBrowserAuth(handle2, source) {
1775
+ sources.set(handle2, source);
1776
+ }
1777
+ function browserAuthSource(handle2) {
1778
+ return sources.get(handle2);
1432
1779
  }
1433
- var files = {
1434
- async upload(id2) {
1435
- return operation(async (context2, signal) => {
1436
- let file = await send(`${idPath(id2)}/upload`, { method: "POST" }, !0, context2, signal);
1437
- if (file.id !== id2) throw unavailable();
1438
- return file;
1439
- });
1440
- },
1441
- async create(input, options) {
1442
- let context2 = await resolveFilesContext();
1443
- 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")))
1444
- throw invalid3();
1445
- let blob = input.file instanceof Blob, array2 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
1446
- if (!blob && !array2 && !stream) throw invalid3();
1447
- let intrinsic = blob ? input.file.size : array2 ? input.file.byteLength : void 0;
1448
- if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid3();
1449
- let name = input.name;
1450
- 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));
1451
- let metadata = parseFileCreateMetadata({
1452
- name,
1453
- size: intrinsic ?? input.size,
1454
- path: input.path,
1455
- storage: input.storage,
1456
- csv: input.csv,
1457
- requestKey: options?.requestKey === void 0 ? crypto.randomUUID() : options.requestKey
1458
- }, FILE_ORIGINAL_MAX_BYTES);
1459
- if (!context2.local && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
1460
- let header = encodeURIComponent(JSON.stringify(metadata));
1461
- if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid3();
1462
- if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1463
- if (active++, context2.localFiles && metadata.size > MAX_BYTES) {
1464
- let controller = new AbortController(), file = input.file, offset = 0, body2 = file instanceof ReadableStream ? file : file instanceof Blob ? file.stream() : new ReadableStream({
1465
- pull(controller2) {
1466
- if (offset === file.byteLength) {
1467
- controller2.close();
1468
- return;
1469
- }
1470
- let end = Math.min(offset + 256 * 1024, file.byteLength);
1471
- controller2.enqueue(file.subarray(offset, end)), offset = end;
1472
- }
1473
- }, { highWaterMark: 0 });
1474
- try {
1475
- return await send("", { method: "POST", headers: {
1476
- "content-type": "application/octet-stream",
1477
- "x-oddington-file": header
1478
- }, body: body2 }, !0, context2, controller.signal);
1479
- } finally {
1480
- active--;
1481
- }
1482
- }
1483
- 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) => {
1484
- try {
1485
- let bytes = array2 ? input.file.slice() : await boundedBytes(
1486
- blob ? input.file.stream() : input.file,
1487
- metadata.size
1488
- );
1489
- if (bytes.byteLength !== metadata.size) throw invalid3();
1490
- if (signal.aborted) throw unavailable();
1491
- return await send("", {
1492
- method: "POST",
1493
- headers: { "content-type": "application/octet-stream", "x-oddington-file": header },
1494
- body: bytes.buffer
1495
- }, !0, context2, signal);
1496
- } finally {
1497
- active--;
1498
- }
1499
- }).catch((error) => {
1500
- throw error instanceof FileOperationError ? error : unavailable();
1501
- });
1502
- },
1503
- async enrich(input) {
1504
- let context2 = await resolveFilesContext();
1505
- 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 invalid3();
1506
- let path = `${idPath(input.file)}/enrichments`;
1507
- if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
1508
- throw new FileOperationError("request_too_large", 413);
1509
- return operation(async (context3, signal) => {
1510
- let bytes;
1511
- if (typeof input.content == "string") {
1512
- let buffer = new Uint8Array(Math.min(MAX_BYTES, input.content.length * 3)), encoded = new TextEncoder().encodeInto(input.content, buffer);
1513
- if (encoded.read !== input.content.length) throw new FileOperationError("request_too_large", 413);
1514
- bytes = buffer.slice(0, encoded.written);
1515
- } else bytes = input.content.slice();
1516
- let metadata = parseFileEnrichMetadata({
1517
- name: input.name,
1518
- size: bytes.byteLength,
1519
- ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
1520
- ...input.replace === void 0 ? {} : { replace: input.replace }
1521
- }, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
1522
- if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid3();
1523
- let result2 = await send(path, { method: "POST", headers: {
1524
- "content-type": "application/octet-stream",
1525
- "x-oddington-enrichment": header
1526
- }, body: bytes.buffer }, "enrichment", context3, signal);
1527
- if (result2.name !== metadata.name) throw unavailable();
1528
- return result2;
1529
- }, context2);
1530
- },
1531
- async get(id2) {
1532
- return operation((context2, signal) => send(idPath(id2), { method: "GET" }, !0, context2, signal));
1533
- },
1534
- read
1535
- };
1536
1780
 
1537
1781
  var sessionKey = "_os.app.session", responseChecks = /* @__PURE__ */ new WeakMap(), AppResponseReadError = class extends Error {
1538
1782
  }, AppContextDenied = class extends Error {
@@ -1851,8 +2095,15 @@ function validBinding(value) {
1851
2095
  }
1852
2096
 
1853
2097
  var installedDispose;
1854
- function init({ auth }) {
2098
+ function init({ auth: input }) {
1855
2099
  installedDispose?.();
2100
+ let registered = browserAuthSource(input), auth2 = registered ?? input;
2101
+ if (!registered && input && "getState" in input || typeof auth2?.getSession != "function" || typeof auth2?.onAuthStateChange != "function") {
2102
+ installedDispose = installMemberContext(async () => {
2103
+ throw new Error("Hosted Data context unavailable.");
2104
+ });
2105
+ return;
2106
+ }
1856
2107
  let endpoint, workspace, localOrigin;
1857
2108
  try {
1858
2109
  let url = new URL(globalThis.location.origin);
@@ -1861,13 +2112,13 @@ function init({ auth }) {
1861
2112
  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);
1862
2113
  } catch {
1863
2114
  }
1864
- let active2 = !0, revision = 0, person, local = localOrigin ? appContext(localOrigin, () => active2) : void 0, { data: { subscription } } = auth.onAuthStateChange((event2, session) => {
2115
+ let active2 = !0, revision = 0, person, token, local = localOrigin ? appContext(localOrigin, () => active2) : void 0, { data: { subscription } } = auth2.onAuthStateChange((event2, session) => {
1865
2116
  let next = session?.user.id ?? null;
1866
- (event2 === "SIGNED_OUT" || person !== void 0 && next !== person) && (revision++, local?.invalidate()), person = next;
2117
+ (event2 === "SIGNED_OUT" || person !== void 0 && next !== person || registered && person !== void 0 && event2 === "SIGNED_IN" && token !== session?.access_token) && (revision++, local?.invalidate()), person = next, token = session?.access_token;
1867
2118
  }), uninstall = installMemberContext(async () => {
1868
2119
  if (local) return local.resolve();
1869
2120
  if (!active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
1870
- let started = revision, { data: { session }, error } = await auth.getSession();
2121
+ let started = revision, { data: { session }, error } = await auth2.getSession();
1871
2122
  if (!active2 || globalThis.location.origin !== endpoint || started !== revision || error || !session || person !== void 0 && person !== session.user.id)
1872
2123
  throw new Error("Hosted Data context unavailable.");
1873
2124
  let expiresAt = (session.expires_at ?? 0) * 1e3;
@@ -1887,6 +2138,403 @@ function init({ auth }) {
1887
2138
  }
1888
2139
  var os = { init };
1889
2140
 
2141
+ var CLI_CALLBACK = "http://127.0.0.1:53682/oauth/callback";
2142
+ function authorizationConfiguration(value) {
2143
+ let setup = value;
2144
+ if (!setup || typeof setup.clientId != "string" || !/^[A-Za-z0-9_-]{1,128}$/.test(setup.clientId) || setup.redirectUri !== CLI_CALLBACK || !Array.isArray(setup.scopes) || setup.scopes.length !== 1 || setup.scopes[0] !== "email") throw new Error("Unavailable");
2145
+ return { clientId: setup.clientId, redirectUri: CLI_CALLBACK, scopes: ["email"] };
2146
+ }
2147
+ function authorizationDetails(value, id2, setup, userId, account) {
2148
+ let details = value;
2149
+ return !details || details.authorization_id !== id2 || details.redirect_uri !== setup.redirectUri || details.client?.id !== setup.clientId || typeof details.client.name != "string" || !details.client.name.trim() || details.client.name.length > 128 || /[\x00-\x1f\x7f]/.test(details.client.name) || details.user?.id !== userId || details.user.email !== account.email || typeof details.scope != "string" || details.scope.trim() !== "email" ? Object.freeze({ status: "invalid" }) : Object.freeze({
2150
+ status: "consent",
2151
+ clientName: details.client.name.trim(),
2152
+ account,
2153
+ scopes: Object.freeze([...setup.scopes]),
2154
+ callbackAddress: new URL(setup.redirectUri).host
2155
+ });
2156
+ }
2157
+ function authorizationReturn(value, decision) {
2158
+ let returnUrl = value?.redirect_url;
2159
+ if (typeof returnUrl != "string" || returnUrl.length > 8192 || !returnUrl.startsWith(`${CLI_CALLBACK}?`) || /[\x00-\x20\x7f]/.test(returnUrl)) return Object.freeze({ status: "invalid" });
2160
+ try {
2161
+ let url = new URL(returnUrl);
2162
+ if (url.origin + url.pathname !== CLI_CALLBACK || url.username || url.password || url.hash) return Object.freeze({ status: "invalid" });
2163
+ let parameters = url.searchParams, allowed = ["code", "state", "error", "error_description", "error_uri"];
2164
+ for (let key of parameters.keys())
2165
+ if (!allowed.includes(key) || parameters.getAll(key).length !== 1) return Object.freeze({ status: "invalid" });
2166
+ let code = parameters.get("code"), error = parameters.get("error");
2167
+ return !parameters.get("state") || !!code == !!error || decision === "deny" && !error || decision === "approve" && !code || parameters.has("code") && !code || parameters.has("error") && !error || code && (parameters.has("error_description") || parameters.has("error_uri")) ? Object.freeze({ status: "invalid" }) : Object.freeze({ status: "return", returnUrl });
2168
+ } catch {
2169
+ return Object.freeze({ status: "invalid" });
2170
+ }
2171
+ }
2172
+ function authorizationFailure(error) {
2173
+ let status = error?.status;
2174
+ return Object.freeze({ status: status === 404 || status === 410 || status === 400 ? "expired" : status === 401 ? "signed_out" : status === 403 || status === 422 ? "invalid" : "unavailable" });
2175
+ }
2176
+
2177
+ function createBrowserAuth(runtime) {
2178
+ let coordinators = /* @__PURE__ */ new Map();
2179
+ function publish(c, state) {
2180
+ c.state = Object.freeze(state);
2181
+ for (let listener of c.listeners)
2182
+ try {
2183
+ listener(c.state);
2184
+ } catch {
2185
+ }
2186
+ }
2187
+ function notify(c, event2) {
2188
+ for (let listener of c.sessions)
2189
+ try {
2190
+ listener(event2, event2 === "SIGNED_OUT" ? null : c.session);
2191
+ } catch {
2192
+ }
2193
+ }
2194
+ function expire(c) {
2195
+ !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"));
2196
+ }
2197
+ function accept(c, event2, session) {
2198
+ if (!c.active || event2 === "INITIAL_SESSION" && c.state.status !== "initializing" || event2 === "TOKEN_REFRESHED" && !c.session && c.state.status !== "initializing") return;
2199
+ (c.session?.user?.id !== session?.user?.id || event2 === "SIGNED_OUT" || event2 === "SIGNED_IN" && c.session && session?.access_token !== c.session.access_token) && c.revision++, c.timer && clearTimeout(c.timer);
2200
+ let pending = c.state.pending;
2201
+ if (!session) {
2202
+ c.session = null, publish(c, { status: c.state.status === "expired" ? "expired" : "signed_out", ...pending ? { pending } : {} }), notify(c, "SIGNED_OUT");
2203
+ return;
2204
+ }
2205
+ if (!validSession(session)) {
2206
+ c.session = session, expire(c);
2207
+ return;
2208
+ }
2209
+ c.session = session;
2210
+ let email = typeof session.user.email == "string" ? session.user.email.trim() : "", metadata = session.user.user_metadata, displayName = ["name", "full_name", "first_name"].map((key) => metadata?.[key]).find((value) => typeof value == "string" && value.trim());
2211
+ publish(c, { status: "signed_in", account: Object.freeze({ email, displayName: displayName?.trim() || email }), ...pending ? { pending } : {} }), notify(c, event2);
2212
+ let checkExpiry = () => {
2213
+ if (!c.active || !c.session) return;
2214
+ let remaining = c.session.expires_at * 1e3 - Date.now();
2215
+ remaining <= 0 ? expire(c) : c.timer = setTimeout(checkExpiry, Math.min(remaining, 2147483647));
2216
+ };
2217
+ checkExpiry();
2218
+ }
2219
+ function validSession(session) {
2220
+ return typeof session.access_token == "string" && /^[^\s]{1,8192}$/.test(session.access_token) && typeof session.user?.id == "string" && !!session.user.id && Number.isFinite(session.expires_at) && session.expires_at * 1e3 > Date.now();
2221
+ }
2222
+ function createCoordinator(origin) {
2223
+ let c = {
2224
+ state: Object.freeze({ status: "initializing" }),
2225
+ session: null,
2226
+ revision: 0,
2227
+ active: !0,
2228
+ refs: 0,
2229
+ listeners: /* @__PURE__ */ new Set(),
2230
+ sessions: /* @__PURE__ */ new Set(),
2231
+ ready: Promise.resolve()
2232
+ };
2233
+ return c.ready = (async () => {
2234
+ let revision = c.revision;
2235
+ try {
2236
+ if (!allowedOrigin(origin)) throw runtime.failure("unavailable");
2237
+ let response = await fetch(`${origin}/api/auth/browser-configuration`, { method: "GET", credentials: "same-origin", redirect: "error", cache: "no-store" });
2238
+ if (!response.ok) throw runtime.failure("unavailable");
2239
+ let configuration = validateConfiguration(await response.json());
2240
+ if (configuration.authorization && origin !== "https://auth.oddington.ai" && origin !== "http://127.0.0.1:5176") throw runtime.failure("unavailable");
2241
+ if (c.authorization = configuration.authorization, !c.active || globalThis.location?.origin !== origin) return;
2242
+ if (c.provider = await runtime.provider(configuration, {
2243
+ revision: () => c.revision,
2244
+ current: (revision2) => current2(c, origin, revision2),
2245
+ canPersistSession: () => c.active && (c.state.status === "initializing" || !!c.session || c.state.pending === "verify_code"),
2246
+ canAuthorize: (accessToken) => current2(c, origin, c.revision) && !!c.session && c.session.access_token === accessToken && c.state.pending !== "sign_out"
2247
+ }), !c.active || globalThis.location?.origin !== origin) {
2248
+ c.provider.dispose();
2249
+ return;
2250
+ }
2251
+ let subscription = c.provider.onAuthStateChange((event2, session) => {
2252
+ c.state.status === "initializing" && c.state.pending === "sign_out" || accept(c, event2, session);
2253
+ }).data.subscription;
2254
+ c.unsubscribe = () => subscription.unsubscribe();
2255
+ let started = c.revision, { data: data3, error } = await c.provider.getSession();
2256
+ if (!current2(c, origin, started)) return;
2257
+ 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);
2258
+ } catch {
2259
+ current2(c, origin, revision) && publish(c, { status: "unavailable", error: "unavailable" });
2260
+ }
2261
+ })(), c;
2262
+ }
2263
+ function current2(c, origin, revision) {
2264
+ return c.session && !validSession(c.session) && expire(c), c.active && c.revision === revision && globalThis.location?.origin === origin;
2265
+ }
2266
+ return { create() {
2267
+ let origin = globalThis.location?.origin ?? "", c = coordinators.get(origin);
2268
+ c || (c = createCoordinator(origin), coordinators.set(origin, c));
2269
+ let coordinator = c;
2270
+ coordinator.refs++;
2271
+ let active2 = !0, ownedAction, authorizationId, authorizationGeneration = 0, inspected, observers = /* @__PURE__ */ new Set(), sessionObservers = /* @__PURE__ */ new Set(), lastState = coordinator.state, observation = (state) => {
2272
+ lastState = state;
2273
+ for (let listener of observers)
2274
+ try {
2275
+ listener(state);
2276
+ } catch {
2277
+ }
2278
+ };
2279
+ coordinator.listeners.add(observation);
2280
+ let assertActive = () => {
2281
+ if (!active2) throw runtime.failure("disposed");
2282
+ };
2283
+ async function action(kind, work) {
2284
+ if (assertActive(), coordinator.action && kind !== "sign_out" || kind === "sign_out" && coordinator.state.pending === "sign_out") throw runtime.failure("busy");
2285
+ kind === "sign_out" && (coordinator.revision++, notify(coordinator, "SIGNED_OUT"));
2286
+ let marker = {};
2287
+ coordinator.action = marker, ownedAction = marker;
2288
+ let revision = coordinator.revision;
2289
+ publish(coordinator, { ...coordinator.state, error: void 0, pending: kind });
2290
+ try {
2291
+ if (await coordinator.ready, assertActive(), !coordinator.provider || !coordinator.active || globalThis.location?.origin !== origin) throw runtime.failure("unavailable");
2292
+ 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");
2293
+ } catch (error) {
2294
+ let reason = active2 ? current2(coordinator, origin, revision) ? safeReason(error) ?? "unavailable" : "stale" : "disposed";
2295
+ throw active2 && current2(coordinator, origin, revision) && publish(coordinator, { ...coordinator.state, error: reason }), runtime.failure(reason);
2296
+ } finally {
2297
+ 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);
2298
+ }
2299
+ }
2300
+ async function authorize(kind, id2) {
2301
+ if (!active2) return Object.freeze({ status: "disposed" });
2302
+ if (id2 !== authorizationId && (authorizationId = id2, authorizationGeneration++, inspected = void 0), !id2) return Object.freeze({ status: "missing" });
2303
+ if (typeof id2 != "string" || !/^[A-Za-z0-9_-]{1,128}$/.test(id2)) return Object.freeze({ status: "invalid" });
2304
+ let generation = authorizationGeneration;
2305
+ if (await coordinator.ready, !active2) return Object.freeze({ status: "disposed" });
2306
+ if (generation !== authorizationGeneration) return Object.freeze({ status: "stale" });
2307
+ let revision = coordinator.revision;
2308
+ if (!current2(coordinator, origin, revision)) return Object.freeze({ status: "stale" });
2309
+ if (!coordinator.session || coordinator.state.pending === "sign_out") return Object.freeze({ status: coordinator.state.status === "expired" ? "expired" : coordinator.state.status === "unavailable" ? "unavailable" : "signed_out" });
2310
+ if (!coordinator.authorization || !coordinator.provider) return Object.freeze({ status: "unavailable" });
2311
+ if (coordinator.action) return Object.freeze({ status: "busy" });
2312
+ if (kind !== "get" && (!inspected || inspected.id !== id2 || inspected.revision !== revision)) return Object.freeze({ status: "stale" });
2313
+ if (kind !== "get" && inspected?.result.status !== "consent") return inspected.result;
2314
+ let marker = {};
2315
+ coordinator.action = marker, ownedAction = marker;
2316
+ let requestCurrent = () => active2 && generation === authorizationGeneration && current2(coordinator, origin, revision) && coordinator.action === marker && !!coordinator.session && coordinator.state.pending !== "sign_out", stale = () => Object.freeze({ status: active2 ? "stale" : "disposed" });
2317
+ try {
2318
+ let provider2 = coordinator.provider, response = await provider2.authorization.get(id2, requestCurrent);
2319
+ if (!requestCurrent()) return stale();
2320
+ if (response.error) {
2321
+ inspected = void 0;
2322
+ let failure = authorizationFailure(response.error);
2323
+ return failure.status === "signed_out" && expire(coordinator), failure;
2324
+ }
2325
+ let account = coordinator.state.account, result2 = response.data && typeof response.data == "object" && "redirect_url" in response.data ? authorizationReturn(response.data) : authorizationDetails(response.data, id2, coordinator.authorization, coordinator.session.user.id, account);
2326
+ if (inspected = { id: id2, revision, result: result2 }, kind === "get" || result2.status !== "consent") return result2;
2327
+ if (!requestCurrent()) return stale();
2328
+ let decision = await provider2.authorization[kind](id2, requestCurrent);
2329
+ if (!requestCurrent()) return stale();
2330
+ let returned = decision.error ? authorizationFailure(decision.error) : authorizationReturn(decision.data, kind);
2331
+ return returned.status === "signed_out" && expire(coordinator), inspected = { id: id2, revision, result: returned }, returned;
2332
+ } catch (error) {
2333
+ return !requestCurrent() || (inspected = void 0, safeReason(error) === "stale") ? stale() : Object.freeze({ status: "unavailable" });
2334
+ } finally {
2335
+ coordinator.action === marker && (coordinator.action = void 0), ownedAction === marker && (ownedAction = void 0);
2336
+ }
2337
+ }
2338
+ let handle2 = Object.freeze({
2339
+ authorization: Object.freeze({
2340
+ get: (id2) => authorize("get", id2),
2341
+ approve: (id2) => authorize("approve", id2),
2342
+ deny: (id2) => authorize("deny", id2)
2343
+ }),
2344
+ getState() {
2345
+ return active2 && coordinator.session && !validSession(coordinator.session) && expire(coordinator), lastState;
2346
+ },
2347
+ subscribe(listener) {
2348
+ return assertActive(), observers.add(listener), () => {
2349
+ observers.delete(listener);
2350
+ };
2351
+ },
2352
+ async sendCode(email) {
2353
+ if (assertActive(), !validEmail(email)) throw runtime.failure("invalid_input");
2354
+ await action("send_code", async (provider2) => {
2355
+ let { error } = await provider2.signInWithOtp({ email: email.trim(), options: { shouldCreateUser: !1 } });
2356
+ if (error && !accountRefusal(error)) throw runtime.failure("unavailable");
2357
+ });
2358
+ },
2359
+ async verifyCode(email, code) {
2360
+ if (assertActive(), !validEmail(email) || typeof code != "string" || !/^\d{6}$/.test(code)) throw runtime.failure("invalid_input");
2361
+ await action("verify_code", async (provider2) => {
2362
+ let revision = coordinator.revision, { data: data3, error } = await provider2.verifyOtp({ email: email.trim(), token: code, type: "email" });
2363
+ if (error) throw runtime.failure(accountRefusal(error) ? "invalid_code" : "unavailable");
2364
+ if (!data3.session || !validSession(data3.session)) throw runtime.failure("invalid_code");
2365
+ if (!current2(coordinator, origin, revision) && (coordinator.session?.access_token !== data3.session.access_token || coordinator.revision !== revision + 1 || coordinator.state.pending !== "verify_code")) throw runtime.failure("stale");
2366
+ accept(coordinator, "SIGNED_IN", data3.session);
2367
+ });
2368
+ },
2369
+ async signOut() {
2370
+ assertActive(), await action("sign_out", async (provider2) => {
2371
+ let revision = coordinator.revision, { error } = await provider2.signOut({ scope: "local" });
2372
+ if (error) throw runtime.failure("unavailable");
2373
+ if (!current2(coordinator, origin, revision) && coordinator.session) throw runtime.failure("stale");
2374
+ accept(coordinator, "SIGNED_OUT", null);
2375
+ });
2376
+ },
2377
+ dispose() {
2378
+ if (active2) {
2379
+ active2 = !1, authorizationGeneration++, inspected = void 0, ownedAction && coordinator.action === ownedAction && coordinator.revision++, observers.clear(), coordinator.listeners.delete(observation);
2380
+ for (let listener of sessionObservers)
2381
+ coordinator.sessions.delete(listener), listener("SIGNED_OUT", null);
2382
+ 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));
2383
+ }
2384
+ }
2385
+ });
2386
+ return registerBrowserAuth(handle2, {
2387
+ async getSession() {
2388
+ assertActive(), await coordinator.ready, assertActive();
2389
+ let revision = coordinator.revision;
2390
+ if (!current2(coordinator, origin, revision) || !coordinator.provider || !coordinator.session || coordinator.state.pending === "sign_out") return { data: { session: null }, error: null };
2391
+ let result2;
2392
+ try {
2393
+ result2 = await coordinator.provider.getSession();
2394
+ } catch {
2395
+ result2 = { data: { session: null }, error: runtime.failure("unavailable") };
2396
+ }
2397
+ return !active2 || !current2(coordinator, origin, revision) ? { data: { session: null }, error: runtime.failure("stale") } : result2.error ? !terminalSessionFailure(result2.error) && coordinator.session && validSession(coordinator.session) ? { data: { session: coordinator.session }, error: null } : (expire(coordinator), { data: { session: null }, error: runtime.failure("unavailable") }) : (accept(coordinator, "TOKEN_REFRESHED", result2.data.session), { data: { session: coordinator.session }, error: null });
2398
+ },
2399
+ onAuthStateChange(callback) {
2400
+ if (!active2)
2401
+ return callback("SIGNED_OUT", null), { data: { subscription: { unsubscribe() {
2402
+ } } } };
2403
+ let listener = (event2, session) => callback(event2, session);
2404
+ return coordinator.sessions.add(listener), sessionObservers.add(listener), callback("INITIAL_SESSION", coordinator.session), { data: { subscription: { unsubscribe() {
2405
+ coordinator.sessions.delete(listener), sessionObservers.delete(listener);
2406
+ } } } };
2407
+ }
2408
+ }), handle2;
2409
+ } };
2410
+ }
2411
+ function safeReason(error) {
2412
+ let reason = error?.reason;
2413
+ return ["invalid_input", "invalid_code", "unavailable", "busy", "stale", "disposed"].includes(reason) ? reason : void 0;
2414
+ }
2415
+ function accountRefusal(error) {
2416
+ return [400, 401, 403, 404, 422].includes(error?.status ?? 0);
2417
+ }
2418
+ function terminalSessionFailure(error) {
2419
+ return [400, 401, 403, 404, 422].includes(error?.status ?? 0);
2420
+ }
2421
+ function validEmail(email) {
2422
+ return typeof email == "string" && email.length <= 320 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());
2423
+ }
2424
+ function allowedOrigin(origin) {
2425
+ if (origin === "http://127.0.0.1:5176" || origin === "https://auth.oddington.ai") return !0;
2426
+ try {
2427
+ let url = new URL(origin), slug = url.hostname.endsWith(".oddington.ai") ? url.hostname.slice(0, -13) : "";
2428
+ return slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "api", "os", "www"].includes(slug) && origin === `https://${slug}.oddington.ai`;
2429
+ } catch {
2430
+ return !1;
2431
+ }
2432
+ }
2433
+ function validateConfiguration(value) {
2434
+ let configuration = value;
2435
+ if (!configuration || typeof configuration.providerUrl != "string" || typeof configuration.publishableKey != "string") throw new Error("Unavailable");
2436
+ let url = new URL(configuration.providerUrl);
2437
+ if (url.origin !== configuration.providerUrl || url.protocol !== "https:" || url.username || url.password || url.port || !configuration.publishableKey) throw new Error("Unavailable");
2438
+ return {
2439
+ providerUrl: url.origin,
2440
+ publishableKey: configuration.publishableKey,
2441
+ ...configuration.authorization === void 0 ? {} : { authorization: authorizationConfiguration(configuration.authorization) }
2442
+ };
2443
+ }
2444
+
2445
+ var BrowserAuthError = class extends Error {
2446
+ constructor(reason) {
2447
+ super(`Browser authentication failed: ${reason}`);
2448
+ this.reason = reason;
2449
+ this.name = "BrowserAuthError";
2450
+ }
2451
+ reason;
2452
+ };
2453
+ async function provider(configuration, guard) {
2454
+ let { AuthClient } = await import("./auth-provider.js");
2455
+ if (!guard.current(guard.revision())) throw new BrowserAuthError("stale");
2456
+ let provenance = /* @__PURE__ */ new Map(), removalRevision, authorizationRequest, authorizationQueue = Promise.resolve(), storage = globalThis.localStorage, client = new AuthClient({
2457
+ url: `${configuration.providerUrl}/auth/v1`,
2458
+ headers: { apikey: configuration.publishableKey, Authorization: `Bearer ${configuration.publishableKey}` },
2459
+ storageKey: `sb-${new URL(configuration.providerUrl).hostname.split(".")[0]}-auth-token`,
2460
+ persistSession: !0,
2461
+ autoRefreshToken: !0,
2462
+ detectSessionInUrl: !1,
2463
+ storage: {
2464
+ getItem: (key) => storage.getItem(key),
2465
+ removeItem(key) {
2466
+ if (!guard.current(removalRevision ?? guard.revision())) throw new BrowserAuthError("stale");
2467
+ storage.removeItem(key);
2468
+ },
2469
+ setItem(key, value) {
2470
+ let token = JSON.parse(value).access_token, revision = token ? provenance.get(token) : void 0;
2471
+ if (!guard.current(revision ?? guard.revision()) || token && !guard.canPersistSession()) throw new BrowserAuthError("stale");
2472
+ storage.setItem(key, value);
2473
+ }
2474
+ },
2475
+ fetch: Object.assign(async (input, init2) => {
2476
+ let revision = guard.revision(), request = String(input).startsWith(`${configuration.providerUrl}/auth/v1/oauth/authorizations/`) ? authorizationRequest : void 0, rejectStale = () => {
2477
+ throw request && (request.rejected = !0), new BrowserAuthError("stale");
2478
+ };
2479
+ request && (!request.current() || !guard.canAuthorize(new Headers(init2?.headers).get("authorization")?.replace(/^Bearer /, "") ?? "")) && rejectStale();
2480
+ let response = await fetch(input, { ...init2, redirect: "error" }), body2 = await response.arrayBuffer();
2481
+ (!guard.current(revision) || request && !request.current()) && rejectStale();
2482
+ let result2 = new Response(
2483
+ [204, 205, 304].includes(response.status) ? null : body2,
2484
+ { status: response.status, statusText: response.statusText, headers: response.headers }
2485
+ ), json2 = result2.json.bind(result2);
2486
+ return result2.json = async () => {
2487
+ let value = await json2();
2488
+ return (!guard.current(revision) || request && !request.current()) && rejectStale(), value && typeof value.access_token == "string" && provenance.set(value.access_token, revision), value;
2489
+ }, result2;
2490
+ }, { preconnect: fetch.preconnect })
2491
+ });
2492
+ async function authorization(kind, id2, current2) {
2493
+ let previous = authorizationQueue, release;
2494
+ authorizationQueue = new Promise((resolve) => {
2495
+ release = resolve;
2496
+ }), await previous;
2497
+ let request = { current: current2, rejected: !1 };
2498
+ authorizationRequest = request;
2499
+ try {
2500
+ if (!current2()) throw new BrowserAuthError("stale");
2501
+ let result2 = await (kind === "get" ? client.oauth.getAuthorizationDetails(id2) : kind === "approve" ? client.oauth.approveAuthorization(id2, { skipBrowserRedirect: !0 }) : client.oauth.denyAuthorization(id2, { skipBrowserRedirect: !0 }));
2502
+ if (request.rejected || !current2()) throw new BrowserAuthError("stale");
2503
+ return result2;
2504
+ } catch (error) {
2505
+ throw request.rejected || !current2() ? new BrowserAuthError("stale") : error;
2506
+ } finally {
2507
+ authorizationRequest = void 0, release();
2508
+ }
2509
+ }
2510
+ return {
2511
+ authorization: {
2512
+ get: (id2, current2) => authorization("get", id2, current2),
2513
+ approve: (id2, current2) => authorization("approve", id2, current2),
2514
+ deny: (id2, current2) => authorization("deny", id2, current2)
2515
+ },
2516
+ getSession: () => client.getSession(),
2517
+ onAuthStateChange: (callback) => client.onAuthStateChange((event2, session) => {
2518
+ let revision = session ? provenance.get(session.access_token) : void 0;
2519
+ revision !== void 0 && !guard.current(revision) || (callback(event2, session), session && provenance.delete(session.access_token));
2520
+ }),
2521
+ signInWithOtp: (input) => client.signInWithOtp(input),
2522
+ verifyOtp: (input) => client.verifyOtp(input),
2523
+ async signOut(input) {
2524
+ removalRevision = guard.revision();
2525
+ try {
2526
+ return await client.signOut(input);
2527
+ } finally {
2528
+ removalRevision = void 0;
2529
+ }
2530
+ },
2531
+ dispose() {
2532
+ provenance.clear(), client.dispose();
2533
+ }
2534
+ };
2535
+ }
2536
+ var auth = /* @__PURE__ */ createBrowserAuth({ provider, failure: (reason) => new BrowserAuthError(reason) });
2537
+
1890
2538
  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}$/i, isReason = (value) => value === "authority_unavailable" || value === "execution_unavailable" || value === "invalid_input", AppRoutineError = class extends Error {
1891
2539
  constructor(reason) {
1892
2540
  super(reason);
@@ -2070,7 +2718,7 @@ var app = Object.freeze({ routines: new Proxy(/* @__PURE__ */ Object.create(null
2070
2718
  deleteProperty: () => !1
2071
2719
  }) });
2072
2720
 
2073
- var LIMIT = 16 * 1024, context;
2721
+ var LIMIT2 = 16 * 1024, context;
2074
2722
  var appRun = {
2075
2723
  current() {
2076
2724
  return context;
@@ -2091,7 +2739,7 @@ function validateCsvHints(value) {
2091
2739
  return v;
2092
2740
  }
2093
2741
 
2094
- function routinePublicationClient(options = {}) {
2742
+ function routinePublicationClient2(options = {}) {
2095
2743
  let environment = {}, local = void 0, workspace = options.workspace ?? environment.ODDINGTON_ROUTINE_WORKSPACE, capability = options.capability ?? environment.ODDINGTON_ROUTINE_RUN;
2096
2744
  if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
2097
2745
  throw new Error("A workspace and valid optional routine capability are required");
@@ -2159,6 +2807,7 @@ function routinePublicationClient(options = {}) {
2159
2807
  export {
2160
2808
  AirtableOperationError,
2161
2809
  AppRoutineError,
2810
+ BrowserAuthError,
2162
2811
  DataOperationError,
2163
2812
  FileOperationError,
2164
2813
  InboxContractError,
@@ -2166,10 +2815,13 @@ export {
2166
2815
  app,
2167
2816
  appRun,
2168
2817
  asksBlock,
2818
+ auth,
2169
2819
  connections,
2170
2820
  continueAsk,
2171
2821
  data,
2172
2822
  defineHandler,
2823
+ defineRoutine,
2824
+ file,
2173
2825
  fileBlock,
2174
2826
  files,
2175
2827
  os,
@@ -2179,6 +2831,7 @@ export {
2179
2831
  resolveAsk,
2180
2832
  respond,
2181
2833
  richTextBlock,
2182
- routinePublicationClient,
2834
+ routinePublicationClient2 as routinePublicationClient,
2835
+ schema,
2183
2836
  selection
2184
2837
  };