@pipelex/sdk 0.29.1 → 0.30.0
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 +1 -2
- package/dist/client.d.ts +30 -90
- package/dist/client.js +29 -119
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +5 -5
- package/dist/errors.js +5 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +27 -152
- package/dist/models.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/architecture.md +7 -6
- package/docs/crate-routes.md +9 -5
- package/docs/errors.md +1 -1
- package/docs/input-preparation.md +5 -5
- package/package.json +2 -2
- package/docs/build-routes.md +0 -101
package/docs/build-routes.md
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# Build routes (`/v1/build/*`)
|
|
2
|
-
|
|
3
|
-
The three build projections — `buildInputs`, `buildOutput`, `buildRunner` — take a **closure** of MTHDS files, select **one pipe** in it, and project something from that pipe. They are Pipelex API extensions, not MTHDS Protocol routes: the standard specifies no projection surface, so these are ours to shape.
|
|
4
|
-
|
|
5
|
-
> **`prepareInputs` no longer reads the inputs template.** It reads its signature from the input-form descriptor `POST /v1/pipe-io` returns (see [input-preparation.md](./input-preparation.md#signature-driven-asset-identification)), so nothing inside this SDK calls these routes. They are kept for external consumers, and their retirement across the workspace is tracked separately.
|
|
6
|
-
|
|
7
|
-
## The shared envelope
|
|
8
|
-
|
|
9
|
-
Every build request supplies the closure **either** as inline `files` **or** as a `method_ref` — never both:
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
interface MthdsFileItem {
|
|
13
|
-
content: string;
|
|
14
|
-
source?: string; // provenance label — threaded onto this file's diagnostics
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface CrateRequestBase {
|
|
18
|
-
files?: MthdsFileItem[];
|
|
19
|
-
method_ref?: string; // address form server-resolved (pipelex-api >= 0.21.0); registry form reserved → 501
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface BuildRequestBase extends CrateRequestBase {
|
|
23
|
-
pipe_ref?: string; // QUALIFIED `domain.pipe_code`; omit to default to the closure's `main_pipe`
|
|
24
|
-
method_id?: never; // the build routes have no by-id form — expand with getMethodClosure
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
The selector half is `CrateRequestBase`, shared verbatim with the [crate routes](./crate-routes.md) (`resolve` / `codegen`) — the same split the server makes (`MthdsPipeRequest(MthdsFilesRequest)`). What the build routes add is the pipe selector. An **address-form** `method_ref` (`github.com/<owner>/<repo>[/<selector>][@<tag>]`) is resolved by the server through the same fetch path as a `method_ref` run — the package's real relative paths feed the per-file `source` labels; any non-address reference stays reserved and answers `501`.
|
|
29
|
-
|
|
30
|
-
The build routes deliberately take **no `method_id`** — the hosted tooling selector covers `validate` / `resolve` / `codegen` only, and these routes are frozen, being replaced by the codegen surface. The type pins the field to `never`, and `buildInputs` additionally rejects a stray runtime `method_id` with an error naming the migration (its old client-side by-id expansion was deleted). To build from a stored method, expand it first: `buildInputs({ files: await client.getMethodClosure(methodId) })`.
|
|
31
|
-
|
|
32
|
-
`source` is why the envelope exists. A closure is a set of files, and a diagnostic that cannot say _which_ file it came from is much harder to act on. Pass a filename (or any label) per file and, **when the engine can attribute the diagnostic to a file**, it comes back as `source` on the corresponding `validation_errors[]` item.
|
|
33
|
-
|
|
34
|
-
Treat that attribution as best-effort, not a guarantee — which is why `ValidationErrorItem.source` is typed optional and why the sample below reads `err.source ?? "?"`. Some arms don't populate it: graph-level `dry_run` and `pipe_factory` items have no single owning file, and a `main_pipe` naming a nonexistent pipe currently reports its provenance in the message prose while leaving the structured field unset. The syntax-error arm, the common case, does thread it.
|
|
35
|
-
|
|
36
|
-
`pipe_ref` is **qualified** — `smoke.echo`, not `echo`. Omitting it defaults to the closure's declared `main_pipe`, which fails with a `422` when the closure declares **none**, or declares **several** across its domains. When you already know the pipe, name it: it is one field, and it removes the whole default-resolution failure mode.
|
|
37
|
-
|
|
38
|
-
> `MthdsFileItem` is not the same type as `MthdsFile` (the one `validateFiles()` takes). `/v1/validate` spells the provenance label `uri` and carries it in a parallel `mthds_sources` array; this envelope spells it `source` and carries it inline. The two collapse into one only if `/v1/validate` ever migrates onto `files[]` — a protocol-level change owned by the MTHDS standard, not ours to make here.
|
|
39
|
-
|
|
40
|
-
## The response is a verdict, not a payload
|
|
41
|
-
|
|
42
|
-
Each route returns a **discriminated 200**, following `validate`'s discipline: an unresolvable closure is the _successful product_ of the call (the request was well-formed; the library was not), so it rides a 200 with `is_valid: false`, never a 4xx.
|
|
43
|
-
|
|
44
|
-
**Branch on `is_valid` before reading the arm.** This is the easy thing to get wrong — a consumer that only catches throws will render a success over an unusable result, because nothing threw:
|
|
45
|
-
|
|
46
|
-
```ts
|
|
47
|
-
const result = await client.buildInputs({ files: [{ content: src, source: "method.mthds" }] });
|
|
48
|
-
|
|
49
|
-
if (!result.is_valid) {
|
|
50
|
-
// 200, but the closure did not resolve. `validation_errors[]` says why, and each
|
|
51
|
-
// item's `source` names the file it came from.
|
|
52
|
-
for (const err of result.validation_errors) {
|
|
53
|
-
console.error(`${err.source ?? "?"}: ${err.message}`);
|
|
54
|
-
}
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Narrowed to the valid arm.
|
|
59
|
-
console.log(result.pipe_ref); // the RESOLVED qualified ref, e.g. "smoke.echo"
|
|
60
|
-
console.log(result.inputs); // the template
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
The valid arm always echoes two refs: `pipe_ref` is what the server **resolved** (always qualified), and `requested_pipe_ref` is what you **submitted** — absent entirely when you omitted it and the server defaulted to `main_pipe`.
|
|
64
|
-
|
|
65
|
-
## What throws
|
|
66
|
-
|
|
67
|
-
Only a **no-verdict** condition, and it throws the typed `ApiResponseError` — branch on its `status`, never on its message:
|
|
68
|
-
|
|
69
|
-
| Status | Cause |
|
|
70
|
-
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
71
|
-
| `422` | The pipe selector does not resolve: an unknown `pipe_ref`, or an omitted one on a closure with no `main_pipe` — or several. Also an output concept that cannot be rendered (`buildOutput`), and a requested pipe the dry-run skipped (`buildRunner`). |
|
|
72
|
-
| `501` | Registry-form `method_ref` — reserved, not implemented (the address form resolves). |
|
|
73
|
-
| `401` / `403` | Auth. |
|
|
74
|
-
| `5xx` | Server fault. |
|
|
75
|
-
|
|
76
|
-
Note the split: a bad **closure** is a 200 verdict; a bad **request** throws. "Your `pipe_ref` names nothing in this closure" says nothing is wrong with the closure — you asked for a pipe that isn't there — so it is a request error.
|
|
77
|
-
|
|
78
|
-
## The payload field follows `format`
|
|
79
|
-
|
|
80
|
-
Both `buildInputs` and `buildOutput` carry their payload in **one of two fields**, chosen by the requested `format`. The field the format did not select is **absent** from the body, not `null`.
|
|
81
|
-
|
|
82
|
-
| Route | `format` | Field | Type |
|
|
83
|
-
| ------------- | ---------------------------- | --------------- | ------------------------- |
|
|
84
|
-
| `buildInputs` | `json` _(default)_ | `inputs` | `Record<string, unknown>` |
|
|
85
|
-
| `buildInputs` | `toml` | `inputs_toml` | `string` |
|
|
86
|
-
| `buildOutput` | `schema` _(default)_, `json` | `output` | `Record<string, unknown>` |
|
|
87
|
-
| `buildOutput` | `python` | `output_python` | `string` |
|
|
88
|
-
|
|
89
|
-
The split is deliberate, not an accident of serialization. TOML cannot ride as a parsed object without losing exactly what makes it worth asking for — its concept comments and key order — and Python source is text by nature. Collapsing either into the JSON case would have meant stringifying the object case too, and the object shape is what consumers actually want.
|
|
90
|
-
|
|
91
|
-
`buildInputs` also takes `explicit` (default `false`), which emits the ceremonial `{concept, content}` envelope per input instead of the light shape.
|
|
92
|
-
|
|
93
|
-
## `buildRunner` is the odd one out
|
|
94
|
-
|
|
95
|
-
It is the only build route that still **dry-runs** the closure, so:
|
|
96
|
-
|
|
97
|
-
- It keeps `allow_signatures` (accept unresolved pipe signatures as pending rather than invalid). The other two dropped it — the flag only ever parameterized the sweep, and they no longer sweep.
|
|
98
|
-
- Its valid arm carries `python_code` plus a stamped `structures` projection (`directory`, `artifacts[]`, `lock`, `lock_filename`) — write the artifacts and the lock under `directory`, relative to the runner script, and the script runs against them.
|
|
99
|
-
- **Omitting `pipe_ref` sweeps the WHOLE closure**, not just the pipe it defaults to. The default can only be resolved _after_ the sweep has run, so there is no way to scope it in advance. A broken _sibling_ pipe can therefore sink the request — which is the honest answer for a caller who did not say which pipe they meant. Pass `pipe_ref` to scope the sweep.
|
|
100
|
-
|
|
101
|
-
`buildInputs` and `buildOutput` are **static**: they read the pipe's _declared_ IO off a resolved crate. A valid verdict from them says the closure is structurally sound — never that the pipe runs. Runnability is `validate`'s vocabulary, and `buildRunner`'s.
|