@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/dist/index.d.ts CHANGED
@@ -21,7 +21,7 @@ export type { GrantedUpload, UploadWithGrantOptions } from "./upload-grant.js";
21
21
  export type { PrepareInputsBase, PrepareInputsClosure, PrepareInputsRequest, PreparedInputs, } from "./prepare-inputs.js";
22
22
  export { locateArtifacts, collectArtifacts, artifactFilename, PIPELEX_STORAGE_SCHEME, BULK_RESOLVE_MAX_URIS, DEFAULT_ARTIFACT_MAX_BYTES, DEFAULT_ARTIFACT_TIMEOUT_MS, DEFAULT_DOWNLOAD_MAX_TOTAL_BYTES, DEFAULT_DOWNLOAD_CONCURRENCY, } from "./artifacts.js";
23
23
  export type { ArtifactItemError, ArtifactLocation, ArtifactScope, BulkResolveStorageUrlsInput, BulkResolvedStorageUrls, DownloadArtifactsOptions, DownloadArtifactsRequest, DownloadArtifactsResult, DownloadedArtifact, FetchArtifactOptions, ResolvedArtifact, } from "./artifacts.js";
24
- export type { DiagnosticKind, DiagnosticRange, Diagnostic, LintResponse, FormatResponse, DictStuff, DictWorkingMemory, DictPipeOutput, DictRunResultExecute, MethodProvenance, PipelexRunResultStart, PipelexHostedToolingExtensions, DryRunStatus, ValidatedPipeEntry, LiftablePipeEntry, PipelexValidationReport, PipelexInvalidReport, PipelexValidationResult, ValidationErrorCategory, ValidationErrorItem, FixSafety, FixOpKind, TomlScalar, TomlValue, FixValue, SetKeyOp, EnsureTableOp, DeleteKeyOp, DeleteTableOp, RenameTableKeyOp, MoveKeyOp, RemapValueOp, FixOp, SuggestedFix, ConceptRepresentationFormat, InputsTemplateFormat, MthdsFileItem, CrateRequestBase, BuildRequestBase, BuildInputsRequest, BuildOutputRequest, BuildRunnerRequest, ConceptRequest, PipeSpecRequest, CrateInvalidReport, BuildInputsValidReport, BuildOutputValidReport, BuildRunnerValidReport, GeneratedArtifact, RunnerStructures, BuildInputsResponse, BuildOutputResponse, BuildRunnerResponse, ConceptResponse, PipeSpecResponse, ResolveRequest, ResolveValidReport, ResolveResponse, CodegenKind, CodegenTarget, CodegenRequest, CodegenValidReport, CodegenResponse, PipeIORequest, PipeIOValidReport, PipeIOResponse, } from "./models.js";
24
+ export type { DiagnosticKind, DiagnosticRange, Diagnostic, LintResponse, FormatResponse, DictStuff, DictWorkingMemory, DictPipeOutput, DictRunResultExecute, MethodProvenance, PipelexRunResultStart, PipelexHostedToolingExtensions, DryRunStatus, ValidatedPipeEntry, LiftablePipeEntry, PipelexValidationReport, PipelexInvalidReport, PipelexValidationResult, ValidationErrorCategory, ValidationErrorItem, FixSafety, FixOpKind, TomlScalar, TomlValue, FixValue, SetKeyOp, EnsureTableOp, DeleteKeyOp, DeleteTableOp, RenameTableKeyOp, MoveKeyOp, RemapValueOp, FixOp, SuggestedFix, MthdsFileItem, CrateRequestBase, CrateInvalidReport, GeneratedArtifact, ResolveRequest, ResolveValidReport, ResolveResponse, CodegenKind, CodegenTarget, CodegenRequest, CodegenValidReport, CodegenResponse, PipeIORequest, PipeIOValidReport, PipeIOResponse, } from "./models.js";
25
25
  export { runCodegenCheck, isStampableArtifactPath, STAMPABLE_ARTIFACT_SUFFIXES, CodegenLockError, } from "./codegen-check.js";
26
26
  export type { CodegenCheckInput, CodegenCheckReport, CodegenDrift, CodegenDriftCategory, CodegenTreeFile, } from "./codegen-check.js";
27
27
  export type { UserProfile, ListMethodsQuery, MethodData, MethodDeletionAccepted, MethodDeletionState, MethodPage, MethodSummary, MethodWriteInput, Membership, MembershipsResponse, SubscriptionResponse, PlanView, InvoiceView, CheckoutResponse, ChangePlanResponse, BillingPortalResponse, PipelexApiKey, PipelexApiKeyCreated, PipelexApiKeyList, OnboardingRole, OnboardingCurrentTool, OnboardingInputType, OnboardingHeardFrom, OnboardingSubmission, ResolvedStorageUrl, UploadInput, UploadedFile, UploadGrantInput, UploadGrant, PipeStatus, ListRunsQuery, PipelineRun, RunDetail, RunHistoryItem, RunPage, UpdateRunInput, } from "./product-models.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,6FAA6F;AAC7F,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,oFAAoF;AACpF,kFAAkF;AAClF,mFAAmF;AACnF,wBAAwB;AACxB,cAAc,gBAAgB,CAAC;AAE/B,wEAAwE;AACxE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACrE,sFAAsF;AACtF,yFAAyF;AACzF,2EAA2E;AAC3E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAazF,+FAA+F;AAC/F,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,iGAAiG;AACjG,kFAAkF;AAClF,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAK/E,yFAAyF;AACzF,sEAAsE;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AASpD,uEAAuE;AACvE,wFAAwF;AACxF,0FAA0F;AAC1F,iFAAiF;AACjF,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,gCAAgC,EAChC,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAqFxB,+EAA+E;AAC/E,4EAA4E;AAC5E,iFAAiF;AACjF,0EAA0E;AAC1E,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAiD5B,wEAAwE;AACxE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAa1F,oFAAoF;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAS5C,+EAA+E;AAC/E,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,4BAA4B,EAC5B,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,gCAAgC,EAChC,yBAAyB,EACzB,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,6FAA6F;AAC7F,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,oFAAoF;AACpF,kFAAkF;AAClF,mFAAmF;AACnF,wBAAwB;AACxB,cAAc,gBAAgB,CAAC;AAE/B,wEAAwE;AACxE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACrE,sFAAsF;AACtF,yFAAyF;AACzF,2EAA2E;AAC3E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAazF,+FAA+F;AAC/F,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,iGAAiG;AACjG,kFAAkF;AAClF,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAK/E,yFAAyF;AACzF,sEAAsE;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AASpD,uEAAuE;AACvE,wFAAwF;AACxF,0FAA0F;AAC1F,iFAAiF;AACjF,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,gCAAgC,EAChC,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAoExB,+EAA+E;AAC/E,4EAA4E;AAC5E,iFAAiF;AACjF,0EAA0E;AAC1E,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAiD5B,wEAAwE;AACxE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAa1F,oFAAoF;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAS5C,+EAA+E;AAC/E,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,4BAA4B,EAC5B,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,gCAAgC,EAChC,yBAAyB,EACzB,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
package/dist/models.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * Holds the Dict-serialized protocol concretes (`DictStuff` / `DictWorkingMemory`
5
5
  * / `DictPipeOutput` and the default `RunResultExecute` binding), the Pipelex
6
6
  * `/v1/validate` surface (`PipelexValidationResult` + `ValidationErrorItem`), and
7
- * the `/v1/build/*` request/response models. Built on the protocol wire types
8
- * imported from the `mthds/protocol` subpath.
7
+ * the request/response models of the tools routes and the crate routes. Built on
8
+ * the protocol wire types imported from the `mthds/protocol` subpath.
9
9
  */
10
10
  import type { InputForm, OutputForm, InvalidValidationReport, PipeIOContracts, RunResultExecute, RunResultStart, ValidationReport } from "mthds/protocol";
11
11
  export interface DictStuff {
@@ -75,8 +75,7 @@ export interface PipelexRunResultStart extends RunResultStart {
75
75
  * one of inline source / `method_ref` / `method_id` per request — any second
76
76
  * selector is a request-shape `422`. An unknown or foreign-org id is a `404`
77
77
  * (indistinguishable by design); a stored method with no MTHDS source is a
78
- * `422`. The `/v1/build/*` projections are deliberately excluded — they take
79
- * no `method_id` (expand a stored method with `getMethodClosure` there).
78
+ * `422`.
80
79
  */
81
80
  export interface PipelexHostedToolingExtensions {
82
81
  /** A stored method's catalog id (`mt_…`) — hosted-only, resolved server-side. */
@@ -274,7 +273,7 @@ export type ValidationErrorCategory = "blueprint_validation" | "pipe_factory" |
274
273
  * One structured bundle-validation error — mirror of pipelex's `ValidationErrorItem`.
275
274
  * Carried by `PipelexInvalidReport.validation_errors[]` on the **200** invalid arm of
276
275
  * `POST /v1/validate` (NOT a 422 — an invalid bundle is a produced verdict), by the
277
- * VALID arm's advisory `warnings[]`, by the build and crate routes' **200** invalid arm
276
+ * VALID arm's advisory `warnings[]`, by the crate routes' **200** invalid arm
278
277
  * (`CrateInvalidReport.validation_errors[]`), by the 422 problem body a run route answers
279
278
  * when the runner refuses the method for its validation errors
280
279
  * (`ApiResponseError.validationErrors`), and by a failed run's stored report.
@@ -462,11 +461,8 @@ export interface FormatResponse {
462
461
  changed: boolean;
463
462
  diagnostics: Diagnostic[];
464
463
  }
465
- export type ConceptRepresentationFormat = "json" | "python" | "schema";
466
- /** Encoding of a `/v1/build/inputs` template. Decides which field carries it back. */
467
- export type InputsTemplateFormat = "json" | "toml";
468
464
  /**
469
- * One MTHDS file in a build closure. `source` is an optional provenance label (a
465
+ * One MTHDS file in a crate closure. `source` is an optional provenance label (a
470
466
  * filename, a URI) that the server threads onto every diagnostic it raises from
471
467
  * this file, so an invalid verdict can point at the file that caused it.
472
468
  *
@@ -481,11 +477,13 @@ export interface MthdsFileItem {
481
477
  source?: string;
482
478
  }
483
479
  /**
484
- * The closure selector every crate-family route shares — `/v1/resolve`, `/v1/codegen`,
485
- * `/v1/pipe-io`, and `/v1/build/*` (mirror of the server's `MthdsFilesRequest`).
480
+ * The closure selector every crate route shares — `/v1/resolve`, `/v1/codegen` and
481
+ * `/v1/pipe-io` (mirror of the server's `MthdsFilesRequest`).
486
482
  *
487
483
  * Supply the closure EITHER as inline `files` OR as a `method_ref` — never both, and
488
- * never neither (both arms are a request-shape `422`). An **address-form** `method_ref`
484
+ * never neither (both arms are a request-shape `422`); the hosted `method_id` joins
485
+ * them as a third form on each route's own request (see
486
+ * {@link PipelexHostedToolingExtensions}). An **address-form** `method_ref`
489
487
  * (`github.com/<owner>/<repo>[/<selector>][@<tag>]`) is resolved by the server
490
488
  * (pipelex-api >= 0.21.0): the repository is fetched at the tag, the package is
491
489
  * located by manifest identity, and its `.mthds` files feed the closure with their
@@ -494,162 +492,29 @@ export interface MthdsFileItem {
494
492
  *
495
493
  * The XOR is a server-side invariant, not a type-level one: expressing it as a union
496
494
  * here would make the common `{ files }` call site pick a branch for no gain, and the
497
- * server rejects the two illegal shapes with a typed `ApiResponseError` either way.
495
+ * server rejects the illegal shapes with a typed `ApiResponseError` either way.
498
496
  */
499
497
  export interface CrateRequestBase {
500
498
  files?: MthdsFileItem[];
501
499
  method_ref?: string;
502
500
  }
503
501
  /**
504
- * The crate envelope plus the pipe selector the `/v1/build/*` projections add
505
- * (mirror of the server's `MthdsPipeRequest`).
506
- */
507
- export interface BuildRequestBase extends CrateRequestBase {
508
- /**
509
- * The pipe to project, as a QUALIFIED `domain.pipe_code` ref. Omit it to default
510
- * to the closure's declared `main_pipe` — which fails (422) when the closure
511
- * declares none, or declares several across its domains.
512
- */
513
- pipe_ref?: string;
514
- /**
515
- * The `/v1/build/*` projections take NO `method_id` — the hosted platform's
516
- * tooling selector covers `validate`/`resolve`/`codegen`/`pipe-io` only, and the build
517
- * routes are deliberately excluded (they are frozen, being replaced by the
518
- * codegen surface). Pinned to `never` so a stored-method caller reaches for
519
- * `getMethodClosure` instead of a field no server resolves.
520
- */
521
- method_id?: never;
522
- }
523
- export interface BuildInputsRequest extends BuildRequestBase {
524
- /** `json` (default) puts the parsed template in `inputs`; `toml` puts raw text in `inputs_toml`. */
525
- format?: InputsTemplateFormat;
526
- /** Emit the ceremonial `{concept, content}` envelope per input. Defaults to the light shape. */
527
- explicit?: boolean;
528
- }
529
- export interface BuildOutputRequest extends BuildRequestBase {
530
- /** `schema` (default) and `json` put a parsed object in `output`; `python` puts source in `output_python`. */
531
- format?: ConceptRepresentationFormat;
532
- }
533
- export interface BuildRunnerRequest extends BuildRequestBase {
534
- /**
535
- * Accept unresolved pipe signatures as pending rather than invalid. Alone among
536
- * the build routes this one still runs the dry-run sweep, and the flag only ever
537
- * parameterized that sweep.
538
- */
539
- allow_signatures?: boolean;
540
- }
541
- export interface ConceptRequest {
542
- spec: Record<string, unknown>;
543
- }
544
- export interface PipeSpecRequest {
545
- pipe_type: string;
546
- spec: Record<string, unknown>;
547
- }
548
- /**
549
- * The `is_valid: false` arm shared by every crate-family route — `/v1/build/*`,
550
- * `/v1/resolve`, `/v1/codegen`, and `/v1/pipe-io` (mirror of the server's one
551
- * `CrateInvalidReport`).
502
+ * The `is_valid: false` arm shared by every crate route — `/v1/resolve`,
503
+ * `/v1/codegen` and `/v1/pipe-io` (mirror of the server's one `CrateInvalidReport`).
552
504
  *
553
505
  * They all follow `/validate`'s discipline: an unresolvable closure is the
554
506
  * *successful product* of the call (the request was well-formed, the library was
555
507
  * not), so it rides a **200** discriminated on `is_valid` — never a 4xx. Only a
556
508
  * no-verdict condition throws `ApiResponseError`: a request the route cannot act on
557
- * (an unknown `pipe_ref` on the build routes and `pipe-io`, an unknown `kind`/`target`
558
- * on codegen), the reserved `method_ref`, auth, a server fault. Branch on `is_valid`,
559
- * never on the transport.
509
+ * (a pipe selection `pipe-io` refuses, an unknown `kind`/`target` on codegen), the
510
+ * reserved `method_ref`, auth, a server fault. Branch on `is_valid`, never on the
511
+ * transport.
560
512
  */
561
513
  export interface CrateInvalidReport {
562
514
  is_valid: false;
563
515
  validation_errors: ValidationErrorItem[];
564
516
  message: string;
565
517
  }
566
- /** Fields the valid arm of every `/v1/build/*` route carries. */
567
- interface BuildValidReportBase {
568
- is_valid: true;
569
- /** The qualified pipe that was projected — the RESOLVED selector, always `domain.pipe_code`. */
570
- pipe_ref: string;
571
- /** The `pipe_ref` as submitted. Absent when it was omitted and defaulted to `main_pipe`. */
572
- requested_pipe_ref?: string;
573
- message: string;
574
- }
575
- /**
576
- * The `/v1/build/inputs` valid arm. The template rides ONE of two fields, chosen by
577
- * `format`: `inputs` (a parsed object) for `json`, `inputs_toml` (raw text) for
578
- * `toml`. TOML cannot be carried as a parsed object without losing what makes it
579
- * worth asking for — its concept comments and key order — so the two are separate
580
- * fields and the unused one is absent from the body entirely.
581
- *
582
- * That "absent entirely" is why this is a union rather than one interface with two
583
- * optional fields: `format` is a real discriminant, so narrowing on it hands you the
584
- * field it selected as REQUIRED, with the other one statically unreachable.
585
- */
586
- interface BuildInputsJsonReport extends BuildValidReportBase {
587
- format: "json";
588
- explicit: boolean;
589
- inputs: Record<string, unknown>;
590
- inputs_toml?: never;
591
- }
592
- interface BuildInputsTomlReport extends BuildValidReportBase {
593
- format: "toml";
594
- explicit: boolean;
595
- inputs?: never;
596
- inputs_toml: string;
597
- }
598
- export type BuildInputsValidReport = BuildInputsJsonReport | BuildInputsTomlReport;
599
- export type BuildInputsResponse = BuildInputsValidReport | CrateInvalidReport;
600
- /**
601
- * The `/v1/build/output` valid arm. Same two-field split as the inputs template, for
602
- * the same reason: `schema` and `json` are objects, `python` is source text — and so
603
- * it is a discriminated union for the same reason too.
604
- */
605
- interface BuildOutputObjectReport extends BuildValidReportBase {
606
- format: "schema" | "json";
607
- output: Record<string, unknown>;
608
- output_python?: never;
609
- }
610
- interface BuildOutputPythonReport extends BuildValidReportBase {
611
- format: "python";
612
- output?: never;
613
- output_python: string;
614
- }
615
- export type BuildOutputValidReport = BuildOutputObjectReport | BuildOutputPythonReport;
616
- export type BuildOutputResponse = BuildOutputValidReport | CrateInvalidReport;
617
- /**
618
- * One stamped generated file — shared by `/v1/build/runner`'s structures projection
619
- * and `/v1/codegen`'s artifact set. `path` is relative to the output root the client
620
- * chooses; `content` is complete, stamp header included, and is written verbatim.
621
- */
622
- export interface GeneratedArtifact {
623
- path: string;
624
- content: string;
625
- }
626
- /**
627
- * The typed-structures projection the runner script imports from. Write `artifacts`
628
- * and `lock` (as `lock_filename`) under `directory`, relative to the runner script,
629
- * and the returned `python_code` runs against them.
630
- */
631
- export interface RunnerStructures {
632
- directory: string;
633
- artifacts: GeneratedArtifact[];
634
- lock: string;
635
- lock_filename: string;
636
- }
637
- export interface BuildRunnerValidReport extends BuildValidReportBase {
638
- python_code: string;
639
- structures: RunnerStructures;
640
- }
641
- export type BuildRunnerResponse = BuildRunnerValidReport | CrateInvalidReport;
642
- export interface ConceptResponse {
643
- success: boolean;
644
- concept_code: string;
645
- toml: string;
646
- }
647
- export interface PipeSpecResponse {
648
- success: boolean;
649
- pipe_code: string;
650
- pipe_type: string;
651
- toml: string;
652
- }
653
518
  /**
654
519
  * `POST /v1/resolve` request — the crate envelope (no projection axes) plus the
655
520
  * hosted `method_id` selector. Exactly one of `files` / `method_ref` /
@@ -687,7 +552,8 @@ export type ResolveResponse = ResolveValidReport | CrateInvalidReport;
687
552
  * projected into typed models) is the only kind served today; the future per-pipe kinds
688
553
  * (`docs`, `tools`, `tests`) join it and select their pipe via `pipe_ref`. Input templates
689
554
  * are deliberately NOT a kind here — they are user-editable scaffolds, never stamped or
690
- * locked, and ride `POST /v1/build/inputs` instead.
555
+ * locked, and a client projects one from the input-form descriptor `/v1/pipe-io` returns
556
+ * (`renderInputsTemplate`, from `mthds/protocol`).
691
557
  */
692
558
  export type CodegenKind = "types";
693
559
  /**
@@ -712,6 +578,15 @@ export interface CodegenRequest extends CrateRequestBase, PipelexHostedToolingEx
712
578
  */
713
579
  pipe_ref?: string;
714
580
  }
581
+ /**
582
+ * One stamped generated file of `/v1/codegen`'s artifact set. `path` is relative to the
583
+ * output root the client chooses; `content` is complete, stamp header included, and is
584
+ * written verbatim.
585
+ */
586
+ export interface GeneratedArtifact {
587
+ path: string;
588
+ content: string;
589
+ }
715
590
  /**
716
591
  * The `/v1/codegen` valid arm — the stamped artifact set plus its lock.
717
592
  *
package/dist/models.js CHANGED
@@ -4,8 +4,8 @@
4
4
  * Holds the Dict-serialized protocol concretes (`DictStuff` / `DictWorkingMemory`
5
5
  * / `DictPipeOutput` and the default `RunResultExecute` binding), the Pipelex
6
6
  * `/v1/validate` surface (`PipelexValidationResult` + `ValidationErrorItem`), and
7
- * the `/v1/build/*` request/response models. Built on the protocol wire types
8
- * imported from the `mthds/protocol` subpath.
7
+ * the request/response models of the tools routes and the crate routes. Built on
8
+ * the protocol wire types imported from the `mthds/protocol` subpath.
9
9
  */
10
10
  export {};
11
11
  //# sourceMappingURL=models.js.map
package/dist/version.d.ts CHANGED
@@ -3,4 +3,4 @@
3
3
  * `User-Agent` without importing the public barrel. Kept in sync with
4
4
  * `package.json` — enforced by `tests/index.test.ts`.
5
5
  */
6
- export declare const SDK_VERSION = "0.29.1";
6
+ export declare const SDK_VERSION = "0.30.0";
package/dist/version.js CHANGED
@@ -3,5 +3,5 @@
3
3
  * `User-Agent` without importing the public barrel. Kept in sync with
4
4
  * `package.json` — enforced by `tests/index.test.ts`.
5
5
  */
6
- export const SDK_VERSION = "0.29.1";
6
+ export const SDK_VERSION = "0.30.0";
7
7
  //# sourceMappingURL=version.js.map
@@ -9,6 +9,8 @@
9
9
  - read the model deck and version handshake (`models` / `version`),
10
10
  - and reach the Pipelex product surface (user profile, methods catalog, organizations, billing, API keys, onboarding, storage).
11
11
 
12
+ `models` returns the deck as the runner sent it, with no runtime check, and types each entry's `type` as `ModelCategory | (string & {}) | null`: a category `mthds` defines, `judgment` among them, or the raw value of one this version does not define, which the MTHDS Protocol requires a client reading a model list to keep rather than fail on.
13
+
12
14
  ## Dependency direction (one-way)
13
15
 
14
16
  ```
@@ -23,7 +25,7 @@
23
25
  ## Brand boundary
24
26
 
25
27
  - **MTHDS-branded (lives in `mthds`):** protocol wire models, the standard `ValidationReport` / `ValidationResult` shapes, `.mthds` utilities, the `MthdsProtocolClient`.
26
- - **Pipelex-branded (lives here):** `PipelexApiClient`, run store / durable lifecycle, build helpers, `PipelexValidationResult`, hosted-product typed errors, API keys / orgs / billing / methods catalog / storage / onboarding.
28
+ - **Pipelex-branded (lives here):** `PipelexApiClient`, run store / durable lifecycle, the crate and tools routes, `PipelexValidationResult`, hosted-product typed errors, API keys / orgs / billing / methods catalog / storage / onboarding.
27
29
  - Inside a Pipelex envelope, field names stay neutral (`bundle_blueprint`, `pipe_io_contracts`, `input_form`, `liftable_pipes`, `graph_spec`) — Pipelex branding is reserved for genuinely runtime-specific envelopes.
28
30
 
29
31
  ## Module format & packaging
@@ -72,7 +74,7 @@ A run request carries its method inline exactly one of three ways: `mthds_conten
72
74
 
73
75
  - **It is a named option, not an `extra` entry.** Typing its own platform's arguments is the one job a layer-3 client exists to do; `extra` stays the escape hatch for extensions this client does not know about (a third-party server, or a newer version of ours). That split, and the reserved-keys guard that enforces it, are normative for every client in the layered stack: a client types the arguments of the platform it is built for, and only the layer that owns an argument may validate or reject it. It was previously passed as `extra: { method_id }`, which worked but documented nothing and validated nothing.
74
76
  - **The guard is per layer.** `method_id` is reserved on `extra` _here_ and must never become reserved in `mthds` / `mthds-python`: a protocol client talking to another vendor's server has no business rejecting that vendor's arguments.
75
- - **Pure pass-through — nothing is expanded client-side.** The platform resolves the id against the org's catalog. The same posture holds across the tooling routes: `validate` / `resolve` / `codegen` / `pipeIo` take a typed `method_id` the platform resolves server-side (see the surface list below), and so does `prepareInputs`, which composes a `pipeIo` of its own. `/v1/build/*` is the last family with no by-id form — it takes `files` only, and a stored method is expanded explicitly with `getMethodClosure`, which stays public as the local expansion utility.
77
+ - **Pure pass-through — nothing is expanded client-side.** The platform resolves the id against the org's catalog. The same posture holds across the tooling routes: `validate` / `resolve` / `codegen` / `pipeIo` take a typed `method_id` the platform resolves server-side (see the surface list below), and so does `prepareInputs`, which composes a `pipeIo` of its own. `getMethodClosure` stays public as the local expansion utility, for a caller that wants a stored method's files in hand or talks to a bare runner, which has no catalog to resolve an id against.
76
78
  - **Alone it is a run source; alongside an inline source it is linkage.** With no inline source the platform resolves and runs the stored method. With one, the inline source is what RUNS (precedence) and the id is recorded as run-history linkage on the Run row — the index key `GET /v1/runs?method_id=` queries. Rejecting the combination is not an option: it once orphaned every unsaved-bundle run from its method. The client therefore counts `method_id` towards its "something to run" precondition, and never treats it as an exclusivity violation.
77
79
  - **It rides the blocking fallback too.** `startAndWaitForResult` degrades to `POST /v1/execute` against a runner with no run store, and the selector goes with it — so a bare `pipelex-api` answers a `422` that names the key (its Rule 4 diagnosis: "a hosted-only selector must be sent to the hosted API") instead of the client silently dropping it and running something else.
78
80
  - **An empty string is treated as absent.** `method_id: ""` selects no method and links nothing, so it is not sent and does not satisfy the precondition.
@@ -82,7 +84,7 @@ A run request carries its method inline exactly one of three ways: `mthds_conten
82
84
  Flat `src/` (mirrors `mthds-js`'s `runners/api` flatness — the SDK has one client, so no runner/registry abstraction):
83
85
 
84
86
  - `client.ts` — `PipelexApiClient`: the `request()` pipeline (auth, base URL, timeouts/abort, problem-details parsing) and every route. `implements MTHDSProtocol<DictPipeOutput>` so the protocol-execution methods stay shaped like the standard.
85
- - `models.ts` — Dict-serialized concretes (`DictStuff` / `DictWorkingMemory` / `DictPipeOutput` / `DictRunResultExecute`), the `/v1/validate` surface (`PipelexValidationResult`, `ValidationErrorItem`, and the `SuggestedFix` / `FixOp` repair vocabulary its items carry — the standard's declarations, restated because `mthds` exports them only from its package root and pinned to it by a type-level test, see [errors.md](./errors.md#a-validation-item--validationerroritem)), the tools surface (`Diagnostic` / `LintResponse` / `FormatResponse`), and the crate-family request/response models — the shared `CrateRequestBase` / `CrateInvalidReport` / `GeneratedArtifact` vocabulary plus the `/v1/build/*`, `/v1/resolve` and `/v1/codegen` shapes built on it.
87
+ - `models.ts` — Dict-serialized concretes (`DictStuff` / `DictWorkingMemory` / `DictPipeOutput` / `DictRunResultExecute`), the `/v1/validate` surface (`PipelexValidationResult`, `ValidationErrorItem`, and the `SuggestedFix` / `FixOp` repair vocabulary its items carry — the standard's declarations, restated because `mthds` exports them only from its package root and pinned to it by a type-level test, see [errors.md](./errors.md#a-validation-item--validationerroritem)), the tools surface (`Diagnostic` / `LintResponse` / `FormatResponse`), and the crate-route request/response models — the shared `MthdsFileItem` / `CrateRequestBase` / `CrateInvalidReport` vocabulary plus the `/v1/resolve`, `/v1/codegen` and `/v1/pipe-io` shapes built on it, `GeneratedArtifact` among them.
86
88
  - `product-models.ts` — the snake_case wire shapes for the hosted-product management routes (profile, methods catalog, organizations, billing, API keys, onboarding, storage, runs list/detail/update). Each interface models only the fields the product actually consumes — no speculative mirrors.
87
89
  - `error-models.ts` — the error-report wire models: `RunErrorReport`, the runner's `ErrorReport` typed with every field it carries (with `UserAction`, `ProviderErrorMetadata` and `MigrationErrorBlock`), which is the one type for a failed run's report on `RunPublic.error`, `PipelineRun.error`, `RunHistoryItem.error`, the failed arm of `RunResultState` and `RunFailedError.error`; and `ProblemDetails` / `FieldError`, the typed members of a problem document that `ApiResponseError` exposes. Every field is optional and every interface keeps an index signature, because the runner owns the shape and adds fields without asking. Types only: it imports the `ValidationErrorItem` type and nothing else. See [errors.md](./errors.md).
88
90
  - `method-source.ts` — `methodSourceToContents`, the canonical parser turning a stored method's polymorphic `mthds` source (raw single-bundle text XOR a JSON `{name, content}[]` file array) into a flat list of file contents. A verbatim port of the platform's `method_source_to_contents` so the SDK and runtime read a stored source identically; exported from the barrel and consumed by `getMethodClosure`. See [input-preparation.md](./input-preparation.md#getmethodclosure--the-explicit-expansion-utility).
@@ -105,8 +107,7 @@ Flat `src/` (mirrors `mthds-js`'s `runners/api` flatness — the SDK has one cli
105
107
  - **Method-bundle transport (pipelex-api extension):** `execute` / `start` / the blocking fallback accept the whole method — the `.mthds` plus its `funcs/*.py`, `structures/*.py`, `requirements.txt` — instead of only the inline `mthds_contents` text, so custom PipeFunc Python travels with the method. Two equivalent, mutually exclusive encodings: `files` (a `{ relativePath: text }` map) and `bundle_b64` (the same bundle as a base64 zip). A bundle is self-contained, so it satisfies the "something to run" precondition on its own — neither `pipe_code` nor `mthds_contents` is required beside it. See [run-sources](#run-sources) above.
106
108
  - **Method selectors on the run methods:** `execute` / `start` / `startAndWaitForResult` take the Pipelex API's `method_ref` (an address the runner resolves; provenance comes back typed as `method_provenance`) and the platform's `method_id` as **typed named options** (`PipelexRunOptions` / `PipelexStartOptions`), never `extra` entries. See [Pipelex API run extensions](#pipelex-api-run-extensions-method_ref) and [hosted run extensions](#hosted-run-extensions-method_id) above.
107
109
  - **Method selectors on `validate`:** the first argument is inline contents (`string[]`) or a `ValidateMethodSelector` — `{ method_ref }` (runner-resolved by address) or `{ method_id }` (hosted, platform-resolved) — under the strict tooling XOR: exactly one selector, no linkage exception, `mthds_sources` legal only beside inline contents. A selector-resolution failure is a non-2xx `ApiResponseError`, never an `is_valid: false` verdict.
108
- - **Build helpers (`/v1/build/*`):** `buildInputs`, `buildOutput`, `buildRunner`, `concept`, `pipeSpec`. The three projections share one closure envelope (`files: [{content, source?}]` XOR a `method_ref` — the address form server-resolved, the registry form still `501`) plus an optional **qualified** `pipe_ref` that defaults to the closure's `main_pipe`, and each returns a **discriminated 200 verdict** (`is_valid`) rather than a bare payload — same discipline as `validate`. The build routes take **no `method_id`** (`method_id?: never` on `BuildRequestBase`): the hosted tooling selector deliberately excludes them, so a stored method is expanded first with `getMethodClosure`. **Nothing inside this SDK calls them** — `prepareInputs` reads its signature from the input-form descriptor `pipeIo` returns — so they exist for external consumers only, and are retired with the rest of `/v1/build/*` once those consumers project the template client-side. See [build-routes.md](./build-routes.md).
109
- - **Crate routes (`/v1/resolve`, `/v1/codegen`, `/v1/pipe-io`):** `resolve` emits the **normalized library crate** (the MTHDS standard's Library Crate Format, fingerprint riding inside the payload); `codegen` projects that crate through two explicit axes — `kind` (`types`) × `target` (`ts-zod` / `python-pydantic` / `python-structures`) — into stamped artifacts plus their `codegen.lock`. They share the build routes' closure envelope and its **discriminated 200 verdict** (`CrateInvalidReport` is literally the same invalid arm), and additionally take the hosted `method_id` (`PipelexHostedToolingExtensions`) as a third closure form under the strict three-way XOR — a pass-through the platform resolves, meaningless against a bare runner. Writing the artifacts and lock verbatim reproduces a local `pipelex codegen types` run byte-for-byte, so the offline `pipelex codegen check` passes — the SDK stays transport-only and does not write files. Verifying such a tree afterwards is `runCodegenCheck`, a standalone pure helper rather than a client method, because it needs no server at all. `pipeIo` derives a method's three I/O artifacts — the standard's `PipeIOContracts`, `InputForm` and `OutputForm`, imported from `mthds/protocol` — for the pipe the route selects (the request's qualified `pipe_ref`, else the method's own entry pipe) or for every pipe under `all_pipes`, with the runnability facts beside them and the closure's files echoed on `include_files`, and it runs no dry run; a selection it refuses is a `422` typed `EntryPipeNotFoundError` or `EntryPipeAmbiguousError`. See [crate-routes.md](./crate-routes.md).
110
+ - **Crate routes (`/v1/resolve`, `/v1/codegen`, `/v1/pipe-io`):** `resolve` emits the **normalized library crate** (the MTHDS standard's Library Crate Format, fingerprint riding inside the payload); `codegen` projects that crate through two explicit axes — `kind` (`types`) × `target` (`ts-zod` / `python-pydantic` / `python-structures`) — into stamped artifacts plus their `codegen.lock`. All three share one closure envelope (`files: [{content, source?}]` XOR a `method_ref`, the address form server-resolved and the registry form a `501`) and return a **discriminated 200 verdict** (`is_valid`, with `CrateInvalidReport` as the shared invalid arm) rather than a bare payload, the same discipline as `validate`. They also take the hosted `method_id` (`PipelexHostedToolingExtensions`) as a third closure form under the strict three-way XOR — a pass-through the platform resolves, meaningless against a bare runner. Writing the artifacts and lock verbatim reproduces a local `pipelex codegen types` run byte-for-byte, so the offline `pipelex codegen check` passes — the SDK stays transport-only and does not write files. Verifying such a tree afterwards is `runCodegenCheck`, a standalone pure helper rather than a client method, because it needs no server at all. `pipeIo` derives a method's three I/O artifacts — the standard's `PipeIOContracts`, `InputForm` and `OutputForm`, imported from `mthds/protocol` — for the pipe the route selects (the request's qualified `pipe_ref`, else the method's own entry pipe) or for every pipe under `all_pipes`, with the runnability facts beside them and the closure's files echoed on `include_files`, and it runs no dry run; a selection it refuses is a `422` typed `EntryPipeNotFoundError` or `EntryPipeAmbiguousError`. See [crate-routes.md](./crate-routes.md).
110
111
  - **Tools (`/v1/lint`, `/v1/format`):** `lint`, `format` — single-file static diagnostics and canonical formatting, served by any pipelex-api runner (no inference, no bundle load). Both are **diagnostic endpoints** like `validate`: a malformed `.mthds` file is a produced verdict on a **200** carrying `diagnostics[]`, never a thrown error — `format` additionally echoes the content back unchanged with `changed: false`. Only a no-verdict condition is non-2xx: a malformed body, **malformed formatter `options`** (e.g. a non-numeric `column_width` ⇒ 422), auth, or a server fault, all mapped to the typed `ApiResponseError`. `lint` is the cheap static check (syntax / schema / semantic); it does not replace `validate`, which loads the bundle, resolves across files, and dry-runs the pipes.
111
112
  - **Durable run lifecycle (hosted extension — NOT protocol):** `getRunStatus`, `getRunResult` (with an optional `artifacts` selection sent as `?artifacts=`, see [run-results.md](./run-results.md#reading-only-some-artifacts--artifacts)), `waitForResult`, `startAndWaitForResult` (handshakes `/v1/version`, takes the durable start+poll path on a hosted deployment, and self-heals to the blocking `execute` against a bare runner). A run that ended without completing answers the results read with a `409` whose `run_status` and `error` members carry its status and its stored error report; `getRunResult` turns it into the `failed` arm (`status`, `message` from `detail`, `error`) and the waiting calls on the durable path into a `RunFailedError` carrying the same (the blocking fallback's failure is the runner's `ApiResponseError`), the status read from the member, or from the `detail` sentence on a platform that does not send it yet. The status read serves the same report as `RunRead.error`. See [errors.md](./errors.md#a-failed-run--runerrorreport). Reading what a completed run consumed is `summarizeUsage(results)`, a standalone pure helper rather than a client method, because it folds the usage pair the results already carry and needs no server. See [run-usage.md](./run-usage.md#summarizing-a-run--summarizeusage).
112
113
  - **Health:** `health` (origin-level `/health`).
@@ -133,4 +134,4 @@ The hosted catalog/account routes the webapp drives. All ride the same `{base}/v
133
134
  Two layers, split by whether a server is in the loop:
134
135
 
135
136
  - **Unit suites (`tests/*.test.ts`, `make test`):** mock the fetch boundary (`vi.spyOn(globalThis, "fetch")`) and pin the client's wire behavior — URLs, request bodies, status→error mapping, poll semantics. These run everywhere, including CI. The codegen-check suite is the exception that proves the rule: it has no server to mock, so it runs against **vendored real codegen output** under `tests/fixtures/codegen/` — artifacts and lock emitted by an actual `pipelex codegen types` run, committed beside the `.mthds` they came from. A hand-written stamp would only prove the port agrees with itself. The artifacts are vendored with a trailing `.txt` and their real names restored at load time, because `format:check`, `lint`, and `typecheck:test` all glob `tests/**/*.ts` — and a single reformatted byte would invalidate the very hash the fixture exists to pin.
136
- - **E2E suites (`tests/e2e/*.e2e.ts`, `make test-e2e`):** no mocks — they drive a **live pipelex-api server** (`PIPELEX_E2E_BASE_URL`, default `http://localhost:8081`) and verify the diagnostic-endpoint contract end-to-end with correct and malformed MTHDS bundles: clean content lints with zero diagnostics and formats to itself (idempotently), malformed content comes back as a 200 verdict (`diagnostics[]` on lint; `diagnostics[]` plus the content echoed back unchanged with `changed: false` on format; `is_valid: false` + `validation_errors[]` on validate), and malformed formatter options surface as a 422 `ApiResponseError`. The crate suite adds the case only a live server can settle: the `kind` / `target` vocabulary is a mirror of a Python `StrEnum` in another repo, so nothing but a real call proves the two still agree — and it cross-checks that `codegen`'s `crate_fingerprint` equals the `fingerprint` `resolve` returns for the same closure. It then runs `runCodegenCheck` over the artifacts and lock the server just emitted — verbatim first (current, with the lock header's fingerprint matching the response's), then mutated in memory once per drift category, for a `.ts` target and a `.py` one. The unit suite pins the port against vendored bytes; only this pins it against the stamp and lock bytes the server writes **today**, which is the pairing that matters when a consumer commits the server's artifacts and gates CI on the SDK's verdict about them. The same suite drives `pipeIo` across all three selectors: the artifacts under the resolved ref, their equality with `validate`'s views for the same closure, the `include_files` echo, `all_pipes` on a method with no entry pipe, a `method_ref` package's manifest entry pipe, the invalid arm, and the typed selection `422`. Its `method_id` case, like the `prepareInputs` suite's, runs only when `PIPELEX_E2E_METHOD_ID` names a stored method the key's organization owns, since only a hosted origin can resolve one, and is skipped otherwise. The distinct `.e2e.ts` suffix + `vitest.e2e.config.ts` keep them out of the default `vitest run`, so `make test` / CI never require a server. An unreachable server is an error, never a silent skip, and it is reported once: `make test-e2e` preflights the target with a single `curl` and bails with a one-line message, instead of letting all three suites fail in `beforeAll` and print a socket-error dump each. The per-suite `beforeAll` guard stays as the backstop for a direct `npm run test:e2e` run. Both probe **`/v1/version`**, deliberately: a bare runner serves the origin-level `/health` and a hosted origin does not (it answers `/v1/health` instead), so `/v1/version` is the one unauthenticated route both answer — probing anything else reports a perfectly reachable hosted origin as down. The target itself is resolved once, in the Makefile, and exported along with `PIPELEX_API_KEY`, so the URL the preflight checks is always the URL the suites call: the shell environment (or a `make test-e2e PIPELEX_E2E_BASE_URL=...` override) wins, then `.env`, then `http://localhost:8081`. The run echoes the resolved target before it starts, since `.env` can now supply it invisibly. Note that a hosted origin cannot run the whole suite today — `lint` and `format` are not exposed there (gateway `403`), while the protocol and build routes and the `resolve` and `codegen` crate routes answer, and `pipe-io` answers only once the platform's proxy and the gateway list it — so a fully green run means a local runner. The upload-grant suite needs the same hosted platform: it requests a grant, sends a small PDF with `uploadWithGrant`, reads the bytes back equal through `fetchArtifact`, and proves the refusals the error mapping reads — the `412` of a used grant, the `403 SignatureDoesNotMatch` of a file one byte longer than declared, and the `413` of a declared size over the cap. It runs in Node, whose `fetch` sends no CORS preflight, so the bucket's CORS rule is proven by a page, not by it. The artifact suite is the mirror image: it uploads a file with `prepareInputs`, runs a pass-through and brings the file back down with `downloadArtifacts` over `working_memory`, bytes equal, so it needs a hosted platform carrying `POST /v1/pipe-io` (which `prepareInputs` reads), the upload, run-lifecycle and bulk resolve routes, and a key for it, and it fails honestly rather than skipping against a bare runner.
137
+ - **E2E suites (`tests/e2e/*.e2e.ts`, `make test-e2e`):** no mocks — they drive a **live pipelex-api server** (`PIPELEX_E2E_BASE_URL`, default `http://localhost:8081`) and verify the diagnostic-endpoint contract end-to-end with correct and malformed MTHDS bundles: clean content lints with zero diagnostics and formats to itself (idempotently), malformed content comes back as a 200 verdict (`diagnostics[]` on lint; `diagnostics[]` plus the content echoed back unchanged with `changed: false` on format; `is_valid: false` + `validation_errors[]` on validate), and malformed formatter options surface as a 422 `ApiResponseError`. The crate suite adds the case only a live server can settle: the `kind` / `target` vocabulary is a mirror of a Python `StrEnum` in another repo, so nothing but a real call proves the two still agree — and it cross-checks that `codegen`'s `crate_fingerprint` equals the `fingerprint` `resolve` returns for the same closure. It then runs `runCodegenCheck` over the artifacts and lock the server just emitted — verbatim first (current, with the lock header's fingerprint matching the response's), then mutated in memory once per drift category, for a `.ts` target and a `.py` one. The unit suite pins the port against vendored bytes; only this pins it against the stamp and lock bytes the server writes **today**, which is the pairing that matters when a consumer commits the server's artifacts and gates CI on the SDK's verdict about them. The same suite drives `pipeIo` across all three selectors: the artifacts under the resolved ref, their equality with `validate`'s views for the same closure, the `include_files` echo, `all_pipes` on a method with no entry pipe, a `method_ref` package's manifest entry pipe, the invalid arm, and the typed selection `422`. Its `method_id` case, like the `prepareInputs` suite's, runs only when `PIPELEX_E2E_METHOD_ID` names a stored method the key's organization owns, since only a hosted origin can resolve one, and is skipped otherwise. The distinct `.e2e.ts` suffix + `vitest.e2e.config.ts` keep them out of the default `vitest run`, so `make test` / CI never require a server. An unreachable server is an error, never a silent skip, and it is reported once: `make test-e2e` preflights the target with a single `curl` and bails with a one-line message, instead of letting every suite fail in `beforeAll` and print a socket-error dump each. The per-suite `beforeAll` guard stays as the backstop for a direct `npm run test:e2e` run. Both probe **`/v1/version`**, deliberately: a bare runner serves the origin-level `/health` and a hosted origin does not (it answers `/v1/health` instead), so `/v1/version` is the one unauthenticated route both answer — probing anything else reports a perfectly reachable hosted origin as down. The target itself is resolved once, in the Makefile, and exported along with `PIPELEX_API_KEY`, so the URL the preflight checks is always the URL the suites call: the shell environment (or a `make test-e2e PIPELEX_E2E_BASE_URL=...` override) wins, then `.env`, then `http://localhost:8081`. The run echoes the resolved target before it starts, since `.env` can now supply it invisibly. Note that a hosted origin cannot run the whole suite today — `lint` and `format` are not exposed there (gateway `403`), while the protocol routes and the `resolve` and `codegen` crate routes answer, and `pipe-io` answers only once the platform's proxy and the gateway list it — so a fully green run means a local runner. The upload-grant suite needs the same hosted platform: it requests a grant, sends a small PDF with `uploadWithGrant`, reads the bytes back equal through `fetchArtifact`, and proves the refusals the error mapping reads — the `412` of a used grant, the `403 SignatureDoesNotMatch` of a file one byte longer than declared, and the `413` of a declared size over the cap. It runs in Node, whose `fetch` sends no CORS preflight, so the bucket's CORS rule is proven by a page, not by it. The artifact suite is the mirror image: it uploads a file with `prepareInputs`, runs a pass-through and brings the file back down with `downloadArtifacts` over `working_memory`, bytes equal, so it needs a hosted platform carrying `POST /v1/pipe-io` (which `prepareInputs` reads), the upload, run-lifecycle and bulk resolve routes, and a key for it, and it fails honestly rather than skipping against a bare runner.
@@ -1,6 +1,6 @@
1
1
  # Crate routes (`/v1/resolve`, `/v1/codegen`, `/v1/pipe-io`)
2
2
 
3
- Three routes project a **closure** of MTHDS files into the artifacts downstream tooling actually consumes: `resolve` emits the **normalized library crate**, `codegen` projects that crate into **stamped typed artifacts** plus their lock, and `pipeIo` derives a method's **pipe I/O contracts, input form and output form** without a dry run. Like the [build routes](./build-routes.md), they are Pipelex API extensions rather than MTHDS Protocol operations — but note the ownership split: the _crate_ and the three I/O artifacts are standard-owned (the MTHDS Library Crate Format, and the standard's pipe I/O contracts and form descriptors), while the HTTP surface serving them, and every type projection on top of the crate, are ours.
3
+ Three routes project a **closure** of MTHDS files into the artifacts downstream tooling actually consumes: `resolve` emits the **normalized library crate**, `codegen` projects that crate into **stamped typed artifacts** plus their lock, and `pipeIo` derives a method's **pipe I/O contracts, input form and output form** without a dry run. They are Pipelex API extensions rather than MTHDS Protocol operations — but note the ownership split: the _crate_ and the three I/O artifacts are standard-owned (the MTHDS Library Crate Format, and the standard's pipe I/O contracts and form descriptors), while the HTTP surface serving them, and every type projection on top of the crate, are ours.
4
4
 
5
5
  > **`resolve` and `codegen` are served on every hosted origin, and by any `pipelex-api` runner.** On the hosted plane a route is reachable only when the gateway's API-key allowlist and the platform's tooling proxy both list its path — each enumerates routes explicitly, and an unlisted path answers a gateway `403 {"message":"Forbidden"}`, refused before any service sees the request, so not even an RFC 7807 problem body. `resolve` and `codegen` are listed by both.
6
6
  >
@@ -25,7 +25,11 @@ interface PipelexHostedToolingExtensions {
25
25
  }
26
26
  ```
27
27
 
28
- This is the same `MthdsFileItem` and the same `source` semantics the build routes use, so the [notes there](./build-routes.md#the-shared-envelope) apply verbatim: pass a filename per file and, when the engine can attribute a diagnostic to one, it comes back as `source` on the corresponding `validation_errors[]` item.
28
+ `source` is why the envelope carries files rather than bare strings. 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.
29
+
30
+ Treat that attribution as best-effort, not a guarantee — which is why `ValidationErrorItem.source` is typed optional and why the `resolve` 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.
31
+
32
+ > `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.
29
33
 
30
34
  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 repository fetched at the tag, the package located by manifest identity, the package's real relative paths feeding the per-file `source` labels. Any non-address reference stays reserved and answers `501`.
31
35
 
@@ -33,7 +37,7 @@ An **address-form** `method_ref` (`github.com/<owner>/<repo>[/<selector>][@<tag>
33
37
 
34
38
  Supplying **no** selector or **more than one** is a request-shape `422` — the tooling routes are stateless, so there is no linkage exception; a second selector could only be ignored, which is the worst contract of the three. The SDK does not model the XOR in the type system — the union would force the overwhelmingly common `{ files }` call site to pick a branch for no gain, and the server's answer is a typed `ApiResponseError` either way.
35
39
 
36
- The old advice to expand a stored method client-side (`resolve({ files: await client.getMethodClosure(methodId) })`) remains valid — `getMethodClosure` stays public as the local expansion utility, and it is what a caller uses against a bare runner or on the routes with no by-id form (`/v1/build/*`).
40
+ The old advice to expand a stored method client-side (`resolve({ files: await client.getMethodClosure(methodId) })`) remains valid — `getMethodClosure` stays public as the local expansion utility, and it is what a caller uses against a bare runner, which has no catalog to resolve an id against.
37
41
 
38
42
  A `method_ref` makes the server fetch the repository before it answers, so the client gives a call carrying one a fetch-sized budget (three minutes) instead of the 30-second default. On the hosted API the gateway caps every request at about 30 seconds whatever the client allows, so a cold `method_ref` clone can answer a `502`; retrying clears it once the runner has cached the clone.
39
43
 
@@ -120,7 +124,7 @@ The valid arm (`PipeIOValidReport`):
120
124
 
121
125
  ## The response is a verdict, not a payload
122
126
 
123
- All three routes return a **discriminated 200**, the same discipline as `validate` and the build routes: 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` and the shared `CrateInvalidReport` — the very same invalid arm the build routes return, carrying the same structured `validation_errors[]`.
127
+ All three routes return a **discriminated 200**, the same discipline as `validate`: 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` and the shared `CrateInvalidReport`, carrying the same structured `validation_errors[]` as `validate`'s invalid arm.
124
128
 
125
129
  **Branch on `is_valid` before reading the arm.** A consumer that only catches throws will render a success over an unusable result, because nothing threw.
126
130
 
@@ -138,7 +142,7 @@ Only a **no-verdict** condition, as the typed `ApiResponseError` — branch on i
138
142
  | `502` | On a hosted origin, a cold `method_ref` clone that outran the gateway's 30-second cap; a retry clears it. |
139
143
  | `5xx` | Server fault, including on `pipeIo` a pipe whose artifacts cannot be derived. |
140
144
 
141
- Note the split, same as the build routes: a bad **closure** is a 200 verdict; a bad **request** throws.
145
+ Note the split: a bad **closure** is a 200 verdict; a bad **request** throws.
142
146
 
143
147
  (The offline check below is not a route and throws its own `CodegenLockError` instead — it never reaches the network.)
144
148
 
package/docs/errors.md CHANGED
@@ -114,7 +114,7 @@ The members `mthds`'s own `ApiResponseError` carries (`type`, `title`, `instance
114
114
 
115
115
  ## A validation item — `ValidationErrorItem`
116
116
 
117
- A method refused for what it says, rather than for how its run went, comes back as a list of validation items. They ride the `/v1/validate` verdict (its invalid arm's `validation_errors[]`, and the advisory `warnings[]` of its valid arm) and the build and crate routes' invalid verdict (`CrateInvalidReport.validation_errors[]`), each a `200` because an invalid bundle is a produced verdict; the `422` a run route answers when the runner refuses the method for its validation errors, as `ApiResponseError.validationErrors`; and a failed run's report, as `validation_errors`. Each item has a `category` and a `message`; the other members locate the error and say what to do next, and each is present only when the runner knows it:
117
+ A method refused for what it says, rather than for how its run went, comes back as a list of validation items. They ride the `/v1/validate` verdict (its invalid arm's `validation_errors[]`, and the advisory `warnings[]` of its valid arm) and the crate routes' invalid verdict (`CrateInvalidReport.validation_errors[]`), each a `200` because an invalid bundle is a produced verdict; the `422` a run route answers when the runner refuses the method for its validation errors, as `ApiResponseError.validationErrors`; and a failed run's report, as `validation_errors`. Each item has a `category` and a `message`; the other members locate the error and say what to do next, and each is present only when the runner knows it:
118
118
 
119
119
  | Member | Meaning |
120
120
  |---|---|
@@ -147,13 +147,13 @@ client.getMethodClosure(methodId) → MthdsFileItem[]
147
147
 
148
148
  `getMethodClosure` is the public **local expansion utility** — a client-side semantic layer over `getMethod` (the platform has no route that returns a parsed closure). It fetches the method, parses its polymorphic `mthds` source with [`methodSourceToContents`](#methodsourcetocontents--the-canonical-source-parser), and labels each resulting file with the `method_id` as its `source` provenance.
149
149
 
150
- Reach for it whenever you want the files **in hand** — to edit, to diff, or to feed a route with no by-id form:
150
+ Reach for it whenever you want the files **in hand** — to edit, to diff, or to send to a bare runner, which has no catalog to resolve an id against:
151
151
 
152
152
  ```
153
- client.buildInputs({ files: await client.getMethodClosure("mt_…"), pipe_ref?, format?, explicit? })
153
+ runner.resolve({ files: await hosted.getMethodClosure("mt_…") })
154
154
  ```
155
155
 
156
- `/v1/build/*` is the last such family, and it is being retired. Every other method-taking operation — `execute` / `start`, `validate` / `resolve` / `codegen` / `pipeIo`, and `prepareInputs` — takes a `method_id` **natively**, as a server pass-through: the platform resolves it and injects the stored source before the runner sees the request (see [architecture.md → hosted run extensions](./architecture.md#hosted-run-extensions-method_id)). That is the uniform rule — *an id option is always a server pass-through, and any client-side expansion is the caller's own explicit call*. An untyped caller still passing `method_id` to `buildInputs` gets a teaching error naming this migration (`PipelineRequestError`); for typed callers the field is a compile error.
156
+ Every method-taking operation — `execute` / `start`, `validate` / `resolve` / `codegen` / `pipeIo`, and `prepareInputs` — takes a `method_id` **natively** on the hosted API, as a server pass-through: the platform resolves it and injects the stored source before the runner sees the request (see [architecture.md → hosted run extensions](./architecture.md#hosted-run-extensions-method_id)). That is the uniform rule — *an id option is always a server pass-through, and any client-side expansion is the caller's own explicit call*.
157
157
 
158
158
  - **Requires an API key.** The methods catalog is org-scoped to the key's org, so resolution only works with an authenticated Pipelex-product key.
159
159
  - **Unknown or foreign-org id → the `getMethod` `404`** (`ApiResponseError`, `code: "not_found"`), propagated unchanged. An id from another org is indistinguishable from a nonexistent one — both 404.
@@ -172,7 +172,7 @@ A stored method's `mthds` field is **polymorphic**: it is either the raw single-
172
172
  Each input may be submitted in **either** of two shapes, and preparation treats them equivalently:
173
173
 
174
174
  - **Compact** — the bare value: a source string / bytes / canonical `{ url }` content (e.g. `photo: "https://…/p.png"`).
175
- - **Explicit envelope** — the `{ concept, content }` shape that `buildInputs({ explicit: true })` returns per input (e.g. `photo: { concept: "native.Image", content: { url: "https://…/p.png" } }`). This is the default template the hosted console and MCP hand agents to fill, so an agent that fills the template can hand it straight back.
175
+ - **Explicit envelope** — the `{ concept, content }` shape an explicit inputs template carries per input (`renderInputsTemplate(descriptor, { explicit: true, format })`, from `mthds/protocol` and re-exported here) (e.g. `photo: { concept: "native.Image", content: { url: "https://…/p.png" } }`). This is the default template the hosted console and MCP hand agents to fill, so an agent that fills the template can hand it straight back.
176
176
 
177
177
  When a value is an envelope (a plain object whose keys are **exactly** `concept` and `content` — matching the runtime's `_is_explicit` in `input_shaper.py`), preparation unwraps `content`, interprets it exactly as the compact value would be, and **re-wraps** the result — so the concept annotation rides through to the run. The runtime accepts the envelope as a run input (`input_shaper.py` `_is_explicit` / `_shape_explicit`), and file-reference resolution (`input_normalizer.py`) runs over the already-shaped content, so a re-wrapped `{ concept, content: { url: "pipelex-storage://…" } }` resolves identically to the compact `{ url }`. The envelope's `content` may itself be a scalar, a canonical file content, a list, or a structured object nesting file fields — the same top-down walk applies underneath.
178
178
 
@@ -198,7 +198,7 @@ Two consequences worth stating outright, because they are what the descriptor bu
198
198
 
199
199
  A repeated reference to the **same source** within one preparation is uploaded once and rewritten consistently (within-preparation dedup by source identity). A caller value whose shape disagrees with the node — a scalar at an `object`, a non-array at a `list` — passes through for the run to reject; preparation never second-guesses the signature.
200
200
 
201
- > **Why the descriptor, and why not the template.** Preparation used to read the *explicit inputs template* (`buildInputs` with `explicit: true`), whose file signal was a rendered `{"url": …}` dict. That signal is a side effect of a field being **named** `url` or `*_url`, not of the field being an Image or a Document — so a text field named `url` was read off the caller's disk and uploaded, and an **optional** nested file field, which the required-only template never rendered, was invisible and travelled to the runner as a literal path. Both were live misclassifications. The descriptor states the kind instead of implying it, and states it at every depth, so both edges fall out correctly rather than needing special cases. It costs the same one round trip, it is the standard's own artifact rather than a presentation of it, and it is what `@pipelex/mthds-form`, `pipelex-app`, `mthds-ui` and `pipelex-mcp` already derive from. The template remains what it always was — a fill-in scaffold for a person or an agent — and is projected from this same descriptor.
201
+ > **Why the descriptor, and why not the template.** Preparation used to read the *explicit inputs template*, served then by `POST /v1/build/inputs`, whose file signal was a rendered `{"url": …}` dict. That signal is a side effect of a field being **named** `url` or `*_url`, not of the field being an Image or a Document — so a text field named `url` was read off the caller's disk and uploaded, and an **optional** nested file field, which the required-only template never rendered, was invisible and travelled to the runner as a literal path. Both were live misclassifications. The descriptor states the kind instead of implying it, and states it at every depth, so both edges fall out correctly rather than needing special cases. It costs the same one round trip, it is the standard's own artifact rather than a presentation of it, and it is what `@pipelex/mthds-form`, `pipelex-app`, `mthds-ui` and `pipelex-mcp` already derive from. The template remains what it always was — a fill-in scaffold for a person or an agent — and is projected from this same descriptor, client-side, by `renderInputsTemplate`.
202
202
 
203
203
  ### Pass-through rules
204
204
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipelex/sdk",
3
- "version": "0.29.1",
3
+ "version": "0.30.0",
4
4
  "description": "TypeScript SDK for the Pipelex hosted API — execute methods, manage runs, and call the product surface.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -70,7 +70,7 @@
70
70
  "vitest": "^4.0.18"
71
71
  },
72
72
  "dependencies": {
73
- "mthds": "^0.28.0",
73
+ "mthds": "^0.30.0",
74
74
  "smol-toml": "^1.6.0",
75
75
  "undici": "^7.29.1"
76
76
  }