@pipelex/sdk 0.47.0 → 0.48.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.
Files changed (46) hide show
  1. package/README.md +8 -6
  2. package/dist/cli/script.d.ts +1 -1
  3. package/dist/cli/source.d.ts +8 -7
  4. package/dist/cli/source.js +11 -5
  5. package/dist/cli/source.js.map +1 -1
  6. package/dist/client.d.ts +321 -210
  7. package/dist/client.js +819 -514
  8. package/dist/client.js.map +1 -1
  9. package/dist/errors.d.ts +5 -2
  10. package/dist/errors.js +5 -2
  11. package/dist/errors.js.map +1 -1
  12. package/dist/hooks/bundle-gather.d.ts +28 -40
  13. package/dist/hooks/bundle-gather.js +55 -230
  14. package/dist/hooks/bundle-gather.js.map +1 -1
  15. package/dist/hooks/claude-mthds-check.d.ts +7 -5
  16. package/dist/hooks/claude-mthds-check.js +8 -53
  17. package/dist/hooks/claude-mthds-check.js.map +1 -1
  18. package/dist/hooks/validate-stage.d.ts +27 -0
  19. package/dist/hooks/validate-stage.js +57 -0
  20. package/dist/hooks/validate-stage.js.map +1 -0
  21. package/dist/index.d.ts +3 -4
  22. package/dist/index.js +4 -3
  23. package/dist/index.js.map +1 -1
  24. package/dist/method-trees.d.ts +208 -73
  25. package/dist/method-trees.js +221 -34
  26. package/dist/method-trees.js.map +1 -1
  27. package/dist/models.d.ts +162 -59
  28. package/dist/prepare-inputs.d.ts +46 -27
  29. package/dist/prepare-inputs.js +123 -42
  30. package/dist/prepare-inputs.js.map +1 -1
  31. package/dist/product-models.d.ts +14 -16
  32. package/dist/version.d.ts +1 -1
  33. package/dist/version.js +1 -1
  34. package/docs/architecture.md +17 -18
  35. package/docs/cli.md +1 -1
  36. package/docs/crate-routes.md +42 -20
  37. package/docs/errors.md +5 -5
  38. package/docs/hook-bundle.md +1 -1
  39. package/docs/input-preparation.md +11 -11
  40. package/docs/method-trees.md +119 -21
  41. package/docs/run-results.md +5 -2
  42. package/package.json +2 -2
  43. package/dist/bundle-resources.d.ts +0 -62
  44. package/dist/bundle-resources.js +0 -165
  45. package/dist/bundle-resources.js.map +0 -1
  46. package/docs/bundle-resources.md +0 -107
@@ -1,41 +1,91 @@
1
1
  /**
2
- * A saved method's tree on the client side (see `docs/method-trees.md`): the source a save reads a
3
- * tree from, how that tree becomes the `files` map a save sends, inline or by hash, the blob routes
4
- * that let a large tree travel by hash (mthds/docs/spec/protocol.md, "Sending files by hash"), the
5
- * upload of a blob the platform lacks, and the writing of a saved tree to disk.
2
+ * A method's tree on the client side (see `docs/method-trees.md`): the forms a caller gives a
3
+ * method's tree in, the listing of a directory through the `mthds` package's own lister, how a
4
+ * tree becomes the `files` map a request sends, inline or by hash, the blob routes that let a
5
+ * large tree travel by hash (mthds/docs/spec/protocol.md, "Sending files by hash"), the upload of
6
+ * a blob the receiver lacks, and the writing of a saved tree to disk.
6
7
  *
7
- * The tree-sending part mirrors the `mthds` npm package's own helpers, which its published
8
- * `mthds/protocol` subpath does not export yet. This SDK imports `mthds` through that subpath alone,
9
- * so it carries this copy, held to the same rule: the same inline threshold, the same text-or-Base64
10
- * choice per file, and each file added as an own property. It needs no Node built-in: SHA-256 is Web
11
- * Crypto's, and Base64 is written here. Only `writeMethodTreeTo` needs Node, which it loads when
12
- * called.
13
- */
14
- import type { FileEntry, MethodFiles } from "mthds/protocol";
15
- import { type MethodFileTransferCode } from "./errors.js";
8
+ * The wire types (`MethodTreeSource`, `BlobRef`, `MissingBlob` and the rest) are the standard's,
9
+ * imported from `mthds/protocol`. A directory is listed by `mthds`'s `listMethodTree`, the
10
+ * standard's lister with its membership rule, which this module loads by a dynamic import when a
11
+ * directory is given, so the SDK's static import graph keeps no Node built-in. The choice between
12
+ * inline and by hash follows `mthds`'s `MthdsApiClient` rule exactly, but its helpers are not
13
+ * exported on a subpath free of Node built-ins, so this module carries its own copy of them: the
14
+ * same threshold, the same weighing of the inline map, the same text-or-Base64 choice per file.
15
+ * SHA-256 is Web Crypto's, and Base64 is written here. Only `writeMethodTreeTo` and
16
+ * `listDirectoryTree` need Node, which each loads when called.
17
+ */
18
+ import type { BlobRef, FileEntry, MethodFiles, MethodTreeSource, MethodTreeSourceFile, MissingBlob } from "mthds/protocol";
19
+ import { RequestArgumentError, type MethodFileTransferCode } from "./errors.js";
16
20
  import type { SavedMethodFile } from "./product-models.js";
17
- /** A file of a {@link MethodTreeSource}. */
18
- export interface MethodTreeSourceFile {
19
- /** Its tree path. */
20
- readonly path: string;
21
- /** Its length in bytes. */
22
- readonly size: number;
23
- /** The SHA-256 of its bytes, in lowercase hexadecimal. */
24
- readonly sha256: string;
21
+ /**
22
+ * A method's tree, given in exactly one of four forms. Every route that takes a method's tree
23
+ * takes these: the runs (`execute`, `start`, `startAndWaitForResult`), `validate`, the crate
24
+ * routes (`resolve`, `codegen`, `pipeIo`), `prepareInputs` and the saves (`createMethod`,
25
+ * `writeDraft`).
26
+ *
27
+ * - `directory`, a path on disk, listed by the `mthds` package's lister under the MTHDS
28
+ * standard's membership rule: rooted at the nearest `METHODS.toml` at or above it, else at the
29
+ * directory itself, every file the rule keeps, a run's inputs file (`inputs.json`,
30
+ * `inputs.toml`) never among them, under the limits the deployment announces. A `.mthds` file
31
+ * named alone is a one-file tree unless a `METHODS.toml` above it roots a larger one. Node only.
32
+ * - `contents`, each file's bytes or its text by tree path, a map held in memory.
33
+ * - `tree`, a listed source such as the `MethodTree` `listMethodTree` returns.
34
+ * - `files`, the protocol's map of file entries, sent as given.
35
+ *
36
+ * A `directory`, `contents` or `tree` travels inline when small and by hash otherwise, after the
37
+ * files the receiver lacks are uploaded (`docs/method-trees.md`).
38
+ */
39
+ export interface MethodTreeForms {
40
+ /** The method's directory, listed by the standard's lister. Node only. */
41
+ directory?: string | null;
42
+ /** Each file's bytes or text, by tree path. */
43
+ contents?: Readonly<Record<string, Uint8Array | string>> | null;
44
+ /** A listed tree, such as the `MethodTree` `listMethodTree` returns. */
45
+ tree?: MethodTreeSource | null;
46
+ /** The protocol's map of file entries, sent as given. */
47
+ files?: MethodFiles | null;
25
48
  }
26
49
  /**
27
- * A method tree a save reads from: its files, its digest, and a way to read each file's bytes. The
28
- * `MethodTree` the `mthds` package's `listMethodTree` returns is one, so a tree listed from a
29
- * directory, under the limits `methodTreeLimits` reports, is passed as it is.
30
- */
31
- export interface MethodTreeSource {
32
- /** Every file of the tree, each tree path once. */
33
- readonly files: readonly MethodTreeSourceFile[];
34
- /** The tree digest, `sha256:` and 64 lowercase hexadecimal digits. */
35
- readonly digest: string;
36
- /** The bytes of the file at `treePath`, which must hash to the SHA-256 the listing gives it. */
37
- readFile(treePath: string): Promise<Uint8Array>;
50
+ * A method's tree in exactly one of the four forms of `MethodTreeForms`, each pinning the other
51
+ * three to `never`, so giving two is a compile error. The calls that take the tree beside a
52
+ * selector it excludes (`validate`, `prepareInputs`) take it in this shape.
53
+ */
54
+ export type MethodTreeForm = {
55
+ directory: string;
56
+ contents?: never;
57
+ tree?: never;
58
+ files?: never;
59
+ } | {
60
+ contents: Readonly<Record<string, Uint8Array | string>>;
61
+ directory?: never;
62
+ tree?: never;
63
+ files?: never;
64
+ } | {
65
+ tree: MethodTreeSource;
66
+ directory?: never;
67
+ contents?: never;
68
+ files?: never;
69
+ } | {
70
+ files: MethodFiles;
71
+ directory?: never;
72
+ contents?: never;
73
+ tree?: never;
74
+ };
75
+ /** The four forms of the tree, each pinned to `never`, for a shape that takes no tree. */
76
+ export interface NoMethodTree {
77
+ directory?: never;
78
+ contents?: never;
79
+ tree?: never;
80
+ files?: never;
38
81
  }
82
+ /**
83
+ * What keeps `value` from being a listed tree as far as the client reads one before any request,
84
+ * an object with a `files` list, a `digest` string and a `readFile` function, in words for a
85
+ * refusal ("a list", "an object without them", or its type); `undefined` when it is one. A tree
86
+ * holding no file passes here, and is refused where it would be sent.
87
+ */
88
+ export declare function treeShapeFault(value: unknown): string | undefined;
39
89
  /**
40
90
  * The limits a deployment holds a tree to, in the shape the `mthds` package's `listMethodTree`
41
91
  * takes as its `limits` option, so a lister stops at the first breach before hashing anything. A
@@ -49,50 +99,75 @@ export interface MethodTreeLimits {
49
99
  /** The largest all the files together may be, in bytes. */
50
100
  readonly maxTotalSize?: number;
51
101
  }
52
- /** A blob a sender is about to send by hash, named by its SHA-256 and its size. */
53
- export interface BlobRef {
54
- sha256: string;
55
- size: number;
56
- }
57
102
  /**
58
- * Body of `POST /v1/blobs/missing`: the blobs a sender is about to send by hash, each hash listed
59
- * once, and the digest of the tree they make up, which lets a platform that holds that tree whole
60
- * answer at once.
103
+ * Every limit a deployment's handshake announces for a tree under `limits.method_tree`, in bytes
104
+ * for the sizes, named as `mthds`'s `AnnouncedTreeLimits` names them. A limit not announced is
105
+ * absent.
61
106
  */
62
- export interface MissingBlobsRequest {
63
- blobs: BlobRef[];
64
- digest?: string;
107
+ export interface AnnouncedTreeLimits {
108
+ /** The files of one tree. */
109
+ readonly maxFiles?: number;
110
+ /** One file of it. */
111
+ readonly maxFileBytes?: number;
112
+ /** All its files together. */
113
+ readonly maxTotalBytes?: number;
114
+ /** The bytes a request carries inline for its tree: its text and Base64 entries. */
115
+ readonly maxInlineBytes?: number;
65
116
  }
66
117
  /**
67
- * Where to upload one blob: its bytes as the whole body of a request with this method to this URL,
68
- * carrying exactly these headers. The URL is signed by storage and is a bearer credential.
118
+ * The heaviest inline map, in bytes of its JSON serialization in UTF-8, that a request or a save
119
+ * sends inline to a deployment keeping a blob store, when the deployment announces no lower inline
120
+ * limit. Below it a tree is cheaper to send whole than to check and upload; above it every file
121
+ * travels by hash. `mthds`'s clients use the same threshold.
69
122
  */
70
- export interface UploadTarget {
71
- method: string;
72
- url: string;
73
- headers: Record<string, string>;
74
- [extension: string]: unknown;
75
- }
76
- /** A blob the platform lacks, with where to upload it. */
77
- export interface MissingBlob {
78
- sha256: string;
79
- size: number;
80
- upload: UploadTarget;
81
- [extension: string]: unknown;
123
+ export declare const INLINE_TREE_MAX_BYTES: number;
124
+ /**
125
+ * How long a version handshake is trusted before the client asks again, `mthds`'s
126
+ * `HANDSHAKE_TTL_MS`: a deployment's blob store and tree limits change only with a deploy, so a
127
+ * client asks once per this span rather than before every request, and drops the answer sooner
128
+ * when a refusal shows it stale (`POST /v1/blobs/missing` gone, a tree refused as too large).
129
+ */
130
+ export declare const HANDSHAKE_TTL_MS: number;
131
+ /** How many blobs a request or a save uploads at once, and how many files `writeMethodTree` downloads at once. */
132
+ export declare const MAX_CONCURRENT_TRANSFERS = 8;
133
+ /**
134
+ * What a tree is prepared for, as its refusals and its failed uploads say it: a save of a method, or
135
+ * a request that runs or reads one (a run, `validate`, `resolve`, `codegen`, `pipeIo`).
136
+ */
137
+ export interface TreeSending {
138
+ /** What did not happen because an upload failed, ending its message. */
139
+ readonly unsent: string;
140
+ /** What to give instead of a tree holding no file, when there is something. */
141
+ readonly emptyRemedy?: string;
82
142
  }
83
- /** The `200` answer of `POST /v1/blobs/missing`; an empty `missing` means nothing to upload. */
84
- export interface MissingBlobsResult {
85
- missing: MissingBlob[];
86
- [extension: string]: unknown;
143
+ /** A save's: a tree holding no file is given as `files: null`, which empties a draft. */
144
+ export declare const SAVE_SENDING: TreeSending;
145
+ /** A request's: a method has at least one file, so there is nothing to give instead. */
146
+ export declare const REQUEST_SENDING: TreeSending;
147
+ /** How a request prepares its tree, beyond what a save needs. */
148
+ export interface TreeSendOptions {
149
+ /**
150
+ * Read before each step the tree costs: each file read, the version handshake's use, the blob
151
+ * route and each upload. Once it has aborted, none of them starts and the abort is thrown; a
152
+ * request already sent runs to its end.
153
+ */
154
+ readonly signal?: AbortSignal | undefined;
155
+ /**
156
+ * The request's `read_scope`, under which the blob route is asked which blobs are missing, so
157
+ * the blobs are uploaded into the store the request's hash entries are read from. The upload
158
+ * targets the route names are signed for that scope already.
159
+ */
160
+ readonly readScope?: string | undefined;
87
161
  }
88
162
  /**
89
- * The heaviest inline map, in bytes of its JSON serialization in UTF-8, that a save sends inline
90
- * to a deployment keeping a blob store. Below it a tree is cheaper to send whole than to check and
91
- * upload; above it every file travels by hash. `mthds`'s clients use the same threshold.
163
+ * A map a crate request was given, or `undefined` when it selects or sends nothing: absent, `null`,
164
+ * or a plain object holding no key, the empty-as-absent rule of the run options and of the Python
165
+ * SDK. Any other value is kept as given, so the server refuses a `files` that is not a map as the
166
+ * shape it is rather than reading it as absent.
92
167
  */
93
- export declare const INLINE_TREE_MAX_BYTES: number;
94
- /** How many blobs a save uploads at once, and how many files `writeMethodTree` downloads at once. */
95
- export declare const MAX_CONCURRENT_TRANSFERS = 8;
168
+ export declare function presentMap<T>(value: T | null | undefined): T | undefined;
169
+ /** The refusal of a tree holding no file, `call` naming the caller's method. */
170
+ export declare function emptyTreeRefusal(call: string, what: string, sending: TreeSending): RequestArgumentError;
96
171
  /** Whether a version handshake declares a blob store (`blob_store: true`). */
97
172
  export declare function declaresBlobStore(version: object): boolean;
98
173
  /**
@@ -100,13 +175,30 @@ export declare function declaresBlobStore(version: object): boolean;
100
175
  * positive safe integer is left out rather than trusted, and a limit not announced is absent, so a
101
176
  * bare runner, which announces none, yields no limit.
102
177
  */
103
- export declare function announcedTreeLimits(version: object): MethodTreeLimits;
178
+ export declare function announcedTreeLimits(version: object): AnnouncedTreeLimits;
179
+ /** The announced limits as the lister takes them, so it stops at the first breach before hashing. */
180
+ export declare function listerLimitsOf(announced: AnnouncedTreeLimits): MethodTreeLimits;
181
+ /**
182
+ * The inline threshold a tree is held to against a receiver keeping a blob store: the lower of
183
+ * `INLINE_TREE_MAX_BYTES` and the inline limit the receiver announces, as `mthds`'s
184
+ * `MthdsApiClient` reads it.
185
+ */
186
+ export declare function inlineThreshold(announced: AnnouncedTreeLimits): number;
104
187
  /** What an inline map spends in a request: its JSON serialization with no whitespace, in UTF-8. */
105
188
  export declare function inlineMapBytes(files: MethodFiles): number;
106
189
  /** The total of a tree's file sizes, in bytes. */
107
190
  export declare function treeTotalSize(tree: MethodTreeSource): number;
108
- /** Every file's bytes, by tree path, each read and checked by the tree, one file at a time. */
109
- export declare function readTreeBytes(tree: MethodTreeSource): Promise<Map<string, Uint8Array>>;
191
+ /**
192
+ * Every file's bytes, by tree path, each read and checked by the tree, one file at a time. `signal`
193
+ * is read before each file: once it has aborted, no further file is read and the abort is thrown.
194
+ */
195
+ export declare function readTreeBytes(tree: MethodTreeSource, signal?: AbortSignal): Promise<Map<string, Uint8Array>>;
196
+ /**
197
+ * Every file's bytes, by tree path, read into `read`: a file already there is not read again, so
198
+ * a request that weighs a tree and then uploads from it, or prepares it a second time, reads each
199
+ * file once. `signal` is read before each file read, as `readTreeBytes` reads it.
200
+ */
201
+ export declare function readTreeBytesInto(tree: MethodTreeSource, read: Map<string, Uint8Array>, signal?: AbortSignal): Promise<Map<string, Uint8Array>>;
110
202
  /** The whole tree as inline entries, from bytes already read by `readTreeBytes`. */
111
203
  export declare function inlineFilesOf(tree: MethodTreeSource, bytesByPath: ReadonlyMap<string, Uint8Array>): MethodFiles;
112
204
  /** The whole tree as hash entries, which the platform resolves in the organization's blobs. */
@@ -121,15 +213,56 @@ export declare function fileByBlob(tree: MethodTreeSource): Map<string, MethodTr
121
213
  * early, and once they have settled the first failure is thrown.
122
214
  */
123
215
  export declare function forEachConcurrently<T>(items: readonly T[], limit: number, task: (item: T, signal: AbortSignal) => Promise<void>): Promise<void>;
216
+ /**
217
+ * Whether an answer refuses a tree as past one of the receiver's limits, as `mthds`'s
218
+ * `MthdsApiClient` reads one: a `422` whose problem is the core registry's
219
+ * `method.package_invalid` carrying its numeric `limit` parameter, the hosted platform's
220
+ * `method_tree_too_large` code, or pipelex-api's `MethodTreeTooLarge` error type.
221
+ */
222
+ export declare function isMethodTreeTooLarge(status: number, body: string): boolean;
223
+ /**
224
+ * The blobs a `422` lists as missing, as `mthds`'s `MthdsApiClient` reads them: the
225
+ * `params.missing_blobs` of a problem coded `request.blobs_missing`, or `undefined` when the
226
+ * answer is no such problem or the list holds anything but strings.
227
+ */
228
+ export declare function missingBlobsOf(status: number, body: string): string[] | undefined;
229
+ /**
230
+ * A signal that aborts when either does, with the reason of the first to abort, and `dispose`,
231
+ * which detaches it from both once it is no longer needed, so a long-lived signal does not keep
232
+ * a listener per call. `second` absent gives `first` itself. Built by hand rather than with
233
+ * `AbortSignal.any`, which older browsers lack.
234
+ */
235
+ export declare function eitherSignal(first: AbortSignal, second: AbortSignal | undefined): {
236
+ signal: AbortSignal;
237
+ dispose: () => void;
238
+ };
124
239
  /**
125
240
  * The tree whose files are `contents`, each file's bytes or its text by tree path, a text encoded
126
241
  * in UTF-8. The keys are sent as they are, and the platform refuses one that is not a tree path,
127
242
  * with the `422` `invalid_method_files` naming it. `call` names the caller's method in a refusal.
128
243
  *
129
244
  * Throws `RequestArgumentError` for `contents` holding no file, for a value that is neither a
130
- * string nor bytes, and for a text holding a lone surrogate, which no file can hold.
245
+ * string nor bytes, and for a text holding a lone surrogate, which no file can hold. `sending` says
246
+ * what the tree is for, which the refusal of an empty one names.
247
+ */
248
+ export declare function contentsTreeSource(contents: Readonly<Record<string, Uint8Array | string>>, call: string, sending: TreeSending): Promise<MethodTreeSource>;
249
+ /** A tree listed from the file system: its files, and the absolute path of its root. */
250
+ export interface ListedMethodTree extends MethodTreeSource {
251
+ /** The absolute path of the root, or `null` for the one-file tree of a `.mthds` file alone. */
252
+ readonly root: string | null;
253
+ }
254
+ /**
255
+ * The tree of the method directory `directory`, listed by the `mthds` package's `listMethodTree`
256
+ * under the MTHDS standard's membership rule and Manifest Discovery, stopping at the first of
257
+ * `limits` it breaches, before any file is hashed. A run's inputs file is never in it. Node only:
258
+ * `mthds`'s root entry, which reads the file system, is loaded by this call alone.
259
+ *
260
+ * Throws `RequestArgumentError` naming `call` when the directory cannot be listed as a tree, the
261
+ * `mthds` package's `MethodTreeError` as its `cause` with its `code` (`not_found`,
262
+ * `symbolic_link`, `limit_exceeded`, `empty_tree` and the rest): a path that names nothing, a
263
+ * symbolic link or a special file in the tree, a tree past one of `limits`, a tree holding no file.
131
264
  */
132
- export declare function contentsTreeSource(contents: Readonly<Record<string, Uint8Array | string>>, call: string): Promise<MethodTreeSource>;
265
+ export declare function listDirectoryTree(directory: string, limits: MethodTreeLimits, call: string): Promise<ListedMethodTree>;
133
266
  /**
134
267
  * The tree digest of a tree's files: `sha256:` and the SHA-256 of its listing, one line
135
268
  * `<sha256> <path>` per file, in tree path order.
@@ -162,11 +295,13 @@ export declare function encodeBase64(bytes: Uint8Array): string;
162
295
  *
163
296
  * Throws `MethodFileTransferError` (`operation` `upload`) when storage gives no answer within
164
297
  * `timeoutMs` or answers any other non-2xx; neither its message nor any member carries the URL,
165
- * nor storage's error body, which can echo the signed request.
298
+ * nor storage's error body, which can echo the signed request. Its message ends with what did not
299
+ * happen because of it, `options.unsent`.
166
300
  */
167
301
  export declare function uploadBlob(blob: MissingBlob, bytes: Uint8Array, options: {
168
302
  timeoutMs: number;
169
303
  signal?: AbortSignal;
304
+ unsent: string;
170
305
  }): Promise<void>;
171
306
  /**
172
307
  * The code of a transfer storage answered with a non-2xx `status`: `storage_error` for one the