@oddington/sdk 0.1.3 → 0.1.5
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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The importable client for Oddington apps, routines and response handlers.
|
|
4
4
|
Node operations require Node.js 22.12.0 or later. The root import and hosted
|
|
5
|
-
Data
|
|
5
|
+
Data and Files APIs work in browsers. Installing the package grants no authority.
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
8
|
npm install @oddington/sdk
|
|
@@ -29,6 +29,84 @@ session subscription. Workspace existence and member access are checked by the
|
|
|
29
29
|
OS service. App modules use capability namespaces; routines and handlers receive
|
|
30
30
|
runtime context without calling `os.init`.
|
|
31
31
|
|
|
32
|
+
Create and recover a private immutable original through the same host context:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { files } from '@oddington/sdk';
|
|
36
|
+
|
|
37
|
+
const report = await files.create({
|
|
38
|
+
file: selectedFile, // Web File, path-backed Blob, Uint8Array or byte stream
|
|
39
|
+
name: 'September statement.csv',
|
|
40
|
+
path: 'HSC/2026/09',
|
|
41
|
+
}, { requestKey: 'statement/2026/09' });
|
|
42
|
+
const descriptor = await files.get(report.id);
|
|
43
|
+
const response = await files.read(descriptor.id);
|
|
44
|
+
await response.text(); // Also supports blob(), arrayBuffer() and body streaming.
|
|
45
|
+
const reading = await files.enrich({ file: report.id, name: 'read.md', content: readingMarkdown });
|
|
46
|
+
await files.enrich({ file: report.id, name: 'extracted.json', content: JSON.stringify(extractedValue) });
|
|
47
|
+
const current = await files.get(report.id); // Discover retained enrichment descriptors.
|
|
48
|
+
const context = await files.read(current.id, ['read.md', 'extracted.json']);
|
|
49
|
+
await context['read.md'].text();
|
|
50
|
+
await context['extracted.json'].json(); // Each body is independently consumed.
|
|
51
|
+
await files.enrich({ file: report.id, name: 'read.md', content: revisedMarkdown, replace: reading.sha256 });
|
|
52
|
+
await files.upload(report.id); // Move a local File and every retained enrichment to remote storage.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Hosted Files retains remote originals and caller-produced named enrichments;
|
|
56
|
+
`storage: 'local'` requires a managed CLI parent. Configure that parent with
|
|
57
|
+
`ODDINGTON_FILES_ROOT` pointing to an empty or already OS-managed dedicated
|
|
58
|
+
directory outside tracked Git content. `ODDINGTON_FILES_DEFAULT=local|remote`
|
|
59
|
+
selects its default; without it, remote remains the default. Per-File `storage`
|
|
60
|
+
overrides it. The root stays private to the parent. Local creation without a
|
|
61
|
+
configured root fails with `unsupported_context`. Files have one durable home;
|
|
62
|
+
`both` is invalid. Local retention establishes no hosted registration.
|
|
63
|
+
Fresh runs recover the same creator's File by its request key, and verify
|
|
64
|
+
retained bytes before returning a descriptor or content. A dead parent fails
|
|
65
|
+
closed. `os routine prepare` seals checked local File references and defers
|
|
66
|
+
new remote Files, their enrichments and explicit uploads until `os routine publish`; legacy Inbox
|
|
67
|
+
file preparation remains additive. Existing hosted Files are read-only during
|
|
68
|
+
preparation.
|
|
69
|
+
`upload(id)` preserves the File descriptor, creator access and existing Source
|
|
70
|
+
references. Local bytes remain authoritative until all remote objects verify;
|
|
71
|
+
retrying a completed upload returns the same File. Later reads and enrichments
|
|
72
|
+
follow remote storage; any remaining managed local bytes are disposable cache.
|
|
73
|
+
An unreferenced local File is disclosed remotely only when explicitly uploaded
|
|
74
|
+
or successfully published as a Source. An authorized hosted caller receives
|
|
75
|
+
non-retryable `local_only` (409) until upload succeeds; unrelated callers receive
|
|
76
|
+
`access_denied`.
|
|
77
|
+
Unnamed inputs require a safe `name`; streams also require declared `size`.
|
|
78
|
+
Blob and byte-array declarations must match their intrinsic size. Originals are
|
|
79
|
+
bounded to 16 MiB per object, metadata to 4 KiB, and descriptor/error bodies to 16 KiB.
|
|
80
|
+
Operations share four concurrent slots and a 30-second deadline;
|
|
81
|
+
transport retries at most once with the same prepared bytes and request key.
|
|
82
|
+
Omitting a key generates one for that invocation. Supply a stable key to recover
|
|
83
|
+
across processes or fresh routine runs. Caller inputs remain owned by the caller.
|
|
84
|
+
Each request resolves current authority; hosted routine Files calls use the
|
|
85
|
+
selected workspace's HTTPS OS host, and managed calls use the authenticated
|
|
86
|
+
private parent transport. `FileOperationError` exposes a bounded code,
|
|
87
|
+
status and retryability without server details. Reads return the successful Web
|
|
88
|
+
Response without consuming its body. Local transfer is bounded and buffered
|
|
89
|
+
before constructing that Response. Creation grants private creator access;
|
|
90
|
+
workspace membership alone never grants another creator's File.
|
|
91
|
+
|
|
92
|
+
`enrich` accepts a string encoded as UTF-8 or exact `Uint8Array` bytes, a safe
|
|
93
|
+
flat filename, and an optional MIME hint. OS verifies text/Markdown/JSON or
|
|
94
|
+
reduces the content to generic binary metadata; it performs no extraction or
|
|
95
|
+
model work. The first enrichment atomically promotes the storage bundle while
|
|
96
|
+
preserving original bytes, File identity, name, path and access. An identical
|
|
97
|
+
retry returns the retained descriptor. Different content conflicts unless
|
|
98
|
+
`replace` matches the current enrichment hash; repeating a completed replacement
|
|
99
|
+
still succeeds with its preceding hash. There is no enrichment request key.
|
|
100
|
+
|
|
101
|
+
`read(id)` returns the original; `read(id, name)` returns one enrichment.
|
|
102
|
+
`read(id, names)` validates at most 16 distinct safe names, deduplicates repeats,
|
|
103
|
+
and returns an object of unconsumed Responses after all reads succeed. An empty
|
|
104
|
+
list returns an empty object in a valid runtime context. Missing authorized names
|
|
105
|
+
return `invalid_input`; a failed keyed request cancels obtained bodies. Each name
|
|
106
|
+
is read independently with fresh authority; there is no cross-name revision snapshot.
|
|
107
|
+
Names cannot contain separators or use the reserved `original` basename with
|
|
108
|
+
or without an extension. Enrichments share their parent File's access and retention.
|
|
109
|
+
|
|
32
110
|
Read a named repository through the authenticated host context:
|
|
33
111
|
|
|
34
112
|
```ts
|
|
@@ -51,7 +129,7 @@ Binding is inert. Each operation resolves current workspace, endpoint and
|
|
|
51
129
|
short-lived authority from the trusted app host or managed routine context.
|
|
52
130
|
Customer calls cannot configure those values. Missing or expired context
|
|
53
131
|
rejects; a named handle does not expand repository access. During explicit
|
|
54
|
-
`os routine
|
|
132
|
+
`os routine prepare`, the same calls use the matched checkout's committed
|
|
55
133
|
version through a private parent transport. Dirty files are ignored. An OS
|
|
56
134
|
cache outside the checkout reuses derived data; reads require no remote access
|
|
57
135
|
or preparation storage. Later accepted record effects advance the run's view
|
|
@@ -62,13 +140,78 @@ Each graph selection sends one request and returns only selected canonical
|
|
|
62
140
|
values, expanded forward links and exact opaque public versions. Cursors
|
|
63
141
|
continue the exact retained artifact and collection selection, even after
|
|
64
142
|
replacement; repeat its options and links while omitting unrelated collections.
|
|
65
|
-
No automatic retry, separate version fetch, search
|
|
66
|
-
|
|
143
|
+
No automatic retry, separate version fetch, search or history operation is
|
|
144
|
+
included. Collection schemas omit Markdown storage hints.
|
|
145
|
+
|
|
146
|
+
`where` combines field conditions with AND. Alongside exact scalar/null equality
|
|
147
|
+
and `$in`, declared one-valued `integer`, `number` and `date` fields accept
|
|
148
|
+
`$gt`, `$gte`, `$lt` and `$lte`:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
await general.records.select({ invoices: { $: { where: {
|
|
152
|
+
amount: { $gte: 10, $lte: 20 },
|
|
153
|
+
date: { $gte: '2026-10-01', $lt: '2026-11-01' },
|
|
154
|
+
month: { $gte: '2026-10', $lte: '2026-10' },
|
|
155
|
+
}, count: true } } });
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Supply one lower bound, one upper bound, or one of each. Bounds cannot combine
|
|
159
|
+
`$gt` with `$gte`, `$lt` with `$lte`, or any bound with `$in`. Operands must be
|
|
160
|
+
valid for the declared field, including numeric precision and real day/month
|
|
161
|
+
dates; values are never coerced. Missing and null values never match bounds.
|
|
162
|
+
A valid interval without matches returns an empty array and requested zero
|
|
163
|
+
count. V0 types check expression structure; runtime schema validation owns field
|
|
164
|
+
eligibility. Repeat the same bounds when continuing a cursor.
|
|
165
|
+
|
|
67
166
|
`DataOperationError.code` distinguishes `context_unavailable`, `unauthenticated`,
|
|
68
167
|
`access_denied`, `invalid_query`, `request_too_large`, `capacity` and `unavailable`.
|
|
69
|
-
|
|
168
|
+
For reads, only `capacity` and `unavailable` are retryable; an error never includes private
|
|
70
169
|
server details. Server boundaries own query bounds and authorization.
|
|
71
170
|
|
|
171
|
+
Schema-driven creates, guarded updates and guarded deletions use the same handle
|
|
172
|
+
in immediate and prepared routines:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const changes = general.changes();
|
|
176
|
+
changes.create({
|
|
177
|
+
$ref: 'invoices/INV-124', $filing: { year: '2026' },
|
|
178
|
+
type: 'invoice', number: 'INV-124', status: 'draft', amount: 1200,
|
|
179
|
+
});
|
|
180
|
+
changes.update(first.invoices[0], { amount: 30 });
|
|
181
|
+
changes.delete(first.invoices[1]);
|
|
182
|
+
await changes.validate();
|
|
183
|
+
const publication = await changes.publish();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Creation captures a complete Record and stable `$ref`, without I/O or a caller
|
|
187
|
+
path. OS resolves exactly one collection and its schema-declared filing path.
|
|
188
|
+
Optional `$filing` supplies only unresolved named safe components and is never
|
|
189
|
+
stored or returned as Record data; missing components reject by name. Updates
|
|
190
|
+
capture only `$ref`, `$version` and explicit fields. Deletion captures only the
|
|
191
|
+
selected `$ref` and `$version`. Links within the deletion set are allowed;
|
|
192
|
+
schema-declared links from any committed Record outside it refuse the whole group,
|
|
193
|
+
even if a proposed update removes that link. Validation checks the complete
|
|
194
|
+
candidate graph without effects; publication repeats authoritative validation
|
|
195
|
+
and applies every create/update/delete in one commit.
|
|
196
|
+
Success returns `{ version, created: [{ $ref, $version }], updated: [{ $ref, $version }], deleted: [{ $ref, $version }] }`
|
|
197
|
+
only after its exact index is ready. Later current reads discover that version.
|
|
198
|
+
Deleted identities keep their captured versions; deletion creates no new Record
|
|
199
|
+
version or tombstone. A Source deletion removes only that guarded Record, retaining
|
|
200
|
+
its File, enrichments and existing durable uses.
|
|
201
|
+
During `os routine prepare`, publication retains the exact proposal and
|
|
202
|
+
advances only run-local reads. `os routine publish` later applies and indexes
|
|
203
|
+
that immutable proposal; unrelated staged and unstaged work is preserved.
|
|
204
|
+
|
|
205
|
+
`invalid_change` and known-unapplied `conflict` reject the batch.
|
|
206
|
+
`publication_pending` is retryable and may report `uncertain` or `applied`;
|
|
207
|
+
retry the same change set to reconcile its retained identity. A transport failure
|
|
208
|
+
also keeps that identity. Concurrent publication calls coalesce, confirmed calls
|
|
209
|
+
replay the result, and changed intent requires a new change set. Updates are
|
|
210
|
+
bounded with creates and deletions to 10,000 total operations and the 256 KiB Data
|
|
211
|
+
request limit, with one operation per ref. Search and history are outside this
|
|
212
|
+
Changes slice. Source Records use ordinary schema rules; Data also validates OS
|
|
213
|
+
File identity/access and registers durable uses from its exact ready artifact.
|
|
214
|
+
|
|
72
215
|
Bind a declared Airtable connection with `connections.airtable('project-management')`
|
|
73
216
|
from the package root. Import and binding perform no network or credential work.
|
|
74
217
|
The client exposes `tables.list()` and `records.list`, `get`, `create`, `update`
|
|
@@ -105,8 +248,14 @@ The defaults read `ODDINGTON_ROUTINE_WORKSPACE`, `ODDINGTON_ROUTINE_RUN` and
|
|
|
105
248
|
`ODDINGTON_INBOX_WORKING_ROOT` (or the current directory). Callers may supply the
|
|
106
249
|
existing `workspace`, `capability` and `workingRoot` options. Runtime context
|
|
107
250
|
provides authority; callers cannot select repository remotes or expand grants.
|
|
108
|
-
|
|
109
|
-
|
|
251
|
+
`os routine run` publishes as capabilities are called. The same calls prepare
|
|
252
|
+
work when launched with `os routine prepare`, and `os routine publish` owns
|
|
253
|
+
explicit publication and recovery of that prepared run. Preparation may contact
|
|
254
|
+
OS for authentication and reads, and declared connections may contact their
|
|
255
|
+
providers; it does not promise offline execution. Execution location and File
|
|
256
|
+
storage are independent of the publication lifecycle. `os routine run --local`
|
|
257
|
+
remains a deprecated compatibility alias for `os routine prepare` and prints
|
|
258
|
+
the replacement command.
|
|
110
259
|
|
|
111
260
|
Retain evidence with `inbox.files.add({ path: 'evidence.txt' })`. Paths stay within
|
|
112
261
|
the invocation's working root and uploaded bytes are verified against the retained
|