@oddington/sdk 0.1.37 → 0.1.38
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/README.md +69 -92
- package/dist/browser.js +45 -68
- package/dist/index.js +4 -4
- package/dist/types/packages/sdk/src/public.d.ts +22 -18
- package/dist/types/packages/sdk/src/routine-definition-types.d.ts +2 -2
- package/dist/types/shared/app-routine-contract.d.ts +1 -1
- package/dist/types/shared/inbox-member-contract.d.ts +1 -1
- package/dist/types/shared/inbox-member-types.d.ts +0 -6
- package/package.json +1 -1
- package/dist/types/shared/delimited-text.d.ts +0 -2
- package/dist/types/shared/inbox-files.d.ts +0 -12
package/README.md
CHANGED
|
@@ -6,11 +6,12 @@ Data and Files APIs work in browsers. Installing the package grants no authority
|
|
|
6
6
|
|
|
7
7
|
Hosted Data and shared Files reach OS directly through `/api/data` and `/api/files`.
|
|
8
8
|
Inbox owns workspace-hosted `/api/inbox/check`, `/api/inbox/publish`,
|
|
9
|
-
`/api/inbox/resolve
|
|
9
|
+
`/api/inbox/resolve`. Request-key recovery and captured
|
|
10
10
|
publication validation are internal behavior of these operations. Retrying the
|
|
11
11
|
same key and content returns the original result; changed content conflicts.
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
Inbox File previews and downloads use package-root `files.read(fileId)` with
|
|
13
|
+
current workspace access. Item visibility does not grant File access. The SDK
|
|
14
|
+
exposes no raw-credential API.
|
|
14
15
|
|
|
15
16
|
Hosted apps use `inbox.questions.list({ routines })` for `AnswerableQuestion[]`.
|
|
16
17
|
Derive `routines` from the existing app declaration with
|
|
@@ -65,7 +66,7 @@ Each step runs at most once and returns `{ summary, data }`. Unknown or repeated
|
|
|
65
66
|
steps fail the Run even if routine code catches the error; unreached steps are
|
|
66
67
|
skipped. Omitted input normalizes to `{}`. A top-level schema can supply a validated
|
|
67
68
|
immutable default with `.default(value)`, such as
|
|
68
|
-
`schema.object({ files: schema.array(file()
|
|
69
|
+
`schema.object({ files: schema.array(file()) }).default({ files: [] })`.
|
|
69
70
|
Nested defaults are unsupported and rejected. Omitted steps permit no step call;
|
|
70
71
|
omitted result permits no returned value. `file()` declares a complete OS File descriptor.
|
|
71
72
|
Its optional `storage` selects local or remote placement and its optional `path`
|
|
@@ -101,8 +102,10 @@ AI calls drain before completion. The host retains authority, isolation,
|
|
|
101
102
|
cancellation and byte limits. Local and remote Runs use the same API.
|
|
102
103
|
|
|
103
104
|
The bounded grammar supports closed objects with required properties, arrays with
|
|
104
|
-
an
|
|
105
|
+
an optional positive safe-integer `maxItems` business bound, booleans, strings (at most 4096 code points),
|
|
105
106
|
finite numbers and safe integers with optional inclusive bounds, and Files.
|
|
107
|
+
Omitting `maxItems` imposes no item-count ceiling; the complete serialized input
|
|
108
|
+
still shares the Run's byte bound, including every File descriptor and other field.
|
|
106
109
|
Definitions allow at most 64 steps, 64 total object properties across their schemas,
|
|
107
110
|
and eight schema levels. Input, each step input, each summary, each detail value,
|
|
108
111
|
and the result accept at most 256 KiB of UTF-8 serialized JSON, without truncation.
|
|
@@ -252,7 +255,7 @@ Local Data selects from the Host's exact published index; a warm selection
|
|
|
252
255
|
neither initiates nor waits for renewal or synchronous hosted authority checks.
|
|
253
256
|
Local Files returns `unsupported_context` after checking context. Neither path
|
|
254
257
|
falls back to hosted services. Local app routines use the same local execution
|
|
255
|
-
and
|
|
258
|
+
and live capability calls as the CLI.
|
|
256
259
|
|
|
257
260
|
Apps can assess a declared routine without starting it:
|
|
258
261
|
|
|
@@ -268,19 +271,17 @@ const detail = await run.step('read'); // Inferred summary and data for this new
|
|
|
268
271
|
const recent = await app.routines.receipts.runs.list();
|
|
269
272
|
const saved = await app.routines.receipts.runs.get(recent[0].id);
|
|
270
273
|
console.log(await saved.current());
|
|
271
|
-
// await saved.publish(); // Only in response to an explicit publication action.
|
|
272
274
|
```
|
|
273
275
|
|
|
274
276
|
The fixed build generates types from each routine definition; no app-authored
|
|
275
277
|
contract map is needed. Descriptions combine safe structure with live readiness
|
|
276
278
|
and connection availability. Starts validate the current definition and input;
|
|
277
|
-
retained reads
|
|
278
|
-
scope. No installation is needed. Bindings accept no endpoint, credential,
|
|
279
|
+
retained local reads check the established session and saved Run ownership. No installation is needed. Bindings accept no endpoint, credential,
|
|
279
280
|
command, path or configuration selector. A local app uses its live Local Host;
|
|
280
281
|
a hosted app uses its existing member session and workspace context to reach
|
|
281
282
|
the current remote Run owner through the same bindings. Operations reject with
|
|
282
283
|
`AppRoutineError.reason`: `authority_unavailable`, `execution_unavailable`, or
|
|
283
|
-
`invalid_input`. Starts
|
|
284
|
+
`invalid_input`. Starts are not automatically retried. A
|
|
284
285
|
disconnected watch ends and requires `current()`. History returns at most 20
|
|
285
286
|
summaries without deleting older Runs. Each JSON value is bounded to 256 KiB.
|
|
286
287
|
Transport envelopes allow 17 MiB per summary, 514 KiB per detail and 20 summaries
|
|
@@ -402,33 +403,28 @@ await files.enrich({ file: report.id, name: 'read.md', content: revisedMarkdown,
|
|
|
402
403
|
await files.upload(report.id); // Move a local File and every retained enrichment to remote storage.
|
|
403
404
|
```
|
|
404
405
|
|
|
405
|
-
Hosted Files retains remote originals and caller-produced named enrichments
|
|
406
|
-
|
|
407
|
-
`
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
retrying a completed upload returns the same File. Later reads and enrichments
|
|
422
|
-
follow remote storage; any remaining managed local bytes are disposable cache.
|
|
423
|
-
An unreferenced local File is disclosed remotely only when explicitly uploaded
|
|
424
|
-
or successfully published as a Source. An authorized hosted caller receives
|
|
425
|
-
non-retryable `local_only` (409) until upload succeeds; unrelated callers receive
|
|
426
|
-
`access_denied`.
|
|
406
|
+
Hosted Files retains remote originals and caller-produced named enrichments.
|
|
407
|
+
A managed local CLI parent stores local Files beneath the signed-in active
|
|
408
|
+
workspace's `~/.os/<workspace>/files` root; callers cannot configure another
|
|
409
|
+
root. Local Runs default new Files to local storage, hosted Runs to remote.
|
|
410
|
+
An existing local or remote File keeps its placement. Every completed File has
|
|
411
|
+
one workspace registry row, including local Files whose bytes stay on this
|
|
412
|
+
device. Request-key replay and reusable enrichments preserve the same identity
|
|
413
|
+
across member calls, Runs and restarts.
|
|
414
|
+
|
|
415
|
+
Explicit remote creation, upload and enrichment complete during their calls.
|
|
416
|
+
`upload(id)` verifies the original and every enrichment before changing the same
|
|
417
|
+
File's placement; retrying a completed upload returns that File. Later reads
|
|
418
|
+
and enrichments follow its pinned remote store. A Source reference leaves a
|
|
419
|
+
local File local. Inbox publication uploads that same File before exposing the
|
|
420
|
+
Ask or Digest. Completed effects survive later Run failure. A runtime without
|
|
421
|
+
the local bytes reports `local_only` (409).
|
|
427
422
|
Unnamed inputs require a safe `name`; streams also require declared `size`.
|
|
428
423
|
Blob and byte-array declarations must match their intrinsic size. Originals are
|
|
429
|
-
bounded to
|
|
430
|
-
|
|
431
|
-
|
|
424
|
+
bounded to 5 GiB per original and 16 MiB per enrichment. Large originals stream
|
|
425
|
+
through bounded multipart transfers; local writes and reads use bounded disk
|
|
426
|
+
buffers. Operations share four concurrent slots and idle/request deadlines;
|
|
427
|
+
transport retries preserve the same bytes and request key.
|
|
432
428
|
Omitting a key generates one for that invocation. Supply a stable key to recover
|
|
433
429
|
across processes or fresh routine runs. Caller inputs remain owned by the caller.
|
|
434
430
|
Each request resolves current authority; hosted routine Files calls use the
|
|
@@ -441,24 +437,10 @@ versus received size. Streaming rejection marks partial received counts with
|
|
|
441
437
|
failure evidence without raw names, keys, file content or provider text. Older
|
|
442
438
|
errors without `detail` remain valid. Reads return the successful Web
|
|
443
439
|
Response without consuming its body. Local transfer is bounded and buffered
|
|
444
|
-
before constructing that Response.
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
retained enrichments under its current member or installed-routine creator.
|
|
449
|
-
It returns `void` only after physical cleanup and durable completion; a completed
|
|
450
|
-
retry succeeds. Independent retention returns `conflict` without changing the
|
|
451
|
-
File. `access_denied` and `integrity` remain terminal; `unavailable` and
|
|
452
|
-
`capacity` are retryable. Pending deletion denies reads, writes, new uses and
|
|
453
|
-
creation-key replay while the same current creator retries cleanup. Deletion
|
|
454
|
-
uses the authenticated parent for managed local Files and uploaded caches.
|
|
455
|
-
R2 cleanup verifies the registered immutable key and native revision, removes
|
|
456
|
-
only that object and confirms absence. Each physical writer owns a distinct
|
|
457
|
-
candidate key, so a delayed writer cannot recreate the deleted representation.
|
|
458
|
-
Pending admission is never success.
|
|
459
|
-
When a completion reply is lost, retry `files.delete` with the same File ID and
|
|
460
|
-
current creator authority. Keep stable creation keys separate from deletion
|
|
461
|
-
recovery: a completed deleted key is denied and cannot recreate the File.
|
|
440
|
+
before constructing that Response. Current workspace members can use every File in that workspace. A
|
|
441
|
+
routine's `files: "read"` permits get/read; `files: "read-write"` also permits
|
|
442
|
+
create/enrich/upload. References in Sources, Runs and Inbox items grant no
|
|
443
|
+
additional access. Files has no public delete operation.
|
|
462
444
|
|
|
463
445
|
`enrich` accepts a string encoded as UTF-8 or exact `Uint8Array` bytes, a safe
|
|
464
446
|
flat filename, and an optional MIME hint. OS verifies text/Markdown/JSON or
|
|
@@ -570,12 +552,11 @@ Binding is inert. Each operation resolves current workspace, endpoint and
|
|
|
570
552
|
short-lived authority from the trusted app host or managed routine context.
|
|
571
553
|
Customer calls cannot configure those values. Missing or expired context
|
|
572
554
|
rejects; a named handle does not expand repository access. During
|
|
573
|
-
`os routine run <name>`, the same calls
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
retain their normal checks. A dead local parent fails without hosted fallback.
|
|
555
|
+
`os routine run <name>`, the same calls read current schema-governed Markdown
|
|
556
|
+
in the trusted checkout, including staged, modified and untracked Records. Each
|
|
557
|
+
operation reads the files as it begins. Later calls see completed writes and
|
|
558
|
+
external edits. Current local Data acquires no hosted binding or index. A dead
|
|
559
|
+
local parent fails without hosted fallback.
|
|
579
560
|
|
|
580
561
|
Each graph selection sends one request and returns only selected canonical
|
|
581
562
|
values, expanded forward links and exact opaque public versions. Cursors
|
|
@@ -706,15 +687,11 @@ projection, highlighting, embedding or historical version option.
|
|
|
706
687
|
|
|
707
688
|
Matches have deterministic order and complete canonical Records. Empty matches
|
|
708
689
|
succeed with the exact searched version. Members search latest published data;
|
|
709
|
-
routines search their
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
another publisher does not move the captured view. Search Records can supply
|
|
715
|
-
guards for subsequent Changes. Missing or incomplete search data, including
|
|
716
|
-
retained versions without it, fails retryably with `unavailable` without an
|
|
717
|
-
alternate read path.
|
|
690
|
+
hosted routines search their admitted hosted version. Local routines search the
|
|
691
|
+
schema-governed Markdown currently in the checkout, including staged, modified
|
|
692
|
+
and untracked Records. Each call refreshes its operation-local view; a later call
|
|
693
|
+
sees completed Changes writes and external edits. Search Records supply captured
|
|
694
|
+
versions for subsequent Changes. Explicit History keeps its hosted contract.
|
|
718
695
|
|
|
719
696
|
`where` combines field conditions with AND. Alongside exact scalar/null equality
|
|
720
697
|
and `$in`, declared one-valued `integer`, `number` and `date` fields accept
|
|
@@ -771,9 +748,10 @@ only after its exact index is ready. Later current reads discover that version.
|
|
|
771
748
|
Deleted identities keep their captured versions; deletion creates no new Record
|
|
772
749
|
version or tombstone. A Source deletion removes only that guarded Record, retaining
|
|
773
750
|
its File, enrichments and existing durable uses.
|
|
774
|
-
During
|
|
775
|
-
|
|
776
|
-
|
|
751
|
+
During a local Run, `changes.publish()` validates the complete set once before
|
|
752
|
+
writing individual complete files atomically. Completed paths remain after a later
|
|
753
|
+
filesystem failure. `validate()` grants no later permission to write; subsequent
|
|
754
|
+
operations read the current checkout. No later Run publication is required.
|
|
777
755
|
|
|
778
756
|
`invalid_change` and known-unapplied `conflict` reject the batch.
|
|
779
757
|
`publication_pending` is retryable and may report `uncertain` or `applied`;
|
|
@@ -816,42 +794,41 @@ records separately. `AirtableOperationError` reports `unapplied`, `partial` or
|
|
|
816
794
|
work; never repeat the whole change blindly. Credentials must never be retained
|
|
817
795
|
in files, publication, logs, handler input, errors or receipts.
|
|
818
796
|
|
|
819
|
-
Managed routine launches supply workspace
|
|
820
|
-
The defaults read `OS_ROUTINE_WORKSPACE
|
|
821
|
-
`
|
|
822
|
-
existing `workspace`, `capability` and `workingRoot` options. Runtime context
|
|
797
|
+
Managed routine launches supply workspace and scoped capability.
|
|
798
|
+
The defaults read `OS_ROUTINE_WORKSPACE` and `OS_ROUTINE_RUN`. Hosts may supply
|
|
799
|
+
`workspace`, `capability` and `request` options. Runtime context
|
|
823
800
|
provides authority; callers cannot select repository remotes or expand grants.
|
|
824
801
|
`os routine run <name> [--input <file|->]` executes the conventional inert
|
|
825
|
-
definition with declared JSON input and
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
No-change success retains Run evidence without requiring publish. `--json`
|
|
830
|
-
returns typed Run state/counts/result, or confirmed publish receipts/links.
|
|
802
|
+
definition with declared JSON input. Data writes and hosted capability calls
|
|
803
|
+
complete live; successful earlier work remains after a later failure. The Run
|
|
804
|
+
retains exact local paths, safe hosted effects and Git provenance. `--json`
|
|
805
|
+
returns typed Run state, result/failure and retained local activity.
|
|
831
806
|
The former `prepare`, `run --local`, command/argv and authority-selection
|
|
832
807
|
flags are rejected. `os routine deploy <canonical-id>` explicitly delivers the
|
|
833
808
|
complete definition, including its response handlers; `--yes` provides automation
|
|
834
809
|
consent. `os routine run <canonical-id> --remote` runs the current successful
|
|
835
810
|
deployment with the same input/defaults, ordered steps and result validation.
|
|
836
811
|
Remote handles expose `current()`, `watch()` and `step(id)`; `runs.list()` and
|
|
837
|
-
`runs.get(id)` read retained bounded history. Remote summaries omit
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
Retain evidence with `
|
|
841
|
-
the
|
|
842
|
-
|
|
843
|
-
creates, updates and deletions. Local Runs read
|
|
844
|
-
|
|
845
|
-
|
|
812
|
+
`runs.get(id)` read retained bounded history. Remote summaries omit local activity.
|
|
813
|
+
App-started local routines use the same current-checkout and live-effects owner.
|
|
814
|
+
|
|
815
|
+
Retain evidence with shared `files.create({ file: bytes, name: 'evidence.txt' })`
|
|
816
|
+
and put the returned File into `fileBlock({ label, files })`. Inbox has no byte
|
|
817
|
+
intake API. Local publication uploads that same File before exposing the item. Use `data.repository(name)` for Record reads and `changes()` for guarded
|
|
818
|
+
creates, updates and deletions. Local Runs read current checkout files and leave
|
|
819
|
+
completed Data writes as ordinary uncommitted files for review, even after later
|
|
820
|
+
failure. Inbox publication has no Record methods;
|
|
846
821
|
managed Response handlers retain their separately injected repository capability.
|
|
847
822
|
|
|
848
823
|
Hosts publishing as a member supply the existing `request` option:
|
|
849
824
|
|
|
850
825
|
```ts
|
|
851
|
-
const inbox = routinePublicationClient({ workspace,
|
|
826
|
+
const inbox = routinePublicationClient({ workspace, request });
|
|
852
827
|
```
|
|
853
828
|
|
|
854
|
-
Here `request` is the host's authorized member transport
|
|
829
|
+
Here `request` is the host's authorized member transport and takes precedence
|
|
830
|
+
over ambient Run routing. The CLI uses its active workspace and shared Files to
|
|
831
|
+
upload referenced local Files before sending publication. A member can publish an
|
|
855
832
|
initial handlerless Ask or Digest where allowed; a member login supplies no
|
|
856
833
|
routine repository-write authority. Login, session storage and refresh belong
|
|
857
834
|
to `@oddington/cli`.
|
package/dist/browser.js
CHANGED
|
@@ -185,7 +185,11 @@ function parseAppRoutineContract(value) {
|
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
case "array":
|
|
188
|
-
return !fields(value2, ["type", "items", "maxItems"]) || !Number.isSafeInteger(value2.maxItems) || value2.maxItems < 1
|
|
188
|
+
return !fields(value2, ["type", "items"], ["maxItems"]) || owns(value2, "maxItems") && (!Number.isSafeInteger(value2.maxItems) || value2.maxItems < 1) ? invalidContract() : {
|
|
189
|
+
type: "array",
|
|
190
|
+
items: schema2(value2.items, depth + 1),
|
|
191
|
+
...owns(value2, "maxItems") ? { maxItems: value2.maxItems } : {}
|
|
192
|
+
};
|
|
189
193
|
case "boolean":
|
|
190
194
|
return fields(value2, ["type"]) ? { type: value2.type } : invalidContract();
|
|
191
195
|
case "file":
|
|
@@ -238,7 +242,8 @@ function validateRoutineSchemaValue(schema2, value, rejected) {
|
|
|
238
242
|
return;
|
|
239
243
|
case "array":
|
|
240
244
|
if (!denseArray(value2)) return fail4("wrong_type");
|
|
241
|
-
if (
|
|
245
|
+
if (schema3.maxItems !== void 0 && value2.length > schema3.maxItems)
|
|
246
|
+
return fail4("out_of_bounds", { constraint: "maxItems", limit: schema3.maxItems });
|
|
242
247
|
value2.forEach((child, index) => check(schema3.items, child, `${path}[${index}]`));
|
|
243
248
|
return;
|
|
244
249
|
case "boolean":
|
|
@@ -887,8 +892,8 @@ var schema = {
|
|
|
887
892
|
object(properties) {
|
|
888
893
|
return declaration({ type: "object", properties: Object.fromEntries(Object.entries(properties).map(([key, value]) => [key, nestedSchema(value)])), required: Object.keys(properties), additionalProperties: !1 });
|
|
889
894
|
},
|
|
890
|
-
array(items, options) {
|
|
891
|
-
return declaration({ type: "array", items: nestedSchema(items),
|
|
895
|
+
array(items, options = {}) {
|
|
896
|
+
return assertRoutineFields(options, ["maxItems"]), declaration({ type: "array", items: nestedSchema(items), ...options });
|
|
892
897
|
},
|
|
893
898
|
string(options = {}) {
|
|
894
899
|
return declaration({ type: "string", ...options });
|
|
@@ -1665,7 +1670,7 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1665
1670
|
parseFileErrorDetail(error?.detail)
|
|
1666
1671
|
) : unavailable2();
|
|
1667
1672
|
}
|
|
1668
|
-
if (response2.status !==
|
|
1673
|
+
if (response2.status !== 200)
|
|
1669
1674
|
throw response2.body?.cancel().catch(() => {
|
|
1670
1675
|
}), unavailable2();
|
|
1671
1676
|
try {
|
|
@@ -1674,7 +1679,6 @@ async function send(suffix, init2, descriptor, initial, parent) {
|
|
|
1674
1679
|
throw response2.body?.cancel().catch(() => {
|
|
1675
1680
|
}), error;
|
|
1676
1681
|
}
|
|
1677
|
-
if (descriptor === 204) return;
|
|
1678
1682
|
if (!descriptor) return response2;
|
|
1679
1683
|
let value = await result(response2, descriptor === "control" ? CONTROL_RESULT_BYTES : RESULT_BYTES);
|
|
1680
1684
|
if (descriptor === "control")
|
|
@@ -1773,10 +1777,15 @@ async function multipartCreate(input, metadata, exchange, release = () => {
|
|
|
1773
1777
|
await upload?.beforeComplete();
|
|
1774
1778
|
let completion = control({ parts: receipts });
|
|
1775
1779
|
if (new TextEncoder().encode(completion.body).byteLength > 128 * 1024) throw unavailable2();
|
|
1776
|
-
|
|
1780
|
+
let completed = parseFileDescriptor(await request2(
|
|
1777
1781
|
(signal) => exchange(`${route}/complete`, completion, !0, signal),
|
|
1778
1782
|
TIMEOUT_MS + Math.ceil(metadata.size / (1024 * 1024)) * 1e3
|
|
1779
1783
|
));
|
|
1784
|
+
if (!upload) {
|
|
1785
|
+
let acknowledged = await request2((signal) => exchange(`${route}/acknowledge`, control(completed), "control", signal));
|
|
1786
|
+
if (!acknowledged || typeof acknowledged != "object" || Object.keys(acknowledged).join(",") !== "acknowledged" || acknowledged.acknowledged !== !0) throw unavailable2();
|
|
1787
|
+
}
|
|
1788
|
+
return completed;
|
|
1780
1789
|
} catch (error) {
|
|
1781
1790
|
throw reader && await reader.cancel(error).catch(() => {
|
|
1782
1791
|
}), ticket && await request2((signal) => exchange(`${route}/abort`, control({}), "control", signal)).catch(() => {
|
|
@@ -1839,9 +1848,6 @@ async function read(id3, names) {
|
|
|
1839
1848
|
});
|
|
1840
1849
|
}
|
|
1841
1850
|
var files = {
|
|
1842
|
-
delete(id3) {
|
|
1843
|
-
return operation((context, signal) => send(idPath(id3), { method: "DELETE" }, 204, context, signal));
|
|
1844
|
-
},
|
|
1845
1851
|
async upload(id3) {
|
|
1846
1852
|
return operation(async (context, signal) => {
|
|
1847
1853
|
let file2 = await send(`${idPath(id3)}/upload`, { method: "POST" }, !0, context, signal);
|
|
@@ -2452,8 +2458,7 @@ var operations = {
|
|
|
2452
2458
|
"items.listRecipientCandidates": ["itemId"],
|
|
2453
2459
|
"items.addRecipient": ["itemId", "personId"],
|
|
2454
2460
|
"questions.answer": ["itemId", "revision", "questionId", "response"],
|
|
2455
|
-
"questions.searchRecords": ["itemId", "revision", "questionId", "query"]
|
|
2456
|
-
"files.read": ["itemId", "fileId"]
|
|
2461
|
+
"questions.searchRecords": ["itemId", "revision", "questionId", "query"]
|
|
2457
2462
|
};
|
|
2458
2463
|
function assert(value) {
|
|
2459
2464
|
if (!value) throw new Error("Invalid Inbox result");
|
|
@@ -3259,34 +3264,6 @@ async function send2(operation2, input, admitted) {
|
|
|
3259
3264
|
if (response2.status !== 200)
|
|
3260
3265
|
throw response2.body?.cancel().catch(() => {
|
|
3261
3266
|
}), unavailable3();
|
|
3262
|
-
if (operation2 === "files.read") {
|
|
3263
|
-
if (!response2.body) throw unavailable3();
|
|
3264
|
-
let source2 = response2.body, reader, size = 0, cancel = async (reason) => {
|
|
3265
|
-
try {
|
|
3266
|
-
await (reader ? reader.cancel(reason) : source2.cancel(reason));
|
|
3267
|
-
} finally {
|
|
3268
|
-
reader?.releaseLock();
|
|
3269
|
-
}
|
|
3270
|
-
}, body = new ReadableStream({
|
|
3271
|
-
async pull(controller) {
|
|
3272
|
-
try {
|
|
3273
|
-
check(), reader ??= source2.getReader();
|
|
3274
|
-
let next = await reader.read();
|
|
3275
|
-
if (check(), next.done) {
|
|
3276
|
-
reader.releaseLock(), controller.close();
|
|
3277
|
-
return;
|
|
3278
|
-
}
|
|
3279
|
-
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw unavailable3();
|
|
3280
|
-
controller.enqueue(next.value);
|
|
3281
|
-
} catch (error) {
|
|
3282
|
-
controller.error(error), await cancel(error).catch(() => {
|
|
3283
|
-
});
|
|
3284
|
-
}
|
|
3285
|
-
},
|
|
3286
|
-
cancel
|
|
3287
|
-
}, { highWaterMark: 0 });
|
|
3288
|
-
return new Response(body, { status: response2.status, headers: response2.headers });
|
|
3289
|
-
}
|
|
3290
3267
|
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
3291
3268
|
if (check(), !bytes) throw unavailable3();
|
|
3292
3269
|
let value = JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)), parsed = parseInboxResult(operation2, value);
|
|
@@ -3365,8 +3342,7 @@ var inbox = {
|
|
|
3365
3342
|
},
|
|
3366
3343
|
answer: async (input) => await send2("questions.answer", input),
|
|
3367
3344
|
searchRecords: async (input) => await send2("questions.searchRecords", input)
|
|
3368
|
-
}
|
|
3369
|
-
files: { read: async (input) => await send2("files.read", input) }
|
|
3345
|
+
}
|
|
3370
3346
|
};
|
|
3371
3347
|
|
|
3372
3348
|
var sources = /* @__PURE__ */ new WeakMap();
|
|
@@ -3882,7 +3858,6 @@ function routineRunHandle(operations2) {
|
|
|
3882
3858
|
return Object.freeze({
|
|
3883
3859
|
current: operations2.current,
|
|
3884
3860
|
step: operations2.step,
|
|
3885
|
-
...operations2.publish ? { publish: operations2.publish } : {},
|
|
3886
3861
|
async *watch() {
|
|
3887
3862
|
let previous;
|
|
3888
3863
|
for (; ; ) {
|
|
@@ -4013,7 +3988,7 @@ function summary(value, key, context, id3) {
|
|
|
4013
3988
|
return fail3("execution_unavailable");
|
|
4014
3989
|
}
|
|
4015
3990
|
let run = value;
|
|
4016
|
-
return (!only(run, "id,routine,placement,status,createdAt,startedAt,finishedAt,steps,result,failure,
|
|
3991
|
+
return (!only(run, "id,routine,placement,status,createdAt,startedAt,finishedAt,steps,result,failure,local") || typeof run.id != "string" || !uuid2.test(run.id) || id3 !== void 0 && run.id !== id3 || run.routine !== key || run.placement !== "local" || !["queued", "running", "succeeded", "failed"].includes(run.status) || !timestamp(run.createdAt) || !optionalTimes(run) || !Array.isArray(run.steps) || run.steps.length > 64 || run.steps.some((step) => !only(step, "id,title,status,startedAt,finishedAt,summary,detailAvailable") || typeof step.detailAvailable != "boolean" || !validStep(step)) || new Set(run.steps.map((step) => step.id)).size !== run.steps.length || Object.hasOwn(run, "result") && (run.status !== "succeeded" || !bounded2(run.result)) || run.failure !== void 0 && (run.status !== "failed" || !only(run.failure, "message") || !message(run.failure.message)) || run.local !== void 0 && !validLocalActivity(run.local)) && fail3("execution_unavailable"), run;
|
|
4017
3992
|
}
|
|
4018
3993
|
function only(value, allowed) {
|
|
4019
3994
|
return !!value && typeof value == "object" && !Array.isArray(value) && Object.keys(value).every((key) => allowed.split(",").includes(key));
|
|
@@ -4025,8 +4000,9 @@ function optionalTimes(value) {
|
|
|
4025
4000
|
function validStep(step) {
|
|
4026
4001
|
return typeof step.id == "string" && identifier.test(step.id) && typeof step.title == "string" && step.title.length > 0 && step.title.length <= 256 && ["pending", "running", "completed", "failed", "skipped"].includes(step.status) && optionalTimes(step) && (!Object.hasOwn(step, "summary") || bounded2(step.summary)) && (!Object.hasOwn(step, "data") || bounded2(step.data));
|
|
4027
4002
|
}
|
|
4028
|
-
function
|
|
4029
|
-
|
|
4003
|
+
function validLocalActivity(value) {
|
|
4004
|
+
let paths = (value2) => Array.isArray(value2) && value2.every((path) => typeof path == "string" && path.length > 0 && path.length <= 4096 && !path.startsWith("/") && !path.includes("\\") && !path.split("/").some((part) => !part || part === "." || part === "..") && !/[\x00-\x1f\x7f]/.test(path));
|
|
4005
|
+
return value && only(value, "data,effects,git") && bounded2(value) && Array.isArray(value.data) && Array.isArray(value.effects) && value.data.every((item) => only(item, "repository,created,updated,deleted,failures") && typeof item.repository == "string" && identifier.test(item.repository) && paths(item.created) && paths(item.updated) && paths(item.deleted) && (item.failures === void 0 || Array.isArray(item.failures) && item.failures.every((code) => code === "unavailable"))) && value.effects.every((item) => only(item, "capability,operation,status,reference,summary") && ["files", "inbox", "ai"].includes(item.capability) && typeof item.operation == "string" && /^[a-zA-Z][a-zA-Z0-9-]{0,62}$/.test(item.operation) && ["completed", "failed"].includes(item.status) && (item.reference === void 0 || typeof item.reference == "string" && uuid2.test(item.reference)) && (!Object.hasOwn(item, "summary") || bounded2(item.summary))) && (value.git === void 0 || only(value.git, "branch,commit,dirty") && typeof value.git.dirty == "boolean" && (value.git.branch === void 0 || typeof value.git.branch == "string" && value.git.branch.length <= 256 && !/[\x00-\x1f\x7f]/.test(value.git.branch)) && (value.git.commit === void 0 || typeof value.git.commit == "string" && /^[0-9a-f]{40}$/.test(value.git.commit)));
|
|
4030
4006
|
}
|
|
4031
4007
|
function jsonInput(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
4032
4008
|
if (value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value)) return;
|
|
@@ -4062,9 +4038,6 @@ function handle(key, id3, context) {
|
|
|
4062
4038
|
return fail3("execution_unavailable");
|
|
4063
4039
|
}
|
|
4064
4040
|
return (!only(value, "id,title,status,startedAt,finishedAt,summary,data") || value.id !== step || !validStep(value)) && fail3("execution_unavailable"), value;
|
|
4065
|
-
},
|
|
4066
|
-
async publish() {
|
|
4067
|
-
return context.kind !== "local" && fail3("execution_unavailable"), summary(await request(key, `runs/${id3}/publish`, { method: "POST" }, SUMMARY_BYTES, context), key, context, id3);
|
|
4068
4041
|
}
|
|
4069
4042
|
});
|
|
4070
4043
|
}
|
|
@@ -4144,21 +4117,31 @@ var app = /* @__PURE__ */ Object.freeze({
|
|
|
4144
4117
|
})
|
|
4145
4118
|
});
|
|
4146
4119
|
|
|
4147
|
-
function
|
|
4148
|
-
let
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4120
|
+
async function requestInboxPublication(operation2, request2, caller) {
|
|
4121
|
+
let attempt = () => {
|
|
4122
|
+
if (caller?.aborted) throw caller.reason;
|
|
4123
|
+
let timeout = AbortSignal.timeout(3e4);
|
|
4124
|
+
return request2(caller ? AbortSignal.any([caller, timeout]) : timeout);
|
|
4125
|
+
};
|
|
4126
|
+
if (operation2 !== "publish") return attempt();
|
|
4127
|
+
try {
|
|
4128
|
+
let response2 = await attempt();
|
|
4129
|
+
if (response2.status !== 408 && response2.status !== 429 && response2.status < 500) return response2;
|
|
4130
|
+
await response2.body?.cancel();
|
|
4131
|
+
} catch (error) {
|
|
4132
|
+
if (caller?.aborted) throw error;
|
|
4133
|
+
}
|
|
4134
|
+
if (caller?.aborted) throw caller.reason;
|
|
4135
|
+
return attempt();
|
|
4153
4136
|
}
|
|
4154
4137
|
|
|
4155
4138
|
function routinePublicationClient2(options = {}) {
|
|
4156
|
-
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;
|
|
4139
|
+
let environment = {}, installed2 = options.request ? void 0 : routineTransport(), local2 = options.request ? void 0 : installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.OS_ROUTINE_WORKSPACE, capability = options.capability ?? (options.request ? void 0 : environment.OS_ROUTINE_RUN);
|
|
4157
4140
|
if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
|
|
4158
4141
|
throw new Error("A workspace and valid optional routine capability are required");
|
|
4159
|
-
let
|
|
4142
|
+
let headers = capability ? { "x-os-run": capability } : {}, request2 = options.request ?? (capability ? async (path, init2) => {
|
|
4160
4143
|
let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
|
|
4161
|
-
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
|
|
4144
|
+
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)$/.test(path) || init2?.method !== "POST")
|
|
4162
4145
|
throw new Error("Invalid routine endpoint");
|
|
4163
4146
|
return fetch(target, { ...init2, redirect: "error" });
|
|
4164
4147
|
} : async () => {
|
|
@@ -4166,11 +4149,12 @@ function routinePublicationClient2(options = {}) {
|
|
|
4166
4149
|
});
|
|
4167
4150
|
async function send3(operation2, body) {
|
|
4168
4151
|
if (local2) return await local2(operation2, body);
|
|
4169
|
-
let response2 = await request2(`/api/inbox/${operation2}`, {
|
|
4152
|
+
let response2 = await requestInboxPublication(operation2, (signal) => request2(`/api/inbox/${operation2}`, {
|
|
4170
4153
|
method: "POST",
|
|
4171
4154
|
headers: { "content-type": "application/json", ...headers },
|
|
4172
|
-
body: JSON.stringify(body)
|
|
4173
|
-
|
|
4155
|
+
body: JSON.stringify(body),
|
|
4156
|
+
signal
|
|
4157
|
+
})), result2 = await response2.json();
|
|
4174
4158
|
if (!response2.ok) throw new Error(result2.error ?? "Could not confirm routine publication");
|
|
4175
4159
|
return result2;
|
|
4176
4160
|
}
|
|
@@ -4183,13 +4167,6 @@ function routinePublicationClient2(options = {}) {
|
|
|
4183
4167
|
await send3("resolve", body);
|
|
4184
4168
|
}
|
|
4185
4169
|
}),
|
|
4186
|
-
files: {
|
|
4187
|
-
async add(value) {
|
|
4188
|
-
let input = validateFileAddOptions(value);
|
|
4189
|
-
if (local2) return validateInboxFile(await local2("files/add", input));
|
|
4190
|
-
throw workingRoot ? new Error("Inbox file reads require a Node working root") : new Error("Inbox file reads require a working root");
|
|
4191
|
-
}
|
|
4192
|
-
},
|
|
4193
4170
|
async check(body) {
|
|
4194
4171
|
await send3("check", { requestKey: body.requestKey, item: validatePublication(body.item) });
|
|
4195
4172
|
}
|