@pipelex/sdk 0.3.1 → 0.5.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/client.d.ts +120 -9
- package/dist/client.js +170 -16
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +62 -0
- package/dist/errors.js +72 -0
- package/dist/errors.js.map +1 -1
- package/dist/hooks/bundle-gather.d.ts +31 -0
- package/dist/hooks/bundle-gather.js +92 -0
- package/dist/hooks/bundle-gather.js.map +1 -0
- package/dist/hooks/check-core.d.ts +111 -0
- package/dist/hooks/check-core.js +224 -0
- package/dist/hooks/check-core.js.map +1 -0
- package/dist/hooks/claude-mthds-check.d.ts +29 -0
- package/dist/hooks/claude-mthds-check.js +220 -0
- package/dist/hooks/claude-mthds-check.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +178 -13
- package/dist/prepare-inputs.d.ts +54 -0
- package/dist/prepare-inputs.js +178 -0
- package/dist/prepare-inputs.js.map +1 -0
- package/dist/runs.d.ts +72 -1
- package/dist/runs.js.map +1 -1
- package/dist/upload.d.ts +66 -0
- package/dist/upload.js +153 -0
- package/dist/upload.js.map +1 -0
- package/package.json +6 -2
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `prepareInputs` — signature-driven input preparation. Resolves the target
|
|
3
|
+
* pipe's declared inputs via the explicit inputs template, interprets the
|
|
4
|
+
* caller's compact inputs top-down against it, uploads the file-bearing values,
|
|
5
|
+
* and returns rewritten inputs (canonical content carrying `pipelex-storage://`
|
|
6
|
+
* in `url`) plus one upload record per prepared asset.
|
|
7
|
+
*
|
|
8
|
+
* The classification mirrors the runtime: `pipelex`'s `input_normalizer` walks
|
|
9
|
+
* Image/Document contents (recognized by their `url`-bearing shape, incl. nested
|
|
10
|
+
* in structured content) and `resolve_uri` decides upload vs pass-through. The
|
|
11
|
+
* declared signature comes from the explicit template (`buildInputs`,
|
|
12
|
+
* `explicit: true`), whose canonical content shape is the classifier — the file
|
|
13
|
+
* signal is a value that is a dict containing a `url` key. See the shared
|
|
14
|
+
* behavior matrix (`wip/upload/behavior-matrix.md`) and `docs/input-preparation.md`.
|
|
15
|
+
*/
|
|
16
|
+
import { InputPreparationError } from "./errors.js";
|
|
17
|
+
import { uploadFile } from "./upload.js";
|
|
18
|
+
const PIPELEX_STORAGE_SCHEME = "pipelex-storage://";
|
|
19
|
+
const HTTP_URL_RE = /^https?:\/\//i;
|
|
20
|
+
/** Strict plain-object test — excludes arrays, `Uint8Array`, `Blob`, and other exotics. */
|
|
21
|
+
function isPlainObject(value) {
|
|
22
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
23
|
+
}
|
|
24
|
+
/** A canonical Image/Document content is a plain object carrying a `url` key. */
|
|
25
|
+
function isFileContent(node) {
|
|
26
|
+
return isPlainObject(node) && "url" in node;
|
|
27
|
+
}
|
|
28
|
+
/** Decode a `data:` URL into bytes plus its MIME type. */
|
|
29
|
+
function decodeDataUrl(dataUrl) {
|
|
30
|
+
const comma = dataUrl.indexOf(",");
|
|
31
|
+
if (comma < 0) {
|
|
32
|
+
throw new InputPreparationError(`Malformed data URL (no comma separator): ${dataUrl.slice(0, 32)}…`);
|
|
33
|
+
}
|
|
34
|
+
const header = dataUrl.slice(5, comma); // strip "data:"
|
|
35
|
+
const payload = dataUrl.slice(comma + 1);
|
|
36
|
+
const isBase64 = /;base64/i.test(header);
|
|
37
|
+
const contentType = header.split(";")[0] || "application/octet-stream";
|
|
38
|
+
// Decoding can throw on a malformed payload — a URIError from percent-decoding,
|
|
39
|
+
// or an InvalidCharacterError from `atob` on bad base64. Surface those as a typed
|
|
40
|
+
// InputPreparationError so a bad data URL stays within the preparation contract.
|
|
41
|
+
try {
|
|
42
|
+
if (isBase64) {
|
|
43
|
+
// Decode via atob in every runtime. atob rejects malformed base64 with an
|
|
44
|
+
// InvalidCharacterError — Buffer.from(payload, "base64") does NOT: in Node it
|
|
45
|
+
// silently drops invalid characters and returns truncated/empty bytes, which would
|
|
46
|
+
// upload corrupt content instead of failing the preparation contract. atob is a
|
|
47
|
+
// global in every supported runtime (engines.node >= 22.12).
|
|
48
|
+
return { bytes: base64ToBytes(payload), contentType };
|
|
49
|
+
}
|
|
50
|
+
const text = decodeURIComponent(payload);
|
|
51
|
+
return { bytes: new TextEncoder().encode(text), contentType };
|
|
52
|
+
}
|
|
53
|
+
catch (cause) {
|
|
54
|
+
throw new InputPreparationError(`Malformed data URL payload (${isBase64 ? "invalid base64" : "invalid percent-encoding"}): ${dataUrl.slice(0, 32)}…`, { cause });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Strict cross-runtime base64 decode via `atob` — the single decoder for data-URL
|
|
59
|
+
* payloads in every runtime. `atob` throws an `InvalidCharacterError` on malformed
|
|
60
|
+
* base64, unlike the lenient `Buffer.from(payload, "base64")`, so a bad payload
|
|
61
|
+
* fails the preparation contract instead of yielding truncated/empty bytes.
|
|
62
|
+
*/
|
|
63
|
+
function base64ToBytes(base64) {
|
|
64
|
+
const binary = atob(base64);
|
|
65
|
+
const bytes = new Uint8Array(binary.length);
|
|
66
|
+
for (let index = 0; index < binary.length; index += 1)
|
|
67
|
+
bytes[index] = binary.charCodeAt(index);
|
|
68
|
+
return bytes;
|
|
69
|
+
}
|
|
70
|
+
/** Resolve one source (string reference or bytes) to the URL/URI to write, deduped by identity. */
|
|
71
|
+
function resolveSource(ctx, source) {
|
|
72
|
+
const cached = ctx.dedup.get(source);
|
|
73
|
+
if (cached !== undefined)
|
|
74
|
+
return cached;
|
|
75
|
+
const pending = doResolveSource(ctx, source);
|
|
76
|
+
ctx.dedup.set(source, pending);
|
|
77
|
+
return pending;
|
|
78
|
+
}
|
|
79
|
+
async function doResolveSource(ctx, source) {
|
|
80
|
+
if (typeof source === "string") {
|
|
81
|
+
if (source.startsWith(PIPELEX_STORAGE_SCHEME))
|
|
82
|
+
return source; // already prepared
|
|
83
|
+
if (HTTP_URL_RE.test(source))
|
|
84
|
+
return source; // reachable URL — pass through
|
|
85
|
+
if (source.startsWith("data:")) {
|
|
86
|
+
const { bytes, contentType } = decodeDataUrl(source);
|
|
87
|
+
const record = await uploadFile(ctx.client, bytes, { contentType });
|
|
88
|
+
ctx.uploads.push(record);
|
|
89
|
+
return record.uri;
|
|
90
|
+
}
|
|
91
|
+
// Anything else is a local filesystem path — Node only (uploadFile enforces it).
|
|
92
|
+
const record = await uploadFile(ctx.client, source);
|
|
93
|
+
ctx.uploads.push(record);
|
|
94
|
+
return record.uri;
|
|
95
|
+
}
|
|
96
|
+
if (source instanceof Blob || source instanceof ArrayBuffer || source instanceof Uint8Array) {
|
|
97
|
+
const record = await uploadFile(ctx.client, source);
|
|
98
|
+
ctx.uploads.push(record);
|
|
99
|
+
return record.uri;
|
|
100
|
+
}
|
|
101
|
+
// An unrecognized value sits at a file-bearing position (neither a source string,
|
|
102
|
+
// bytes, nor a canonical `{url}` content dict). Fail with a typed error rather than
|
|
103
|
+
// letting a raw TypeError escape from the byte-extraction path.
|
|
104
|
+
throw new InputPreparationError(`Unsupported value at a file input: expected a path string, bytes (Blob/File/ArrayBuffer/Uint8Array), ` +
|
|
105
|
+
`a data URL, an http(s)/pipelex-storage:// URL, or canonical {url} content; got ${typeof source}.`);
|
|
106
|
+
}
|
|
107
|
+
/** Resolve a value known to sit at a file position into canonical content with a rewritten `url`. */
|
|
108
|
+
async function resolveFilePosition(ctx, callerValue) {
|
|
109
|
+
if (isFileContent(callerValue)) {
|
|
110
|
+
const resolved = await resolveSource(ctx, callerValue.url);
|
|
111
|
+
return { ...callerValue, url: resolved };
|
|
112
|
+
}
|
|
113
|
+
const resolved = await resolveSource(ctx, callerValue);
|
|
114
|
+
return { url: resolved };
|
|
115
|
+
}
|
|
116
|
+
/** Template-guided walk: a template node that is canonical file content marks a file position. */
|
|
117
|
+
async function resolveNode(ctx, templateNode, callerValue) {
|
|
118
|
+
if (isFileContent(templateNode)) {
|
|
119
|
+
return resolveFilePosition(ctx, callerValue);
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(templateNode) && templateNode.length > 0) {
|
|
122
|
+
const elementTemplate = templateNode[0];
|
|
123
|
+
if (Array.isArray(callerValue)) {
|
|
124
|
+
return Promise.all(callerValue.map((item) => resolveNode(ctx, elementTemplate, item)));
|
|
125
|
+
}
|
|
126
|
+
return callerValue; // shape mismatch — leave it for the run to reject
|
|
127
|
+
}
|
|
128
|
+
if (isPlainObject(templateNode) && isPlainObject(callerValue)) {
|
|
129
|
+
const result = { ...callerValue };
|
|
130
|
+
for (const key of Object.keys(templateNode)) {
|
|
131
|
+
if (key in callerValue) {
|
|
132
|
+
result[key] = await resolveNode(ctx, templateNode[key], callerValue[key]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
return callerValue; // scalar (text/number/…) or shape mismatch — pass through
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Prepare a pipe's inputs: upload local/byte/data-URL assets at the signature's
|
|
141
|
+
* file-bearing positions and return copy-on-write rewritten inputs plus upload
|
|
142
|
+
* records. HTTP(S) URLs and existing `pipelex-storage://` URIs pass through
|
|
143
|
+
* unchanged. All failures are raised before any run is created.
|
|
144
|
+
*
|
|
145
|
+
* The declared signature is resolved from the closure; a closure that does not
|
|
146
|
+
* resolve throws {@link InputPreparationError}. No-verdict conditions from the
|
|
147
|
+
* signature route (unknown `pipe_ref`, auth, server fault) surface as the build
|
|
148
|
+
* route's `ApiResponseError`.
|
|
149
|
+
*/
|
|
150
|
+
export async function prepareInputs(client, request) {
|
|
151
|
+
const report = await client.buildInputs({
|
|
152
|
+
files: request.files,
|
|
153
|
+
...(request.pipe_ref === undefined ? {} : { pipe_ref: request.pipe_ref }),
|
|
154
|
+
format: "json",
|
|
155
|
+
explicit: true,
|
|
156
|
+
});
|
|
157
|
+
if (!report.is_valid) {
|
|
158
|
+
const first = report.validation_errors[0]?.message ?? report.message;
|
|
159
|
+
throw new InputPreparationError(`Cannot prepare inputs: the method signature did not resolve — ${first}`);
|
|
160
|
+
}
|
|
161
|
+
// We requested `format: "json"`, so the valid arm carries the envelope in `inputs`.
|
|
162
|
+
if (report.format !== "json") {
|
|
163
|
+
throw new InputPreparationError(`Cannot prepare inputs: expected a JSON inputs template, got "${report.format}".`);
|
|
164
|
+
}
|
|
165
|
+
const template = report.inputs;
|
|
166
|
+
const ctx = { client, uploads: [], dedup: new Map() };
|
|
167
|
+
const rewritten = { ...request.inputs };
|
|
168
|
+
for (const [name, callerValue] of Object.entries(request.inputs)) {
|
|
169
|
+
const entry = template[name];
|
|
170
|
+
if (!isPlainObject(entry) || !("content" in entry)) {
|
|
171
|
+
// Not a declared input (or an unexpected envelope) — pass through untouched.
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
rewritten[name] = await resolveNode(ctx, entry.content, callerValue);
|
|
175
|
+
}
|
|
176
|
+
return { inputs: rewritten, uploads: ctx.uploads };
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=prepare-inputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare-inputs.js","sourceRoot":"","sources":["../src/prepare-inputs.ts"],"names":[],"mappings":"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"}
|
package/dist/runs.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DictPipeOutput } from "./models.js";
|
|
1
2
|
/**
|
|
2
3
|
* Run-lifecycle types + polling for the hosted polling surface (`/v1/runs/*`).
|
|
3
4
|
*
|
|
@@ -55,6 +56,61 @@ export interface RunRead extends RunPublic {
|
|
|
55
56
|
degraded: boolean;
|
|
56
57
|
retry_after_seconds?: number | null;
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* One inference call's token usage — the client-facing wire record.
|
|
61
|
+
*
|
|
62
|
+
* Mirrors the runtime's `TokensUsageRecord`, specified in
|
|
63
|
+
* `docs/specs/pipelex-mthds-protocol.md#tokensusage-records-on-run-artifacts`. The same
|
|
64
|
+
* shape rides both surfaces: the durable `tokens_usages.json` artifact that the hosted
|
|
65
|
+
* results route relays, and the blocking execute response's `pipe_output.tokens_usages`.
|
|
66
|
+
*
|
|
67
|
+
* Every field is optional and the index signature is open **on purpose**. A record the
|
|
68
|
+
* current runtime emits always carries the full key set (a field with no value is an
|
|
69
|
+
* explicit `null`, never an omitted key), so callers may read any field directly. But
|
|
70
|
+
* durable artifacts written before the contract shipped are relayed verbatim and never
|
|
71
|
+
* migrated: such a record arrives with no `cost` and no `pipe_code`, and keeps its legacy
|
|
72
|
+
* `job_metadata` / `unit_costs` — reachable through the index signature, never contract
|
|
73
|
+
* fields.
|
|
74
|
+
*
|
|
75
|
+
* The enum-ish fields are open sets on the wire and stay `string` here — never frozen
|
|
76
|
+
* unions — so runtime enum churn is non-breaking for consumers.
|
|
77
|
+
*/
|
|
78
|
+
export interface TokensUsageRecord {
|
|
79
|
+
/** Kind of inference. Known values: `llm`, `img_gen`, `extract`, `search`. */
|
|
80
|
+
model_type?: string | null;
|
|
81
|
+
/** Human model name (e.g. `gpt-4o`). */
|
|
82
|
+
inference_model_name?: string | null;
|
|
83
|
+
/** Provider/platform model id (e.g. `gpt-4o-2024-11-20`). */
|
|
84
|
+
inference_model_id?: string | null;
|
|
85
|
+
/** The pipe that made the call — what makes per-pipe cost attribution possible. */
|
|
86
|
+
pipe_code?: string | null;
|
|
87
|
+
/** Known values: `llm_job`, `img_gen_job`, `extract_job`, `search_job`, `jinja2_job`, `mock_job`. */
|
|
88
|
+
job_category?: string | null;
|
|
89
|
+
/**
|
|
90
|
+
* Known values: `llm_gen_text`, `llm_gen_object`, `img_gen_text_to_image`,
|
|
91
|
+
* `extract_pages`, `search_sourced_answer`, `search_structured`.
|
|
92
|
+
*/
|
|
93
|
+
unit_job_id?: string | null;
|
|
94
|
+
/**
|
|
95
|
+
* Raw provider-reported token counts, keyed by token category (`input`, `input_cached`,
|
|
96
|
+
* `output`, `output_reasoning`, …). `input` is the joined total and `input_cached` a
|
|
97
|
+
* subset of it — the categories are NOT additive, so summing them double-counts.
|
|
98
|
+
*/
|
|
99
|
+
nb_tokens_by_category?: Record<string, number> | null;
|
|
100
|
+
/**
|
|
101
|
+
* Computed USD cost of this call. Null when the model has no rate table at all (own-GPU,
|
|
102
|
+
* mock, dry run); `0` means a rate table existed and priced the call at zero. The
|
|
103
|
+
* underlying rate table never crosses the wire and there is no run-level aggregate — sum
|
|
104
|
+
* the records.
|
|
105
|
+
*/
|
|
106
|
+
cost?: number | null;
|
|
107
|
+
/** ISO 8601 start of the call. */
|
|
108
|
+
started_at?: string | null;
|
|
109
|
+
/** ISO 8601 end of the call. Duration is derivable from the pair and deliberately not shipped. */
|
|
110
|
+
completed_at?: string | null;
|
|
111
|
+
/** Legacy fields on a pre-contract artifact relayed verbatim (`job_metadata`, `unit_costs`). */
|
|
112
|
+
[extension: string]: unknown;
|
|
113
|
+
}
|
|
58
114
|
/**
|
|
59
115
|
* Result artifacts for a completed run — `GET /v1/runs/{pipeline_run_id}/results`.
|
|
60
116
|
*
|
|
@@ -81,7 +137,22 @@ export interface RunResults {
|
|
|
81
137
|
* blocking-execute path only; null on the hosted path. Supplementary to `main_stuff`,
|
|
82
138
|
* which is already resolved out of it; kept for consumers that need the whole working memory.
|
|
83
139
|
*/
|
|
84
|
-
pipe_output?:
|
|
140
|
+
pipe_output?: DictPipeOutput | null;
|
|
141
|
+
/**
|
|
142
|
+
* Per-call usage records — token counts by category, computed `cost` in USD, model id —
|
|
143
|
+
* for LLM and img-gen/extract/search calls alike. On the hosted path this is the
|
|
144
|
+
* `tokens_usages.json` artifact's record list relayed verbatim; on the blocking path it is
|
|
145
|
+
* the execute response's `pipe_output.tokens_usages`. Null whenever assembly produced no
|
|
146
|
+
* list — it was off, it broke (see `usage_assembly_error`), or (hosted) the run was
|
|
147
|
+
* delivered before the artifact existed; `[]` when assembly ran and no inference happened.
|
|
148
|
+
*/
|
|
149
|
+
tokens_usages?: TokensUsageRecord[] | null;
|
|
150
|
+
/**
|
|
151
|
+
* Non-null when the runner's usage assembly failed for the run. The ONLY field that
|
|
152
|
+
* separates "usage broke" from "usage was off" / "pre-artifact run" — all three leave
|
|
153
|
+
* `tokens_usages` null, so a caller that cares must branch on this, not on the list.
|
|
154
|
+
*/
|
|
155
|
+
usage_assembly_error?: string | null;
|
|
85
156
|
}
|
|
86
157
|
/**
|
|
87
158
|
* Single-shot result lookup outcome, discriminated on `state`:
|
package/dist/runs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../src/runs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../src/runs.ts"],"names":[],"mappings":"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"}
|
package/dist/upload.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uploadFile` — the single-asset upload convenience over the raw `upload()` wire
|
|
3
|
+
* call. Accepts web byte types in every runtime (`Blob`/`File`/`ArrayBuffer`/
|
|
4
|
+
* `Uint8Array`) and, in Node only, a filesystem path string; returns an
|
|
5
|
+
* {@link UploadRecord} assembled client-side. See `docs/input-preparation.md`.
|
|
6
|
+
*
|
|
7
|
+
* The MIME type and size are known client-side at upload time, so the record is
|
|
8
|
+
* built without extending the `/v1/upload` response.
|
|
9
|
+
*/
|
|
10
|
+
/** A local asset `uploadFile` accepts. A path string is Node-only (see {@link readLocalPath}). */
|
|
11
|
+
export type UploadableAsset = Blob | ArrayBuffer | Uint8Array | string;
|
|
12
|
+
/**
|
|
13
|
+
* The record `uploadFile` returns for a prepared asset. Beyond the source identity
|
|
14
|
+
* it guarantees the resulting `uri`, the MIME `contentType`, the `size` in bytes,
|
|
15
|
+
* and the `filename`. A content checksum is deliberately not included — it is
|
|
16
|
+
* best-effort at most, and within-preparation dedup keys on source identity.
|
|
17
|
+
*/
|
|
18
|
+
export interface UploadRecord {
|
|
19
|
+
/** The `pipelex-storage://` reference for the uploaded asset. */
|
|
20
|
+
uri: string;
|
|
21
|
+
filename: string;
|
|
22
|
+
/** MIME type, known client-side. Best-effort for raw bytes (falls back to `application/octet-stream`). */
|
|
23
|
+
contentType: string;
|
|
24
|
+
/** Size of the uploaded bytes. */
|
|
25
|
+
size: number;
|
|
26
|
+
}
|
|
27
|
+
/** Per-call options for {@link uploadFile}. Fill in a filename/MIME for nameless byte sources. */
|
|
28
|
+
export interface UploadFileOptions {
|
|
29
|
+
filename?: string;
|
|
30
|
+
contentType?: string;
|
|
31
|
+
}
|
|
32
|
+
/** The subset of the client `uploadFile` needs — the raw base64 `upload` wire call. */
|
|
33
|
+
export interface UploadCapableClient {
|
|
34
|
+
upload(input: {
|
|
35
|
+
filename: string;
|
|
36
|
+
data: string;
|
|
37
|
+
content_type: string;
|
|
38
|
+
}): Promise<{
|
|
39
|
+
uri: string;
|
|
40
|
+
filename: string;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
/** True when running under Node (has `process.versions.node`). */
|
|
44
|
+
export declare function isNodeRuntime(): boolean;
|
|
45
|
+
/** MIME guess from a filename extension; `application/octet-stream` when unknown. */
|
|
46
|
+
export declare function guessContentType(filename: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Read a filesystem path into bytes — Node only. A path string in a non-Node
|
|
49
|
+
* runtime cannot be read, so it fails as an invalid local source rather than
|
|
50
|
+
* being silently misread as text or a URL. `node:fs/promises` is imported
|
|
51
|
+
* dynamically and guarded by `isNodeRuntime()`, so it is only *loaded* in Node.
|
|
52
|
+
* Note: the dynamic import defers execution, not bundling — a browser-targeting
|
|
53
|
+
* bundler still statically resolves this literal specifier, so browser consumers
|
|
54
|
+
* must currently mark `node:*` external. Making the byte-only path bundle for the
|
|
55
|
+
* browser out of the box is an open packaging decision (see wip/pr-16-review-notes.md).
|
|
56
|
+
*/
|
|
57
|
+
export declare function readLocalPath(path: string): Promise<Uint8Array>;
|
|
58
|
+
/** Base64-encode bytes, cross-runtime (Buffer when present, else chunked btoa). */
|
|
59
|
+
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
60
|
+
/**
|
|
61
|
+
* Upload one local asset and return its {@link UploadRecord}. Maps the raw
|
|
62
|
+
* `upload()` transport errors onto the semantic input-preparation errors: a
|
|
63
|
+
* `413` is a rejected asset, `401`/`403` an auth failure, `404` an unsupported
|
|
64
|
+
* upload capability, an unreachable host a transport failure.
|
|
65
|
+
*/
|
|
66
|
+
export declare function uploadFile(client: UploadCapableClient, asset: UploadableAsset, options?: UploadFileOptions): Promise<UploadRecord>;
|
package/dist/upload.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uploadFile` — the single-asset upload convenience over the raw `upload()` wire
|
|
3
|
+
* call. Accepts web byte types in every runtime (`Blob`/`File`/`ArrayBuffer`/
|
|
4
|
+
* `Uint8Array`) and, in Node only, a filesystem path string; returns an
|
|
5
|
+
* {@link UploadRecord} assembled client-side. See `docs/input-preparation.md`.
|
|
6
|
+
*
|
|
7
|
+
* The MIME type and size are known client-side at upload time, so the record is
|
|
8
|
+
* built without extending the `/v1/upload` response.
|
|
9
|
+
*/
|
|
10
|
+
import { InvalidLocalSourceError, RejectedAssetError, UploadAuthenticationError, UploadTransportError, UnsupportedUploadCapabilityError, } from "./errors.js";
|
|
11
|
+
import { ApiResponseError, ApiUnreachableError } from "./errors.js";
|
|
12
|
+
const DEFAULT_CONTENT_TYPE = "application/octet-stream";
|
|
13
|
+
const DEFAULT_FILENAME = "upload.bin";
|
|
14
|
+
const EXTENSION_MIME = {
|
|
15
|
+
png: "image/png",
|
|
16
|
+
jpg: "image/jpeg",
|
|
17
|
+
jpeg: "image/jpeg",
|
|
18
|
+
gif: "image/gif",
|
|
19
|
+
webp: "image/webp",
|
|
20
|
+
svg: "image/svg+xml",
|
|
21
|
+
bmp: "image/bmp",
|
|
22
|
+
tif: "image/tiff",
|
|
23
|
+
tiff: "image/tiff",
|
|
24
|
+
heic: "image/heic",
|
|
25
|
+
pdf: "application/pdf",
|
|
26
|
+
txt: "text/plain",
|
|
27
|
+
csv: "text/csv",
|
|
28
|
+
json: "application/json",
|
|
29
|
+
};
|
|
30
|
+
/** True when running under Node (has `process.versions.node`). */
|
|
31
|
+
export function isNodeRuntime() {
|
|
32
|
+
return (typeof process !== "undefined" && process.versions != null && process.versions.node != null);
|
|
33
|
+
}
|
|
34
|
+
/** Filename tail of a path, splitting on both separators (no `node:path` import needed). */
|
|
35
|
+
function basename(path) {
|
|
36
|
+
const parts = path.split(/[\\/]/);
|
|
37
|
+
return parts[parts.length - 1] || path;
|
|
38
|
+
}
|
|
39
|
+
/** MIME guess from a filename extension; `application/octet-stream` when unknown. */
|
|
40
|
+
export function guessContentType(filename) {
|
|
41
|
+
const dot = filename.lastIndexOf(".");
|
|
42
|
+
if (dot < 0 || dot === filename.length - 1)
|
|
43
|
+
return DEFAULT_CONTENT_TYPE;
|
|
44
|
+
const ext = filename.slice(dot + 1).toLowerCase();
|
|
45
|
+
return EXTENSION_MIME[ext] ?? DEFAULT_CONTENT_TYPE;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Read a filesystem path into bytes — Node only. A path string in a non-Node
|
|
49
|
+
* runtime cannot be read, so it fails as an invalid local source rather than
|
|
50
|
+
* being silently misread as text or a URL. `node:fs/promises` is imported
|
|
51
|
+
* dynamically and guarded by `isNodeRuntime()`, so it is only *loaded* in Node.
|
|
52
|
+
* Note: the dynamic import defers execution, not bundling — a browser-targeting
|
|
53
|
+
* bundler still statically resolves this literal specifier, so browser consumers
|
|
54
|
+
* must currently mark `node:*` external. Making the byte-only path bundle for the
|
|
55
|
+
* browser out of the box is an open packaging decision (see wip/pr-16-review-notes.md).
|
|
56
|
+
*/
|
|
57
|
+
export async function readLocalPath(path) {
|
|
58
|
+
if (!isNodeRuntime()) {
|
|
59
|
+
throw new InvalidLocalSourceError(`Cannot read the local path "${path}" outside Node — path strings are Node-only. ` +
|
|
60
|
+
"In the browser or an edge runtime, pass the file as bytes (Blob/File/ArrayBuffer/Uint8Array).", path);
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const { readFile } = await import("node:fs/promises");
|
|
64
|
+
return await readFile(path);
|
|
65
|
+
}
|
|
66
|
+
catch (cause) {
|
|
67
|
+
throw new InvalidLocalSourceError(`Local file cannot be read: "${path}" (${cause.code ?? "read error"}).`, path, { cause });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Base64-encode bytes, cross-runtime (Buffer when present, else chunked btoa). */
|
|
71
|
+
export function bytesToBase64(bytes) {
|
|
72
|
+
if (typeof Buffer !== "undefined") {
|
|
73
|
+
return Buffer.from(bytes).toString("base64");
|
|
74
|
+
}
|
|
75
|
+
let binary = "";
|
|
76
|
+
const chunk = 0x8000; // stay under the String.fromCharCode argument cap
|
|
77
|
+
for (let index = 0; index < bytes.length; index += chunk) {
|
|
78
|
+
binary += String.fromCharCode(...bytes.subarray(index, index + chunk));
|
|
79
|
+
}
|
|
80
|
+
return btoa(binary);
|
|
81
|
+
}
|
|
82
|
+
/** Normalize any accepted asset form into bytes plus a filename and MIME. */
|
|
83
|
+
async function toAssetBytes(asset, options) {
|
|
84
|
+
if (typeof asset === "string") {
|
|
85
|
+
const bytes = await readLocalPath(asset);
|
|
86
|
+
const filename = options.filename ?? basename(asset);
|
|
87
|
+
return { bytes, filename, contentType: options.contentType ?? guessContentType(filename) };
|
|
88
|
+
}
|
|
89
|
+
if (asset instanceof Uint8Array) {
|
|
90
|
+
return assetBytesFromBuffer(asset, options);
|
|
91
|
+
}
|
|
92
|
+
if (asset instanceof ArrayBuffer) {
|
|
93
|
+
return assetBytesFromBuffer(new Uint8Array(asset), options);
|
|
94
|
+
}
|
|
95
|
+
// Blob / File — File carries `.name`; both carry `.type`.
|
|
96
|
+
const bytes = new Uint8Array(await asset.arrayBuffer());
|
|
97
|
+
const name = options.filename ?? asset.name;
|
|
98
|
+
const filename = name && name.length > 0 ? name : DEFAULT_FILENAME;
|
|
99
|
+
const contentType = options.contentType ?? (asset.type || guessContentType(filename));
|
|
100
|
+
return { bytes, filename, contentType };
|
|
101
|
+
}
|
|
102
|
+
function assetBytesFromBuffer(bytes, options) {
|
|
103
|
+
const filename = options.filename ?? DEFAULT_FILENAME;
|
|
104
|
+
return { bytes, filename, contentType: options.contentType ?? guessContentType(filename) };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Upload one local asset and return its {@link UploadRecord}. Maps the raw
|
|
108
|
+
* `upload()` transport errors onto the semantic input-preparation errors: a
|
|
109
|
+
* `413` is a rejected asset, `401`/`403` an auth failure, `404` an unsupported
|
|
110
|
+
* upload capability, an unreachable host a transport failure.
|
|
111
|
+
*/
|
|
112
|
+
export async function uploadFile(client, asset, options = {}) {
|
|
113
|
+
const { bytes, filename, contentType } = await toAssetBytes(asset, options);
|
|
114
|
+
const data = bytesToBase64(bytes);
|
|
115
|
+
let uploaded;
|
|
116
|
+
try {
|
|
117
|
+
uploaded = await client.upload({ filename, data, content_type: contentType });
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
throw mapUploadError(error, filename);
|
|
121
|
+
}
|
|
122
|
+
return { uri: uploaded.uri, filename: uploaded.filename, contentType, size: bytes.length };
|
|
123
|
+
}
|
|
124
|
+
/** Translate a raw `upload()` transport error into the matching preparation error. */
|
|
125
|
+
function mapUploadError(error, filename) {
|
|
126
|
+
if (error instanceof ApiResponseError) {
|
|
127
|
+
switch (error.status) {
|
|
128
|
+
case 413:
|
|
129
|
+
return new RejectedAssetError(`The server rejected "${filename}": ${error.serverMessage ?? "asset exceeds the service size limit"}.`, filename, error.status, { cause: error });
|
|
130
|
+
case 401:
|
|
131
|
+
case 403:
|
|
132
|
+
return new UploadAuthenticationError(`Upload of "${filename}" was not authorized (${error.status}). Check the configured Pipelex API key.`, error.status, { cause: error });
|
|
133
|
+
case 404:
|
|
134
|
+
return new UnsupportedUploadCapabilityError("The configured Pipelex deployment does not support file upload (no /v1/upload route). " +
|
|
135
|
+
"Upload is a hosted Pipelex capability.", { cause: error });
|
|
136
|
+
default:
|
|
137
|
+
return new UploadTransportError(`Upload of "${filename}" failed (${error.status}): ${error.serverMessage ?? error.statusText}.`, { cause: error });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (error instanceof ApiUnreachableError) {
|
|
141
|
+
return new UploadTransportError(`Upload of "${filename}" could not reach the Pipelex API (${error.code ?? "unreachable"}).`, { cause: error });
|
|
142
|
+
}
|
|
143
|
+
// Only errors thrown by the `client.upload()` call reach here — the local-source
|
|
144
|
+
// and asset-type failures are raised in `toAssetBytes`, before this try block. Any
|
|
145
|
+
// error that is neither of the two mapped types (a malformed 2xx body surfacing as a
|
|
146
|
+
// SyntaxError, a custom client throwing a plain Error) is wrapped so every upload
|
|
147
|
+
// failure stays catchable as an InputPreparationError, never a raw escape.
|
|
148
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
149
|
+
return new UploadTransportError(`Upload of "${filename}" failed unexpectedly: ${detail}.`, {
|
|
150
|
+
cause: error,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipelex/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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": {
|
|
@@ -19,8 +19,10 @@
|
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsc",
|
|
22
|
+
"build:hook": "node scripts/build-hook.mjs",
|
|
22
23
|
"test": "vitest run",
|
|
23
24
|
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
24
26
|
"typecheck": "tsc --noEmit",
|
|
25
27
|
"typecheck:test": "tsc -p tsconfig.test.json --noEmit",
|
|
26
28
|
"lint": "eslint src/ tests/",
|
|
@@ -41,9 +43,11 @@
|
|
|
41
43
|
},
|
|
42
44
|
"devDependencies": {
|
|
43
45
|
"@eslint/js": "^9.39.4",
|
|
46
|
+
"@pipelex/tools-wasm": "^0.1.0",
|
|
44
47
|
"@types/node": "^22.12.0",
|
|
45
48
|
"@vitest/coverage-v8": "^4.1.9",
|
|
46
49
|
"dependency-cruiser": "^17.4.3",
|
|
50
|
+
"esbuild": "^0.25.12",
|
|
47
51
|
"eslint": "^9.39.4",
|
|
48
52
|
"globals": "^16.5.0",
|
|
49
53
|
"prettier": "^3.8.4",
|
|
@@ -52,6 +56,6 @@
|
|
|
52
56
|
"vitest": "^4.0.18"
|
|
53
57
|
},
|
|
54
58
|
"dependencies": {
|
|
55
|
-
"mthds": "^0.
|
|
59
|
+
"mthds": "^0.19.0"
|
|
56
60
|
}
|
|
57
61
|
}
|