@oddington/sdk 0.1.20 → 0.1.22

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 CHANGED
@@ -33,39 +33,71 @@ interaction duties belong to the consuming app's interface.
33
33
  npm install @oddington/sdk
34
34
  ```
35
35
 
36
- An authored routine exports an inert definition from its conventional `run.ts`:
36
+ An authored routine exports an inert definition from `routines/<directory>/routine.ts`:
37
37
 
38
38
  ```ts
39
39
  import { defineRoutine, file, schema } from '@oddington/sdk';
40
40
 
41
41
  export default defineRoutine({
42
+ id: 'invoice-import',
42
43
  input: schema.object({ document: file() }),
43
- steps: { read: null, extract: schema.object({ pages: schema.integer() }) },
44
+ access: { files: 'read' },
45
+ steps: {
46
+ read: {
47
+ title: 'Read receipt',
48
+ async run(input: { document: import('@oddington/sdk').File }, os) {
49
+ const response = await os.files.read(input.document.id);
50
+ return { summary: { files: 1 }, data: { text: await response.text() } };
51
+ },
52
+ },
53
+ },
44
54
  result: schema.object({ recordsCreated: schema.integer() }),
45
55
  async run(input, os) {
46
- await os.step('read');
47
- await os.step('extract', { pages: 3 });
48
- // Perform customer-owned work with the supplied installed capabilities.
49
- return { recordsCreated: 1 };
56
+ await os.step('read', input);
57
+ return { recordsCreated: 0 };
50
58
  },
51
59
  });
52
60
  ```
53
61
 
54
- Importing or defining performs no business work. Input, step summaries and returned
55
- results are inferred from serializable declarations and checked at execution.
56
- Omitted input accepts only `{}`; omitted steps permit no public report; omitted
57
- result permits no returned value. `file()` declares a complete OS File descriptor;
62
+ Importing or defining performs no business work. Input and result use bounded
63
+ schemas; step inputs, summaries and detail are inferred from executable functions.
64
+ Each step runs at most once and returns `{ summary, data }`. Unknown or repeated
65
+ steps fail the Run even if routine code catches the error; unreached steps are
66
+ skipped. Omitted input normalizes to `{}`. A top-level schema can supply a validated
67
+ immutable default with `.default(value)`, such as
68
+ `schema.object({ files: schema.array(file(), { maxItems: 32 }) }).default({ files: [] })`.
69
+ Nested defaults are unsupported and rejected. Omitted steps permit no step call;
70
+ omitted result permits no returned value. `file()` declares a complete OS File descriptor;
58
71
  the trusted launcher separately verifies current File-use authority. The supplied
59
72
  runtime contains `run.id`, `data`, `files`, `connections`, `inbox`, and `step`.
60
- Accepted input and reported values are immutable snapshots.
73
+ Accepted input and saved values are immutable snapshots. Access declarations set
74
+ maximum named capabilities and grant no authority; the trusted host checks current
75
+ authority. Response handler IDs are local to the routine and must be unique. A
76
+ declared `review` handler crosses the Inbox publication seam as
77
+ `invoice-import/review`, without deploying or executing that handler.
61
78
 
62
79
  The bounded grammar supports closed objects with required properties, arrays with
63
80
  an explicit `maxItems` from 1 to 64, booleans, strings (at most 4096 code points),
64
81
  finite numbers and safe integers with optional inclusive bounds, and Files.
65
82
  Definitions allow at most 64 steps, 64 total object properties across their schemas,
66
- and eight schema levels. Input, each summary and the result accept at most 256 KiB
67
- of serialized JSON; functions, cycles and non-JSON values reject. No name, entry,
68
- workspace, credentials or placement are authored in this definition.
83
+ and eight schema levels. Input, each step input, each summary, each detail value,
84
+ and the result accept at most 256 KiB of UTF-8 serialized JSON, without truncation.
85
+ Across 64 steps, retained summary plus detail is at most 32 MiB, plus 512 KiB for
86
+ Run input and result; step inputs are transient and individually bounded. Schema
87
+ defaults share the input bound. Titles contain at most 256 UTF-16 code units;
88
+ access dimensions and response handlers each have at most 64 entries. Functions,
89
+ accessors, sparse arrays, cycles and non-JSON values reject. The canonical routine
90
+ ID is a bounded lowercase alphanumeric/hyphen name, independent of its directory.
91
+ No entry, workspace, credentials or placement are authored in this definition.
92
+
93
+ Local Run history returns the newest 20 summaries per canonical routine, without
94
+ deleting older Runs or unpublished changes. Step titles and bounded summary/detail
95
+ values are saved with the accepted Run, so later source edits cannot rewrite them.
96
+ Each checkout-private execution/preparation JSON file has a 64 MiB total bound,
97
+ including private diagnostics; app summaries never include those diagnostics.
98
+ Publication reads the existing confirmed-receipt journal independently from the
99
+ successful execution status. Refresh reads materialized state; watching provides
100
+ connected updates without replay or interrupted-execution recovery.
69
101
 
70
102
  The named CLI local launcher requires native Node TypeScript stripping and a
71
103
  module `routines/package.json` whose `engines.node` range matches that executable.
@@ -195,63 +227,48 @@ changed local context fails closed, as do sign-out and initialization replacemen
195
227
  Local Data selects from the Host's exact published index; a warm selection
196
228
  neither initiates nor waits for renewal or synchronous hosted authority checks.
197
229
  Local Files returns `unsupported_context` after checking context. Neither path
198
- falls back to hosted services. Local app routine
199
- execution uses the installed routine's immediate-publication authority.
230
+ falls back to hosted services. Local app routines use the same local execution
231
+ and explicit publication lifecycle as the CLI.
200
232
 
201
233
  Apps can assess a declared routine without starting it:
202
234
 
203
235
  ```ts
204
- import { app, type AppRoutineBinding } from '@oddington/sdk';
205
-
206
- declare module '@oddington/sdk' {
207
- interface AppRoutineTypes {
208
- reconcile: AppRoutineBinding<
209
- { includeArchived?: boolean; limit: number },
210
- { processed: number },
211
- { read: undefined; write: { changed: number } }
212
- >;
213
- }
214
- }
215
-
216
- const status = await app.routines.reconcile.availability();
217
- if (status.available) {
218
- const steps: ('read' | 'write')[] = status.steps;
219
- }
220
- const run = await app.routines.reconcile.run({ limit: 2 });
221
- for await (const event of run.events()) {
222
- if (event.type === 'step' && event.id === 'write') console.log(event.summary.changed);
223
- if (event.type === 'finished' && event.state === 'succeeded') console.log(event.result.processed);
224
- }
225
- // After refresh or reopening the same live origin:
226
- const recovered = await app.routines.reconcile.recover();
227
- // await recovered[0]?.cancel(); // Resolves only after host acknowledgement.
236
+ import { app } from '@oddington/sdk';
237
+
238
+ const routines = await app.listRoutines(); // Declaration order, including unavailable routines.
239
+ const description = await app.routines.receipts.describe();
240
+ const run = await app.routines.receipts.run(); // Uses the definition's default input.
241
+ for await (const state of run.watch()) console.log(state.status, state.steps);
242
+ const detail = await run.step('read'); // Inferred summary and data for this new Run.
243
+ // After refresh, under newly checked authority:
244
+ const recent = await app.routines.receipts.runs.list();
245
+ const saved = await app.routines.receipts.runs.get(recent[0].id);
246
+ console.log(await saved.current());
247
+ // await saved.publish(); // Only in response to an explicit publication action.
228
248
  ```
229
249
 
230
- Keep these business types in a customer-owned contract module. Augmentation
231
- types the property but grants no runtime authority: the local host checks its
232
- retained `app.json` mapping, current member and installed routine authority,
233
- and fixed local implementation on each assessment. Available status supplies
234
- only the declaration's ordered public step IDs. Unavailability supplies only
235
- `authority_unavailable` or `execution_unavailable`, without steps.
236
- Availability and recovery accept no arguments; run accepts only declared input.
237
- Bindings accept no endpoint, token, path, run selector or routine name. Hosted
238
- bindings report `execution_unavailable` after checking current context, with no
239
- remote request or local fallback. Availability is no reservation or guarantee
240
- of later execution. `run` rejects with `AppRoutineError.reason`:
241
- `authority_unavailable`, `execution_unavailable`, or `invalid_input`.
242
- Only event reads reconnect, with bounded backoff and duplicate suppression;
243
- launch and cancellation requests are never automatically retried. Failed
244
- cancellation requests do not acknowledge cancellation. Handles expose no IDs,
245
- cursors, raw output or process controls. Local sign-out, expiry, context
246
- replacement, origin changes and unconfirmed credential changes invalidate pending work.
250
+ The fixed build generates types from each routine definition; no app-authored
251
+ contract map is needed. Descriptions combine safe structure with live readiness
252
+ and connection availability. Starts validate the current definition and input;
253
+ retained reads and publication recheck complete saved member/source/capability
254
+ scope. No installation is needed. Bindings accept no endpoint, credential,
255
+ command, path or configuration selector. Hosted declarations stay visible and
256
+ unavailable until hosted execution exists. Operations reject with
257
+ `AppRoutineError.reason`: `authority_unavailable`, `execution_unavailable`, or
258
+ `invalid_input`. Starts and publications are not automatically retried. A
259
+ disconnected watch ends and requires `current()`. History returns at most 20
260
+ summaries without deleting older Runs. Each JSON value is bounded to 256 KiB.
261
+ Transport envelopes allow 17 MiB per summary, 514 KiB per detail and 20 summaries
262
+ per list; execution retains at most 10 MiB of report evidence. Raw process
263
+ output and private authority stay private.
247
264
 
248
265
  The exact-origin browser credential survives document disposal, reload and tab
249
266
  closure in local storage. Disposal rejects the outgoing document's pending
250
267
  operations and disconnects its Run handles without cancelling the host-owned
251
268
  child. Fresh initialization at the same live Local Host origin can call the
252
- declared operation's `recover()` to continue that same owned Run without
253
- launching it again. Old handles remain invalid. Recovery is limited to the same
254
- authorized logical session, live Host and operation; it is not durable history.
269
+ declared operation's `runs.get(id)` to read retained facts without launching it
270
+ again. Old handles remain invalid. Terminal facts and bounded step detail live
271
+ in the checkout's existing Run store; interrupted execution is not recovered.
255
272
 
256
273
  Each active initialization proactively renews before expiry, normally
257
274
  sixty seconds early with a shorter lead for shorter lifetimes. Only the exact
@@ -658,7 +675,12 @@ connection effects occur immediately, including before a later failure.
658
675
  No-change success retains Run evidence without requiring publish. `--json`
659
676
  returns typed Run state/counts/result, or confirmed publish receipts/links.
660
677
  The former `prepare`, `run --local`, command/argv and authority-selection
661
- flags are rejected. Remote execution and deployment are not implemented here.
678
+ flags are rejected. `os routine deploy <canonical-id>` explicitly delivers the
679
+ complete definition, including its response handlers; `--yes` provides automation
680
+ consent. `os routine run <canonical-id> --remote` runs the current successful
681
+ deployment with the same input/defaults, ordered steps and result validation.
682
+ Remote handles expose `current()`, `watch()` and `step(id)`; `runs.list()` and
683
+ `runs.get(id)` read retained bounded history. Remote summaries omit publication.
662
684
  Checkout-backed app children retain immediate publication.
663
685
 
664
686
  Retain evidence with `inbox.files.add({ path: 'evidence.txt' })`. Paths stay within
@@ -685,17 +707,19 @@ The CLI consumes the same SDK and supplies its signed-in member transport to CLI
685
707
  commands. The former `@oddington/cli/inbox` subpath is removed; routines import
686
708
  this package root.
687
709
 
688
- The managed response runner supplies the SDK to approved handler modules:
710
+ The managed response runner supplies the SDK to the deployed definition's handlers:
689
711
 
690
712
  ```ts
691
- export const handlers = [defineHandler({
713
+ const review = defineHandler({
692
714
  id: 'review',
693
715
  run: async () => resolveAsk({ outcome: 'Reviewed' }),
694
- })];
716
+ });
717
+ // Include review in defineRoutine({ ..., responses: [review] }).
695
718
  ```
696
719
 
697
720
  A self-contained module importing only the SDK needs no customer dependency
698
721
  installation. Customer manifests cannot replace the runner-owned SDK. The runner
699
- selects the approved code revision and handler, and supplies only scoped capability
722
+ selects current code when an answer is accepted, retains that unit for invocation,
723
+ and supplies only scoped capability
700
724
  transport. The package contains public runtime code, declarations, this README and
701
725
  its license; it has no executable, operator/server code or infrastructure credentials.