@oddington/sdk 0.1.34 → 0.1.35

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
@@ -1,14 +1,49 @@
1
+ var fileValidationReasons = {
2
+ invalid_metadata: "File metadata must contain only the supported fields.",
3
+ invalid_name: "File name must be 1\u2013255 characters, with no reserved names, path separators, control characters or trailing spaces/dots.",
4
+ invalid_path: "File path must contain safe relative folder names and cannot start with .os.",
5
+ invalid_storage: "File storage must be local or remote.",
6
+ invalid_media_type: "File media type must name one valid type/subtype.",
7
+ invalid_size: "File size must be a non-negative safe integer byte count.",
8
+ invalid_request_key: "File request key must contain 1\u2013256 characters, with no surrounding whitespace or control characters.",
9
+ invalid_enrichment_name: "Enrichment name must be a safe filename and cannot be original or original.*.",
10
+ invalid_replacement: "Enrichment replacement must be a SHA-256 hash of 64 lowercase hexadecimal characters.",
11
+ invalid_bytes: "File content must contain byte chunks."
12
+ };
13
+ function parseFileErrorDetail(value) {
14
+ if (!value || typeof value != "object" || Array.isArray(value)) return;
15
+ let v = value;
16
+ if (typeof v.reason != "string") return;
17
+ if (Object.hasOwn(fileValidationReasons, v.reason))
18
+ return Object.keys(v).length === 1 ? { reason: v.reason } : void 0;
19
+ if (v.reason !== "size_mismatch" && v.reason !== "size_limit") return;
20
+ let count = v.reason === "size_mismatch" ? "expectedBytes" : "limitBytes";
21
+ if (!(Object.keys(v).some((key) => !["reason", count, "receivedBytes", "receivedAtLeast"].includes(key)) || !Number.isSafeInteger(v[count]) || v[count] < 0 || !Number.isSafeInteger(v.receivedBytes) || v.receivedBytes < 0 || v.receivedAtLeast !== void 0 && v.receivedAtLeast !== !0))
22
+ return {
23
+ reason: v.reason,
24
+ [count]: v[count],
25
+ receivedBytes: v.receivedBytes,
26
+ ...v.receivedAtLeast ? { receivedAtLeast: !0 } : {}
27
+ };
28
+ }
29
+ function fileErrorExplanation(detail) {
30
+ return detail.reason === "size_mismatch" ? `File byte count mismatch: expected ${detail.expectedBytes} bytes; received ${detail.receivedAtLeast ? "at least " : ""}${detail.receivedBytes} bytes.` : detail.reason === "size_limit" ? `File size exceeds the ${detail.limitBytes}-byte limit; received ${detail.receivedAtLeast ? "at least " : ""}${detail.receivedBytes} bytes.` : fileValidationReasons[detail.reason];
31
+ }
1
32
  var FileOperationError = class extends Error {
2
- constructor(code, status, retryable = !1) {
3
- super(code);
33
+ constructor(code, status, retryable = !1, detail) {
34
+ let safe = ["invalid_input", "request_too_large"].includes(code) ? parseFileErrorDetail(detail) : void 0;
35
+ super(safe ? `${code}: ${fileErrorExplanation(safe)}` : code);
4
36
  this.code = code;
5
37
  this.status = status;
6
38
  this.retryable = retryable;
39
+ safe && (this.detail = Object.freeze(safe));
7
40
  }
8
41
  code;
9
42
  status;
10
43
  retryable;
11
- }, 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;
44
+ detail;
45
+ };
46
+ var 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;
12
47
  function parseFileDescriptor(value) {
13
48
  let invalid9 = () => {
14
49
  throw new FileOperationError("unavailable", 503, !0);
@@ -34,13 +69,22 @@ function safeEnrichmentName(value) {
34
69
  return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
35
70
  }
36
71
  function parseFileEnrichMetadata(value, maxBytes) {
37
- let invalid9 = () => {
38
- throw new FileOperationError("invalid_input", 400);
72
+ let invalid9 = (reason = "invalid_metadata") => {
73
+ throw new FileOperationError("invalid_input", 400, !1, { reason });
39
74
  };
40
75
  if (!value || typeof value != "object" || Array.isArray(value)) return invalid9();
41
76
  let d = value;
42
- 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 invalid9();
43
- if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
77
+ if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key))) return invalid9();
78
+ if (!safeEnrichmentName(d.name)) return invalid9("invalid_enrichment_name");
79
+ if (!Number.isSafeInteger(d.size) || d.size < 0) return invalid9("invalid_size");
80
+ if (d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType))) return invalid9("invalid_media_type");
81
+ if (d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid9("invalid_replacement");
82
+ if (d.size > maxBytes) throw new FileOperationError(
83
+ "request_too_large",
84
+ 413,
85
+ !1,
86
+ { reason: "size_limit", limitBytes: maxBytes, receivedBytes: d.size }
87
+ );
44
88
  return d;
45
89
  }
46
90
  function safeFileName(value) {
@@ -54,9 +98,9 @@ function safeManagedFilePath(value) {
54
98
  }
55
99
  function declaredOriginalMediaType(value) {
56
100
  if (typeof value != "string" || value.length > 255 || /[\u0000-\u001f\u007f-\u009f]/.test(value))
57
- throw new FileOperationError("invalid_input", 400);
101
+ throw new FileOperationError("invalid_input", 400, !1, { reason: "invalid_media_type" });
58
102
  let normalized = value.split(";", 1)[0].trim().toLowerCase(), token = "[a-z0-9!#$%&'+.^_`|~-]+";
59
- if (!new RegExp(`^${token}/${token}$`).test(normalized)) throw new FileOperationError("invalid_input", 400);
103
+ if (!new RegExp(`^${token}/${token}$`).test(normalized)) throw new FileOperationError("invalid_input", 400, !1, { reason: "invalid_media_type" });
60
104
  return normalized;
61
105
  }
62
106
  function isCanonicalOriginalMediaType(value) {
@@ -67,18 +111,25 @@ function isCanonicalOriginalMediaType(value) {
67
111
  }
68
112
  }
69
113
  function parseFileCreateMetadata(value, maxBytes) {
70
- let invalid9 = () => {
71
- throw new FileOperationError("invalid_input", 400);
114
+ let invalid9 = (reason = "invalid_metadata") => {
115
+ throw new FileOperationError("invalid_input", 400, !1, { reason });
72
116
  };
73
117
  if (!value || typeof value != "object" || Array.isArray(value)) return invalid9();
74
118
  let input = value;
75
119
  if (Object.keys(input).some((key) => !["name", "path", "storage", "mediaType", "size", "requestKey"].includes(key))) return invalid9();
76
120
  let path = input.path === void 0 ? "Files" : input.path;
77
- if (!safeFileName(input.name) || !safeManagedFilePath(path) || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local") return invalid9();
121
+ if (!safeFileName(input.name)) return invalid9("invalid_name");
122
+ if (!safeManagedFilePath(path)) return invalid9("invalid_path");
123
+ if (input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local") return invalid9("invalid_storage");
78
124
  let mediaType = input.mediaType === void 0 ? "application/octet-stream" : declaredOriginalMediaType(input.mediaType);
79
- if (!Number.isSafeInteger(input.size) || input.size < 0) return invalid9();
80
- if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
81
- return typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey) ? invalid9() : {
125
+ if (!Number.isSafeInteger(input.size) || input.size < 0) return invalid9("invalid_size");
126
+ if (input.size > maxBytes) throw new FileOperationError(
127
+ "request_too_large",
128
+ 413,
129
+ !1,
130
+ { reason: "size_limit", limitBytes: maxBytes, receivedBytes: input.size }
131
+ );
132
+ return typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey) ? invalid9("invalid_request_key") : {
82
133
  name: input.name,
83
134
  path,
84
135
  ...input.storage ? { storage: input.storage } : {},
@@ -88,6 +139,116 @@ function parseFileCreateMetadata(value, maxBytes) {
88
139
  };
89
140
  }
90
141
 
142
+ var AppRoutineContractError = class extends Error {
143
+ constructor(code) {
144
+ super(code);
145
+ this.code = code;
146
+ }
147
+ code;
148
+ }, 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])/;
149
+ function isAppRoutineName(value) {
150
+ return typeof value == "string" && routineName.test(value);
151
+ }
152
+ var owns = (value, key) => Object.hasOwn(value, key), invalidContract = () => {
153
+ throw new AppRoutineContractError("invalid_contract");
154
+ }, invalidValue = () => {
155
+ throw new AppRoutineContractError("invalid_value");
156
+ };
157
+ function record(value) {
158
+ return value !== null && typeof value == "object" && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
159
+ }
160
+ function fields(value, required, optional = []) {
161
+ return required.every((key) => owns(value, key)) && Object.keys(value).every((key) => required.includes(key) || optional.includes(key));
162
+ }
163
+ function denseArray(value) {
164
+ return Array.isArray(value) && Object.keys(value).length === value.length && Array.from({ length: value.length }, (_, index) => owns(value, String(index))).every(Boolean);
165
+ }
166
+ function parseAppRoutineContract(value) {
167
+ let properties = 0;
168
+ function schema2(value2, depth = 1) {
169
+ if (depth > 8 || !record(value2)) return invalidContract();
170
+ switch (value2.type) {
171
+ case "object": {
172
+ if (!fields(value2, ["type", "properties", "additionalProperties"], ["required"]) || value2.additionalProperties !== !1 || !record(value2.properties)) return invalidContract();
173
+ let entries = Object.entries(value2.properties);
174
+ if (properties += entries.length, properties > 64 || entries.some(([key]) => !propertyName.test(key))) return invalidContract();
175
+ let required;
176
+ if (owns(value2, "required")) {
177
+ 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();
178
+ required = [...value2.required];
179
+ }
180
+ return {
181
+ type: "object",
182
+ properties: Object.fromEntries(entries.map(([key, child]) => [key, schema2(child, depth + 1)])),
183
+ ...required === void 0 ? {} : { required },
184
+ additionalProperties: !1
185
+ };
186
+ }
187
+ case "array":
188
+ return !fields(value2, ["type", "items", "maxItems"]) || !Number.isSafeInteger(value2.maxItems) || value2.maxItems < 1 || value2.maxItems > 64 ? invalidContract() : { type: "array", items: schema2(value2.items, depth + 1), maxItems: value2.maxItems };
189
+ case "boolean":
190
+ return fields(value2, ["type"]) ? { type: value2.type } : invalidContract();
191
+ case "file":
192
+ return !fields(value2, ["type"], ["storage", "path"]) || owns(value2, "storage") && value2.storage !== "local" && value2.storage !== "remote" || owns(value2, "path") && !safeManagedFilePath(value2.path) ? invalidContract() : {
193
+ type: "file",
194
+ ...owns(value2, "storage") ? { storage: value2.storage } : {},
195
+ ...owns(value2, "path") ? { path: value2.path } : {}
196
+ };
197
+ case "string":
198
+ return !fields(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 } : {} };
199
+ case "integer":
200
+ case "number": {
201
+ let validNumber = value2.type === "integer" ? Number.isSafeInteger : Number.isFinite;
202
+ return !fields(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() : {
203
+ type: value2.type,
204
+ ...owns(value2, "minimum") ? { minimum: value2.minimum } : {},
205
+ ...owns(value2, "maximum") ? { maximum: value2.maximum } : {}
206
+ };
207
+ }
208
+ default:
209
+ return invalidContract();
210
+ }
211
+ }
212
+ if (!record(value) || !fields(value, ["routine", "input", "steps"], ["result"]) || !isAppRoutineName(value.routine) || !denseArray(value.steps) || value.steps.length < 1 || value.steps.length > 64) return invalidContract();
213
+ 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) || !fields(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) } : {} }));
214
+ return { routine: value.routine, input, steps, ...result2 === void 0 ? {} : { result: result2 } };
215
+ }
216
+ function jsonData(value, ancestors = /* @__PURE__ */ new Set()) {
217
+ if (!(value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value))) {
218
+ if (!record(value) && !denseArray(value) || ancestors.has(value)) return invalidValue();
219
+ ancestors.add(value);
220
+ for (let child of Object.values(value)) jsonData(child, ancestors);
221
+ ancestors.delete(value);
222
+ }
223
+ }
224
+ function validateRoutineSchemaValue(schema2, value) {
225
+ switch (schema2.type) {
226
+ case "object":
227
+ if (!record(value) || (schema2.required ?? []).some((key) => !owns(value, key)) || Object.keys(value).some((key) => !owns(schema2.properties, key))) return invalidValue();
228
+ for (let [key, child] of Object.entries(value)) validateRoutineSchemaValue(schema2.properties[key], child);
229
+ return;
230
+ case "array":
231
+ if (!denseArray(value) || value.length > schema2.maxItems) return invalidValue();
232
+ for (let child of value) validateRoutineSchemaValue(schema2.items, child);
233
+ return;
234
+ case "boolean":
235
+ return typeof value != "boolean" ? invalidValue() : void 0;
236
+ case "string":
237
+ return typeof value != "string" || Array.from(value).length > (schema2.maxLength ?? 4096) ? invalidValue() : void 0;
238
+ case "integer":
239
+ case "number":
240
+ 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;
241
+ case "file":
242
+ try {
243
+ jsonData(value);
244
+ let file2 = parseFileDescriptor(value);
245
+ if (schema2.path !== void 0 && file2.path !== schema2.path) return invalidValue();
246
+ } catch {
247
+ return invalidValue();
248
+ }
249
+ }
250
+ }
251
+
91
252
  var InboxContractError = class extends Error {
92
253
  constructor(message2) {
93
254
  super(message2), this.name = "InboxContractError";
@@ -157,7 +318,7 @@ function validateInboxFile(value) {
157
318
  let size = natural(v.size, "file size");
158
319
  return size > FILE_ORIGINAL_MAX_BYTES && fail("File exceeds supported size"), { id: fileId, name: name2, mediaType, size, sha256: v.sha256 };
159
320
  }
160
- function fields(value) {
321
+ function fields2(value) {
161
322
  let result2 = array(value, "selected fields").map((entry) => {
162
323
  let field = object(entry, "field");
163
324
  return keys(field, ["label", "value"], "field"), { label: text(field.label, "field label"), value: text(field.value, "field value") };
@@ -184,7 +345,7 @@ function validateBlock(value) {
184
345
  label,
185
346
  ...target,
186
347
  ...expanded,
187
- record: { ref: id(r.ref, "record reference"), title: text(r.title, "record title"), fields: fields(r.fields) }
348
+ record: { ref: id(r.ref, "record reference"), title: text(r.title, "record title"), fields: fields2(r.fields) }
188
349
  };
189
350
  }
190
351
  if (b.kind === "records") {
@@ -194,7 +355,7 @@ function validateBlock(value) {
194
355
  ref: id(r.ref, "record reference"),
195
356
  title: text(r.title, "record title"),
196
357
  ...r.description === void 0 ? {} : { description: text(r.description, "record description") },
197
- ...r.facts === void 0 ? {} : { facts: fields(r.facts) },
358
+ ...r.facts === void 0 ? {} : { facts: fields2(r.facts) },
198
359
  ...r.view === void 0 ? {} : { view: id(r.view, "row View target") }
199
360
  };
200
361
  });
@@ -452,138 +613,6 @@ function createInboxPublisher(transport) {
452
613
  };
453
614
  }
454
615
 
455
- var REPOSITORY = /^[a-z0-9][a-z0-9._/-]{0,127}$/;
456
- function validRepositoryAlias(value) {
457
- return typeof value == "string" && REPOSITORY.test(value) && !value.includes("//") && !value.includes("..");
458
- }
459
-
460
- var RECORD_READ_INPUT_LIMIT = 1024 * 1024, RECORD_CAPTURE_OUTPUT_LIMIT = 25 * 1024 * 1024;
461
- function validRecordRef(value) {
462
- return typeof value == "string" && value.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)+$/.test(value);
463
- }
464
- function validateRecordRead(value) {
465
- if (!value || typeof value != "object" || Array.isArray(value))
466
- throw new InboxContractError("Invalid selected-record read");
467
- let input = value;
468
- if (Object.keys(input).some((key) => !["repository", "refs", "atCommit"].includes(key)) || !validRepositoryAlias(input.repository) || !Array.isArray(input.refs) || !input.refs.length || input.refs.length > 1e4 || input.refs.some((ref) => !validRecordRef(ref)) || new Set(input.refs).size !== input.refs.length || input.atCommit !== void 0 && (typeof input.atCommit != "string" || !/^[0-9a-f]{40}$/.test(input.atCommit)))
469
- throw new InboxContractError("Invalid selected-record read");
470
- return {
471
- repository: input.repository,
472
- refs: [...input.refs],
473
- ...input.atCommit === void 0 ? {} : { atCommit: input.atCommit }
474
- };
475
- }
476
-
477
- var AppRoutineContractError = class extends Error {
478
- constructor(code) {
479
- super(code);
480
- this.code = code;
481
- }
482
- code;
483
- }, 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])/;
484
- function isAppRoutineName(value) {
485
- return typeof value == "string" && routineName.test(value);
486
- }
487
- var owns = (value, key) => Object.hasOwn(value, key), invalidContract = () => {
488
- throw new AppRoutineContractError("invalid_contract");
489
- }, invalidValue = () => {
490
- throw new AppRoutineContractError("invalid_value");
491
- };
492
- function record(value) {
493
- return value !== null && typeof value == "object" && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
494
- }
495
- function fields2(value, required, optional = []) {
496
- return required.every((key) => owns(value, key)) && Object.keys(value).every((key) => required.includes(key) || optional.includes(key));
497
- }
498
- function denseArray(value) {
499
- return Array.isArray(value) && Object.keys(value).length === value.length && Array.from({ length: value.length }, (_, index) => owns(value, String(index))).every(Boolean);
500
- }
501
- function parseAppRoutineContract(value) {
502
- let properties = 0;
503
- function schema2(value2, depth = 1) {
504
- if (depth > 8 || !record(value2)) return invalidContract();
505
- switch (value2.type) {
506
- case "object": {
507
- if (!fields2(value2, ["type", "properties", "additionalProperties"], ["required"]) || value2.additionalProperties !== !1 || !record(value2.properties)) return invalidContract();
508
- let entries = Object.entries(value2.properties);
509
- if (properties += entries.length, properties > 64 || entries.some(([key]) => !propertyName.test(key))) return invalidContract();
510
- let required;
511
- if (owns(value2, "required")) {
512
- 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();
513
- required = [...value2.required];
514
- }
515
- return {
516
- type: "object",
517
- properties: Object.fromEntries(entries.map(([key, child]) => [key, schema2(child, depth + 1)])),
518
- ...required === void 0 ? {} : { required },
519
- additionalProperties: !1
520
- };
521
- }
522
- case "array":
523
- 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 };
524
- case "boolean":
525
- return fields2(value2, ["type"]) ? { type: value2.type } : invalidContract();
526
- case "file":
527
- return !fields2(value2, ["type"], ["storage", "path"]) || owns(value2, "storage") && value2.storage !== "local" && value2.storage !== "remote" || owns(value2, "path") && !safeManagedFilePath(value2.path) ? invalidContract() : {
528
- type: "file",
529
- ...owns(value2, "storage") ? { storage: value2.storage } : {},
530
- ...owns(value2, "path") ? { path: value2.path } : {}
531
- };
532
- case "string":
533
- 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 } : {} };
534
- case "integer":
535
- case "number": {
536
- let validNumber = value2.type === "integer" ? Number.isSafeInteger : Number.isFinite;
537
- 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() : {
538
- type: value2.type,
539
- ...owns(value2, "minimum") ? { minimum: value2.minimum } : {},
540
- ...owns(value2, "maximum") ? { maximum: value2.maximum } : {}
541
- };
542
- }
543
- default:
544
- return invalidContract();
545
- }
546
- }
547
- if (!record(value) || !fields2(value, ["routine", "input", "steps"], ["result"]) || !isAppRoutineName(value.routine) || !denseArray(value.steps) || value.steps.length < 1 || value.steps.length > 64) return invalidContract();
548
- 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) } : {} }));
549
- return { routine: value.routine, input, steps, ...result2 === void 0 ? {} : { result: result2 } };
550
- }
551
- function jsonData(value, ancestors = /* @__PURE__ */ new Set()) {
552
- if (!(value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value))) {
553
- if (!record(value) && !denseArray(value) || ancestors.has(value)) return invalidValue();
554
- ancestors.add(value);
555
- for (let child of Object.values(value)) jsonData(child, ancestors);
556
- ancestors.delete(value);
557
- }
558
- }
559
- function validateRoutineSchemaValue(schema2, value) {
560
- switch (schema2.type) {
561
- case "object":
562
- if (!record(value) || (schema2.required ?? []).some((key) => !owns(value, key)) || Object.keys(value).some((key) => !owns(schema2.properties, key))) return invalidValue();
563
- for (let [key, child] of Object.entries(value)) validateRoutineSchemaValue(schema2.properties[key], child);
564
- return;
565
- case "array":
566
- if (!denseArray(value) || value.length > schema2.maxItems) return invalidValue();
567
- for (let child of value) validateRoutineSchemaValue(schema2.items, child);
568
- return;
569
- case "boolean":
570
- return typeof value != "boolean" ? invalidValue() : void 0;
571
- case "string":
572
- return typeof value != "string" || Array.from(value).length > (schema2.maxLength ?? 4096) ? invalidValue() : void 0;
573
- case "integer":
574
- case "number":
575
- 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;
576
- case "file":
577
- try {
578
- jsonData(value);
579
- let file2 = parseFileDescriptor(value);
580
- if (schema2.path !== void 0 && file2.path !== schema2.path) return invalidValue();
581
- } catch {
582
- return invalidValue();
583
- }
584
- }
585
- }
586
-
587
616
  var ROUTINE_DECLARATION_SCHEMA = "https://schemas.oddington.ai/routine/v1.json", ROUTINE_SOURCE_LIMITS = { files: 2e4, bytes: 256 * 1024 * 1024, declarationBytes: 64 * 1024 };
588
617
  var invalid = (field) => {
589
618
  throw new Error(`Invalid routine declaration: ${field}`);
@@ -603,11 +632,9 @@ function parseRoutineDeclaration(value) {
603
632
  (!routineAlias(key) || !["read", "write"].includes(repositories[key])) && invalid(`access.repositories.${key}`), grants[key] = repositories[key];
604
633
  access.files !== void 0 && !["read", "read-write"].includes(access.files) && invalid("access.files");
605
634
  let runtime = object2(v.runtime === void 0 ? {} : v.runtime, ["features", "resources", "maxDuration"], "runtime");
606
- runtime.resources !== void 0 && !["standard", "large"].includes(runtime.resources) && invalid("runtime.resources");
607
- let duration = runtime.maxDuration === void 0 ? "15m" : runtime.maxDuration;
608
- (typeof duration != "string" || !/^(?:[1-5][0-9]|60)m$/.test(duration) || Number(duration.slice(0, -1)) < 15) && invalid("runtime.maxDuration");
609
- let retry = object2(v.retry === void 0 ? {} : v.retry, ["maxAttempts"], "retry"), maxAttempts = retry.maxAttempts === void 0 ? 1 : retry.maxAttempts;
610
- (!Number.isInteger(maxAttempts) || maxAttempts < 1 || maxAttempts > 3) && invalid("retry.maxAttempts");
635
+ runtime.features !== void 0 && (!Array.isArray(runtime.features) || runtime.features.length !== 0) && invalid("runtime.features"), runtime.resources !== void 0 && runtime.resources !== "standard" && invalid("runtime.resources"), runtime.maxDuration !== void 0 && runtime.maxDuration !== "15m" && invalid("runtime.maxDuration");
636
+ let retry = object2(v.retry === void 0 ? {} : v.retry, ["maxAttempts"], "retry");
637
+ retry.maxAttempts !== void 0 && retry.maxAttempts !== 1 && invalid("retry.maxAttempts");
611
638
  let assets = v.assets === void 0 ? [] : v.assets;
612
639
  return (!Array.isArray(assets) || assets.length > 64 || assets.some((item) => !routineAssetPattern(item)) || new Set(assets).size !== assets.length) && invalid("assets"), {
613
640
  $schema: ROUTINE_DECLARATION_SCHEMA,
@@ -618,12 +645,8 @@ function parseRoutineDeclaration(value) {
618
645
  ...access.files === void 0 ? {} : { files: access.files },
619
646
  publish: list(access.publish, "access.publish", ["asks", "digests"])
620
647
  },
621
- runtime: {
622
- features: list(runtime.features, "runtime.features", ["python", "documents", "browser"]),
623
- resources: runtime.resources ?? "standard",
624
- maxDuration: duration
625
- },
626
- retry: { maxAttempts },
648
+ runtime: { features: [], resources: "standard", maxDuration: "15m" },
649
+ retry: { maxAttempts: 1 },
627
650
  assets: [...assets].sort()
628
651
  };
629
652
  }
@@ -947,6 +970,11 @@ var DataOperationError = class extends Error {
947
970
  component;
948
971
  };
949
972
 
973
+ var RECORD_READ_INPUT_LIMIT = 1024 * 1024, RECORD_CAPTURE_OUTPUT_LIMIT = 25 * 1024 * 1024;
974
+ function validRecordRef(value) {
975
+ return typeof value == "string" && value.length <= 512 && /^[_a-zA-Z0-9][a-zA-Z0-9_-]*(\/[_a-zA-Z0-9][a-zA-Z0-9_-]*)+$/.test(value);
976
+ }
977
+
950
978
  var invalid4 = () => {
951
979
  throw new DataOperationError("invalid_query");
952
980
  }, historyText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
@@ -1471,8 +1499,13 @@ async function boundedBytes(stream, limit, signal) {
1471
1499
  let { done, value } = await reader.read();
1472
1500
  if (signal?.aborted) throw unavailable2();
1473
1501
  if (done) break;
1474
- if (!(value instanceof Uint8Array)) throw invalid7();
1475
- if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
1502
+ if (!(value instanceof Uint8Array)) throw new FileOperationError("invalid_input", 400, !1, { reason: "invalid_bytes" });
1503
+ if (size += value.byteLength, size > limit) throw new FileOperationError(
1504
+ "request_too_large",
1505
+ 413,
1506
+ !1,
1507
+ { reason: "size_limit", limitBytes: limit, receivedBytes: size, receivedAtLeast: !0 }
1508
+ );
1476
1509
  bytes.set(value, size - value.byteLength);
1477
1510
  }
1478
1511
  } catch (error) {
@@ -1524,7 +1557,12 @@ async function send(suffix, init2, descriptor, initial, parent) {
1524
1557
  })();
1525
1558
  if (!response2.ok) {
1526
1559
  let value2 = await result(response2), 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[response2.status]?.find((code2) => code2 === received);
1527
- throw code ? new FileOperationError(code, response2.status, code === "capacity" || code === "unavailable") : unavailable2();
1560
+ throw code ? new FileOperationError(
1561
+ code,
1562
+ response2.status,
1563
+ code === "capacity" || code === "unavailable",
1564
+ parseFileErrorDetail(error?.detail)
1565
+ ) : unavailable2();
1528
1566
  }
1529
1567
  if (response2.status !== (descriptor === 204 ? 204 : 200) || descriptor === 204 && response2.body !== null)
1530
1568
  throw response2.body?.cancel().catch(() => {
@@ -1588,7 +1626,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1588
1626
  };
1589
1627
  for (let sent = 0, partNumber = 1; sent < metadata.size || metadata.size === 0 && partNumber === 1; partNumber++) {
1590
1628
  let length = Math.min(PART_BYTES, metadata.size - sent), part;
1591
- if (input.file instanceof Uint8Array) part = input.file.subarray(sent, sent + length).slice();
1629
+ if (input.file instanceof Uint8Array) part = new Uint8Array(input.file.subarray(sent, sent + length));
1592
1630
  else if (input.file instanceof Blob) {
1593
1631
  let slice = input.file.slice(sent, sent + length);
1594
1632
  part = new Uint8Array(await request2(() => slice.arrayBuffer()));
@@ -1717,7 +1755,13 @@ var files = {
1717
1755
  let blob = input.file instanceof Blob, array3 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
1718
1756
  if (!blob && !array3 && !stream) throw invalid7();
1719
1757
  let intrinsic = blob ? input.file.size : array3 ? input.file.byteLength : void 0;
1720
- if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid7();
1758
+ if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic)
1759
+ throw !Number.isSafeInteger(input.size) || input.size < 0 ? new FileOperationError("invalid_input", 400, !1, { reason: "invalid_size" }) : new FileOperationError(
1760
+ "invalid_input",
1761
+ 400,
1762
+ !1,
1763
+ { reason: "size_mismatch", expectedBytes: input.size, receivedBytes: intrinsic }
1764
+ );
1721
1765
  let name2 = input.name;
1722
1766
  name2 === void 0 && blob && "name" in input.file && typeof input.file.name == "string" && (name2 = typeof globalThis.File < "u" && input.file instanceof globalThis.File ? input.file.name : input.file.name.split(/[\\/]/).at(-1));
1723
1767
  let mediaType = declaredOriginalMediaType(input.mediaType === void 0 ? blob && input.file.type ? input.file.type : "application/octet-stream" : input.mediaType), metadata = parseFileCreateMetadata({
@@ -1754,12 +1798,17 @@ var files = {
1754
1798
  }
1755
1799
  return metadata.size > MAX_BYTES ? multipartCreate(input, metadata, (suffix, init2, kind, signal) => kind === !0 ? send(suffix, init2, !0, context, signal) : send(suffix, init2, "control", context, signal)) : timed(async (signal) => {
1756
1800
  try {
1757
- let bytes = array3 ? input.file.slice() : await boundedBytes(
1801
+ let bytes = array3 ? new Uint8Array(input.file) : await boundedBytes(
1758
1802
  blob ? input.file.stream() : input.file,
1759
1803
  metadata.size,
1760
1804
  signal
1761
1805
  );
1762
- if (bytes.byteLength !== metadata.size) throw invalid7();
1806
+ if (bytes.byteLength !== metadata.size) throw new FileOperationError(
1807
+ "invalid_input",
1808
+ 400,
1809
+ !1,
1810
+ { reason: "size_mismatch", expectedBytes: metadata.size, receivedBytes: bytes.byteLength }
1811
+ );
1763
1812
  if (signal.aborted) throw unavailable2();
1764
1813
  return await send("", {
1765
1814
  method: "POST",
@@ -1785,7 +1834,7 @@ var files = {
1785
1834
  let buffer = new Uint8Array(Math.min(MAX_BYTES, input.content.length * 3)), encoded = new TextEncoder().encodeInto(input.content, buffer);
1786
1835
  if (encoded.read !== input.content.length) throw new FileOperationError("request_too_large", 413);
1787
1836
  bytes = buffer.slice(0, encoded.written);
1788
- } else bytes = input.content.slice();
1837
+ } else bytes = new Uint8Array(input.content);
1789
1838
  let metadata = parseFileEnrichMetadata({
1790
1839
  name: input.name,
1791
1840
  size: bytes.byteLength,
@@ -2130,68 +2179,6 @@ var connections = /* @__PURE__ */ runtimeConnections();
2130
2179
 
2131
2180
  var LOCAL_ROUTINE_VALUE_BYTES = 256 * 1024;
2132
2181
 
2133
- var RECORD_WRITE_INPUT_LIMIT = 8 * 1024 * 1024, RoutineRecordWriteError = class extends Error {
2134
- constructor(message2, effect) {
2135
- super(message2);
2136
- this.effect = effect;
2137
- this.name = "RoutineRecordWriteError";
2138
- }
2139
- effect;
2140
- };
2141
- function validateRecordWrite(value) {
2142
- let input = serializable(value);
2143
- 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)
2144
- throw new InboxContractError("Invalid record update batch");
2145
- for (let edit of input.records) {
2146
- if (!edit || Array.isArray(edit) || typeof edit != "object" || !validRecordRef(edit.ref))
2147
- throw new InboxContractError("Invalid record edit");
2148
- if ("expectedVersion" in edit) {
2149
- 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)
2150
- throw new InboxContractError("Invalid record edit");
2151
- continue;
2152
- }
2153
- 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)
2154
- throw new InboxContractError("Invalid record creation");
2155
- }
2156
- return structuredClone(input);
2157
- }
2158
- function validateRecordUpdate(value) {
2159
- let input = validateRecordWrite(value);
2160
- if (input.records.some((record4) => !("expectedVersion" in record4)))
2161
- throw new InboxContractError("Record creation is unavailable for this operation");
2162
- return input;
2163
- }
2164
- function validateRecordDelete(value) {
2165
- let input = serializable(value);
2166
- 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((record4) => record4?.ref)).size !== input.records.length)
2167
- throw new InboxContractError("Invalid record deletion batch");
2168
- for (let record4 of input.records)
2169
- if (!record4 || Array.isArray(record4) || typeof record4 != "object" || Object.keys(record4).sort().join(",") !== "expectedVersion,ref" || !validRecordRef(record4.ref) || typeof record4.expectedVersion != "string" || !/^record-v1:[0-9a-f]{64}$/.test(record4.expectedVersion))
2170
- throw new InboxContractError("Invalid record deletion");
2171
- return structuredClone(input);
2172
- }
2173
- function validateRecordChange(value) {
2174
- let input = serializable(value);
2175
- 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((record4) => record4?.ref)).size !== input.records.length || new TextEncoder().encode(JSON.stringify(input)).byteLength > RECORD_WRITE_INPUT_LIMIT)
2176
- throw new InboxContractError("Invalid record change batch");
2177
- let writes = [], deletes = [];
2178
- for (let record4 of input.records) {
2179
- if (!record4 || typeof record4 != "object" || Array.isArray(record4))
2180
- throw new InboxContractError("Invalid record change");
2181
- "set" in record4 || "fields" in record4 ? writes.push(record4) : deletes.push(record4);
2182
- }
2183
- return writes.length && validateRecordWrite({ repository: input.repository, records: writes }), deletes.length && validateRecordDelete({ repository: input.repository, records: deletes }), structuredClone(input);
2184
- }
2185
- function validateRoutineRecordWrite(value) {
2186
- let body = serializable(value);
2187
- if (!body || typeof body != "object" || Array.isArray(body) || Object.keys(body).sort().join(",") !== "input,requestKey" || typeof body.requestKey != "string" || !body.requestKey.trim() || body.requestKey !== body.requestKey.trim() || body.requestKey.length > 512)
2188
- throw new InboxContractError("A stable routine request key is required");
2189
- return { input: validateRecordChange(body.input), requestKey: body.requestKey };
2190
- }
2191
- function validCreatePath(value) {
2192
- return value === value.trim() && value.endsWith(".md") && !value.startsWith("/") && value.split("/").every((segment) => !!segment && ![".", ".."].includes(segment) && /^[a-zA-Z0-9_.-]+$/.test(segment));
2193
- }
2194
-
2195
2182
  function locationIdentity(location) {
2196
2183
  let coordinates = location.provider === "os" ? [location.file] : location.provider === "gmail" ? [location.connection, location.message, location.attachment] : location.provider === "dropbox" ? [location.connection, location.file] : void 0;
2197
2184
  if (coordinates?.every((value) => typeof value == "string" && value.length > 0))
@@ -3008,7 +2995,15 @@ function validPair(value) {
3008
2995
  return validProof(pair.credential) && validProof(pair.renewalCredential) && pair.credential !== pair.renewalCredential && validBinding(pair.context);
3009
2996
  }
3010
2997
 
3011
- var unavailable3 = () => new InboxOperationError(503, "unavailable"), stale = () => new InboxOperationError(401, "authority_unavailable");
2998
+ var WorkspaceAdmissionError = class extends Error {
2999
+ constructor(status) {
3000
+ super("Workspace admission unavailable");
3001
+ this.status = status;
3002
+ }
3003
+ status;
3004
+ };
3005
+
3006
+ var unavailable3 = () => new InboxOperationError(503, "unavailable"), stale = () => new InboxOperationError(401, "authority_unavailable"), contextFailure = (error) => error instanceof WorkspaceAdmissionError ? new InboxOperationError(error.status, error.status === 401 ? "authority_unavailable" : error.status === 403 ? "access_denied" : "unavailable") : stale();
3012
3007
  function hostFailure(error, context) {
3013
3008
  return !context.isCurrent() || context.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") : unavailable3();
3014
3009
  }
@@ -3016,8 +3011,8 @@ async function send2(operation2, input, admitted) {
3016
3011
  let envelope = parseInboxRequest({ operation: operation2, input }), context;
3017
3012
  try {
3018
3013
  context = admitted ?? await resolveAppContext();
3019
- } catch {
3020
- throw stale();
3014
+ } catch (error) {
3015
+ throw contextFailure(error);
3021
3016
  }
3022
3017
  if (context.kind === "local") {
3023
3018
  if (!isAppQuestionOperation(operation2)) throw new InboxOperationError(403, "access_denied");
@@ -3125,8 +3120,8 @@ var inbox = {
3125
3120
  let items = [], beforeNumber, initial;
3126
3121
  try {
3127
3122
  initial = await resolveAppContext();
3128
- } catch {
3129
- throw stale();
3123
+ } catch (error) {
3124
+ throw contextFailure(error);
3130
3125
  }
3131
3126
  let host;
3132
3127
  try {
@@ -3164,8 +3159,8 @@ var inbox = {
3164
3159
  let routines = Object.freeze(supplied.routines), questions = [], beforeNumber, initial;
3165
3160
  try {
3166
3161
  initial = await resolveAppContext();
3167
- } catch {
3168
- throw stale();
3162
+ } catch (error) {
3163
+ throw contextFailure(error);
3169
3164
  }
3170
3165
  let check = () => {
3171
3166
  if (!initial.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
@@ -3215,14 +3210,15 @@ function init({ auth: input }) {
3215
3210
  }
3216
3211
  let active2 = !0, revision = 0, person, token, binding = {}, local2 = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, resolve = async () => {
3217
3212
  if (local2) return local2.resolve();
3218
- if (!active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
3213
+ if (registered && await registered.ready(), !active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
3219
3214
  let started = revision, { data: { session }, error } = await auth2.getSession();
3220
3215
  if (!active2 || globalThis.location.origin !== endpoint || started !== revision || error || !session || person !== void 0 && person !== session.user.id)
3221
3216
  throw new Error("Hosted Data context unavailable.");
3222
3217
  let expiresAt = (session.expires_at ?? 0) * 1e3;
3223
3218
  if (!Number.isFinite(expiresAt) || expiresAt <= Date.now() || !session.user.id)
3224
3219
  throw new Error("Hosted Data context unavailable.");
3225
- person = session.user.id;
3220
+ if (person = session.user.id, registered && await registered.admitWorkspace(), !active2 || globalThis.location.origin !== endpoint || started !== revision || person !== session.user.id)
3221
+ throw new Error("Hosted Data context unavailable.");
3226
3222
  let isCurrent = () => active2 && globalThis.location.origin === endpoint && revision === started && person === session.user.id;
3227
3223
  return {
3228
3224
  workspace,
@@ -3369,6 +3365,36 @@ function createBrowserAuth(runtime) {
3369
3365
  function current2(c, origin, revision) {
3370
3366
  return c.session && !validSession(c.session) && expire(c), c.active && c.revision === revision && globalThis.location?.origin === origin;
3371
3367
  }
3368
+ async function admitWorkspace(c, origin) {
3369
+ if (origin === "https://auth.oddington.ai" || origin === "http://127.0.0.1:5176") return;
3370
+ let revision = c.revision;
3371
+ if (!current2(c, origin, revision) || !c.session || c.state.pending === "sign_out") throw runtime.failure("stale");
3372
+ if (c.admission?.revision !== revision) {
3373
+ let token = c.session.access_token, result2 = (async () => {
3374
+ let status;
3375
+ try {
3376
+ let response2 = await fetch(`${origin}/api/auth`, {
3377
+ method: "POST",
3378
+ headers: { authorization: `Bearer ${token}` },
3379
+ credentials: "same-origin",
3380
+ redirect: "error",
3381
+ cache: "no-store",
3382
+ signal: AbortSignal.timeout(15e3)
3383
+ });
3384
+ status = response2.status;
3385
+ let value = status === 200 ? await response2.json() : null;
3386
+ status === 200 && value?.admitted !== !0 && (status = 503), status !== 200 && response2.body?.cancel().catch(() => {
3387
+ });
3388
+ } catch {
3389
+ status = 503;
3390
+ }
3391
+ if (!current2(c, origin, revision) || c.state.pending === "sign_out") throw runtime.failure("stale");
3392
+ if (status !== 200) throw new WorkspaceAdmissionError(status === 401 ? 401 : status === 403 ? 403 : 503);
3393
+ })();
3394
+ c.admission = { revision, result: result2 };
3395
+ }
3396
+ if (await c.admission.result, !current2(c, origin, revision)) throw runtime.failure("stale");
3397
+ }
3372
3398
  return { create() {
3373
3399
  let origin = globalThis.location?.origin ?? "", c = coordinators.get(origin);
3374
3400
  c || (c = createCoordinator(origin), coordinators.set(origin, c));
@@ -3458,7 +3484,9 @@ function createBrowserAuth(runtime) {
3458
3484
  async sendCode(email) {
3459
3485
  if (assertActive(), !validEmail(email)) throw runtime.failure("invalid_input");
3460
3486
  await action("send_code", async (provider2) => {
3461
- let { error } = await provider2.signInWithOtp({ email: email.trim(), options: { shouldCreateUser: !1 } });
3487
+ let { error } = await provider2.signInWithOtp({ email: email.trim(), options: {
3488
+ shouldCreateUser: origin !== "https://auth.oddington.ai" && origin !== "http://127.0.0.1:5176"
3489
+ } });
3462
3490
  if (error && !accountRefusal(error)) throw runtime.failure("unavailable");
3463
3491
  });
3464
3492
  },
@@ -3470,6 +3498,11 @@ function createBrowserAuth(runtime) {
3470
3498
  if (!data3.session || !validSession(data3.session)) throw runtime.failure("invalid_code");
3471
3499
  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");
3472
3500
  accept(coordinator, "SIGNED_IN", data3.session);
3501
+ try {
3502
+ await admitWorkspace(coordinator, origin);
3503
+ } catch (error2) {
3504
+ if (!(error2 instanceof WorkspaceAdmissionError)) throw error2;
3505
+ }
3473
3506
  });
3474
3507
  },
3475
3508
  async signOut() {
@@ -3495,6 +3528,12 @@ function createBrowserAuth(runtime) {
3495
3528
  }
3496
3529
  });
3497
3530
  return registerBrowserAuth(handle2, {
3531
+ async ready() {
3532
+ assertActive(), await coordinator.ready, assertActive();
3533
+ },
3534
+ async admitWorkspace() {
3535
+ assertActive(), await admitWorkspace(coordinator, origin), assertActive();
3536
+ },
3498
3537
  onDispose(callback) {
3499
3538
  return active2 ? (disposalObservers.add(callback), () => {
3500
3539
  disposalObservers.delete(callback);
@@ -3926,18 +3965,11 @@ function validateFileAddOptions(value) {
3926
3965
  return v;
3927
3966
  }
3928
3967
 
3929
- var PREPARED_RECORD_INPUT_LIMIT = 64 * 1024 * 1024;
3930
-
3931
- function routineDataEnvelope(command) {
3932
- return "apply" in command ? { operation: "changes.publish", captured: command.apply } : { operation: "changes.publish", request: command };
3933
- }
3934
-
3935
3968
  function routinePublicationClient2(options = {}) {
3936
3969
  let environment = {}, installed2 = routineTransport(), local2 = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.OS_ROUTINE_WORKSPACE, capability = options.capability ?? environment.OS_ROUTINE_RUN;
3937
3970
  if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
3938
3971
  throw new Error("A workspace and valid optional routine capability are required");
3939
3972
  let workingRoot = options.workingRoot ?? environment.OS_INBOX_WORKING_ROOT ?? void 0, headers = capability ? { "x-os-run": capability } : {}, request2 = options.request ?? (capability ? async (path, init2) => {
3940
- if (path === "/api/data") return fetch(`https://${workspace}.oddington.ai/api/data`, { ...init2, redirect: "error" });
3941
3973
  let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
3942
3974
  if (workspace.length > 63 || ["auth", "www", "api", "os"].includes(workspace) || target.origin !== origin || target.search || target.hash || target.username || target.password || !/^\/api\/inbox\/(check|publish|resolve|files)$/.test(path) || init2?.method !== "POST")
3943
3975
  throw new Error("Invalid routine endpoint");
@@ -3947,49 +3979,23 @@ function routinePublicationClient2(options = {}) {
3947
3979
  });
3948
3980
  async function send3(operation2, body) {
3949
3981
  if (local2) return await local2(operation2, body);
3950
- let writing = operation2 === "records/update", reading = operation2 === "records/read", response2 = await request2(writing || reading ? "/api/data" : `/api/inbox/${operation2}`, {
3982
+ let response2 = await request2(`/api/inbox/${operation2}`, {
3951
3983
  method: "POST",
3952
- headers: {
3953
- "content-type": "application/json",
3954
- ...headers,
3955
- ...writing || reading ? { "x-os-workspace": workspace, "x-os-captured-records": "1" } : {}
3956
- },
3957
- body: JSON.stringify(writing ? routineDataEnvelope(validateRoutineRecordWrite(body)) : reading ? { operation: "records.select", request: validateRecordRead(body) } : body)
3984
+ headers: { "content-type": "application/json", ...headers },
3985
+ body: JSON.stringify(body)
3958
3986
  }), result2 = await response2.json();
3959
- if (!response2.ok && operation2 === "records/update")
3960
- throw new RoutineRecordWriteError(result2.error ?? "Could not confirm routine preparation", result2.effect ?? "uncertain");
3961
3987
  if (!response2.ok) throw new Error(result2.error ?? "Could not confirm routine publication");
3962
3988
  return result2;
3963
3989
  }
3964
- let transport = {
3965
- async publish(body) {
3966
- return await send3("publish", body);
3967
- },
3968
- async resolve(body) {
3969
- await send3("resolve", body);
3970
- }
3971
- };
3972
- async function readRecords(input) {
3973
- return await send3("records/read", validateRecordRead(input));
3974
- }
3975
3990
  return {
3976
- ...createInboxPublisher(transport),
3977
- readRecords,
3978
- repository: {
3979
- readRecords,
3980
- async writeRecords(input, options2) {
3981
- if (!capability && !installed2) throw new Error("A trusted routine launch is required");
3982
- return await send3("records/update", validateRoutineRecordWrite({ input, requestKey: options2?.requestKey }));
3983
- },
3984
- async updateRecords(input, options2) {
3985
- if (!capability && !installed2) throw new Error("A trusted routine launch is required");
3986
- return await send3("records/update", validateRoutineRecordWrite({ input: validateRecordUpdate(input), requestKey: options2?.requestKey }));
3991
+ ...createInboxPublisher({
3992
+ async publish(body) {
3993
+ return await send3("publish", body);
3987
3994
  },
3988
- async deleteRecords(input, options2) {
3989
- if (!capability && !installed2) throw new Error("A trusted routine launch is required");
3990
- return await send3("records/update", validateRoutineRecordWrite({ input: validateRecordDelete(input), requestKey: options2?.requestKey }));
3995
+ async resolve(body) {
3996
+ await send3("resolve", body);
3991
3997
  }
3992
- },
3998
+ }),
3993
3999
  files: {
3994
4000
  async add(value) {
3995
4001
  let input = validateFileAddOptions(value);
@@ -4010,7 +4016,6 @@ export {
4010
4016
  FileOperationError,
4011
4017
  InboxContractError,
4012
4018
  InboxOperationError,
4013
- RoutineRecordWriteError,
4014
4019
  app,
4015
4020
  asksBlock,
4016
4021
  auth,