@itsoltech/basal-client 0.4.0 → 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/README.md CHANGED
@@ -77,10 +77,83 @@ retains the native JSON without those defaults. The one-argument raw `decide(req
77
77
 
78
78
  ## Batch API
79
79
 
80
+ Resource helpers (`create`, `wait`, `results`) require SDK 0.5.0+.
81
+
80
82
  Requires a Basal server with the Batch API enabled ([docs/BATCHES.md](https://github.com/itsoltech/basal-rs/blob/main/docs/BATCHES.md)).
81
83
  Every Batch and Files route needs `apiKey` set to a batch token `<key_id>.<secret>`, also on loopback; the owner
82
- of every file and batch comes from that token. Records are native `/v1/basal` requests; the SDK only transfers files and controls batches. It never polls:
83
- call `getBatch` at an interval your application chooses and stop on `completed`, `failed`, `expired` or `cancelled`.
84
+ of every file and batch comes from that token. Records are native `/v1/basal` requests; the SDK only transfers files and controls batches.
85
+ `client.files` and `client.batches` follow the OpenAI resource names and workflow (upload, create, retrieve, download).
86
+ That compatibility is in naming and workflow only: records are native Basal requests, not OpenAI chat payloads.
87
+
88
+ ```typescript
89
+ import { BasalBatchSubmissionError, BasalClient, batchInput, buildRequest, choice, parseBatchResults } from "@itsoltech/basal-client";
90
+
91
+ const client = new BasalClient({ baseUrl: "https://basal.example.com", apiKey: "<key_id>.<secret>" });
92
+ const body = buildRequest("Klient prosi o zwrot.", { department: choice("Dział?", { returns: "Zwroty", support: "Wsparcie" }) }, {});
93
+
94
+ // Simplified: records in, terminal batch and records out.
95
+ const batch = await client.batches.create({ requests: [{ custom_id: "ticket-1", body }], metadata: { source: "tickets" } });
96
+ const done = await client.batches.wait(batch.id); // completed, failed, expired or cancelled
97
+ for await (const line of client.batches.results(done.id)) { // output file, then error file
98
+ console.log(line.custom_id, line.response?.status_code ?? line.error?.code);
99
+ }
100
+ ```
101
+
102
+ ```typescript
103
+ // Same steps as separate calls: upload, create, retrieve, download.
104
+ const file = await client.files.create({ file: batchInput([{ custom_id: "ticket-1", body }]), filename: "tickets.jsonl" });
105
+ const created = await client.batches.create({ input_file_id: file.id }, { idempotencyKey: "tickets-2026-10-20" });
106
+ const current = await client.batches.retrieve(created.id);
107
+ const lines = current.output_file_id ? parseBatchResults(await client.files.content(current.output_file_id)) : [];
108
+ ```
109
+
110
+ | Resource method | Same as |
111
+ |---|---|
112
+ | `files.create`, `files.retrieve`, `files.list`, `files.delete`, `files.content` | `uploadFile`, `getFile`, `listFiles`, `deleteFile`, `downloadFile` |
113
+ | `batches.create({input_file_id, ...})`, `batches.retrieve`, `batches.list`, `batches.cancel` | `createBatch`, `getBatch`, `listBatches`, `cancelBatch` |
114
+ | `batches.create({requests, ...}, {idempotencyKey?, uploadTimeoutMs?, signal?})` | validate, `uploadFile`, `createBatch` |
115
+ | `batches.wait(id, {timeoutMs?, pollIntervalMs?, signal?})` | `getBatch` until a terminal status |
116
+ | `batches.results(id, {maxBytes?, timeoutMs?, signal?})` → async iterator | `getBatch`, `downloadFile`, line parsing |
117
+
118
+ `batches.create` takes exactly one of `input_file_id` and `requests` (a type error otherwise, and a `TypeError` at runtime).
119
+ `requests` is an iterable of `{custom_id, body, method?, url?}`; the SDK checks it before uploading anything: at least one
120
+ record, no other fields, unique `custom_id` of 1–256 UTF-8 bytes, `method` POST, `url` /v1/basal, an object `body`, at most
121
+ `MAX_BATCH_REQUESTS` (50 000) records and `MAX_BATCH_INPUT_BYTES` (200 000 000) bytes of JSONL. These are the server
122
+ defaults; a server configured lower refuses the upload or fails the batch. The JSONL is built in memory, so for a short
123
+ time memory holds up to about twice its size; `body` contents are checked by the server. Unknown top-level parameters
124
+ are refused locally in this form. The upload uses the client `timeoutMs` unless `uploadTimeoutMs` is set.
125
+ Without `idempotencyKey` the SDK generates one for the call. If the upload succeeds and creating the batch then fails
126
+ (HTTP, transport or abort), `BasalBatchSubmissionError` gives `fileId`, `idempotencyKey` and the original error in
127
+ `cause`. The file is not deleted and nothing is retried. The create may have succeeded on the server, so resume
128
+ with the file instead of uploading again:
129
+
130
+ ```typescript
131
+ try { await client.batches.create({ requests, metadata }); }
132
+ catch (error) {
133
+ if (!(error instanceof BasalBatchSubmissionError)) throw error;
134
+ await client.batches.create({ input_file_id: error.fileId, metadata }, { idempotencyKey: error.idempotencyKey });
135
+ }
136
+ ```
137
+
138
+ `batches.wait` retrieves immediately, then every `pollIntervalMs` (default 5000) until `completed`, `failed`, `expired`
139
+ or `cancelled`, and returns that batch. Check `status`, `errors` (validation errors of a `failed` batch) and
140
+ `request_counts`. Other and unknown statuses keep it waiting. `timeoutMs` (default 600 000) bounds the whole wait, including an
141
+ in-flight retrieve, which is aborted. It then raises `BasalBatchTimeoutError` with `batchId` and `lastBatch` (null if no
142
+ retrieve finished). The batch is not cancelled. HTTP and transport errors propagate without retries. Aborting
143
+ `signal` rejects with `BasalTransportError` (the reason in `cause`). Timers and listeners are removed when the wait ends;
144
+ nothing keeps running in the background.
145
+
146
+ `batches.results` does not wait: a batch that is not terminal raises `BasalBatchNotReadyError` (`batchId`, `status`).
147
+ It yields the records of `output_file_id`, then `error_file_id` (once if they are equal). Match records by `custom_id`, not by order. An
148
+ expired or cancelled batch yields its partial results; a completed batch can yield failed records (`response.status_code`
149
+ other than 200, or `error`). A batch without result files yields nothing. Each file is downloaded whole into memory,
150
+ bounded by `maxBytes` (default `maxResponseBytes`, 8 MiB); raise it for large results. `timeoutMs` is the deadline of each
151
+ download. The downloaded bytes are then decoded and checked one line at a time. A line that is not UTF-8 (including a BOM), not JSON, or not a
152
+ result envelope (`id`, `custom_id`, `response` or `error`) raises `BasalBatchResultError` (`fileId`, 1-based `line`, a
153
+ `BasalProtocolError`) after the earlier records were yielded; no record is skipped. Invalid arguments throw when
154
+ `results` is called; nothing is sent until iteration starts.
155
+
156
+ The flat methods below remain available with unchanged behavior. They never poll.
84
157
 
85
158
  ```typescript
86
159
  import { BasalClient, batchInput, buildRequest, choice, parseBatchResults } from "@itsoltech/basal-client";
@@ -124,7 +197,8 @@ metadata is retained. The SDK does not retry on its own. Resource ids and cursor
124
197
  the server answers malformed ids like missing resources (404). `cancelBatch` returns the batch in
125
198
  `cancelling`; cancellation ends asynchronously.
126
199
 
127
- Errors use the same classes as the online API: `BasalHTTPError` with the
200
+ `BasalBatchTimeoutError.lastBatch` and `BasalBatchNotReadyError.batch` are non-enumerable, like `BasalHTTPError.body`,
201
+ so default inspection does not log batch metadata. Errors use the same classes as the online API: `BasalHTTPError` with the
128
202
  `{"error": {message, type, param, code}}` body and `retryAfter` (429/503), and
129
203
  `BasalResponseTooLargeError` above the byte cap. Resource types preserve unknown fields at runtime, and
130
204
  status/code enumerations accept future string values.
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TERMINAL_BATCH_STATUSES = exports.MAX_BATCH_INPUT_BYTES = exports.MAX_BATCH_REQUESTS = void 0;
3
4
  exports.resourcePath = resourcePath;
4
5
  exports.listPath = listPath;
5
6
  exports.idempotencyHeader = idempotencyHeader;
@@ -7,7 +8,13 @@ exports.createBody = createBody;
7
8
  exports.uploadForm = uploadForm;
8
9
  exports.batchInput = batchInput;
9
10
  exports.parseBatchResults = parseBatchResults;
11
+ exports.serializeBatchRequests = serializeBatchRequests;
12
+ exports.readBatchResultLines = readBatchResultLines;
10
13
  const errors_cjs_1 = require("./errors.cjs");
14
+ /** Client-side bounds of `batches.create({requests})`, equal to the server defaults; a server may be configured lower. */
15
+ exports.MAX_BATCH_REQUESTS = 50_000;
16
+ exports.MAX_BATCH_INPUT_BYTES = 200_000_000;
17
+ exports.TERMINAL_BATCH_STATUSES = Object.freeze(["completed", "failed", "expired", "cancelled"]);
11
18
  const encoder = new TextEncoder();
12
19
  /** Path segment of a resource id. `.` and `..` would be resolved as dot segments by URL parsing. */
13
20
  function resourcePath(prefix, id, suffix = "") {
@@ -189,3 +196,117 @@ function parseBatchResults(content) {
189
196
  return value;
190
197
  });
191
198
  }
199
+ const LINE_KEYS = new Set(["custom_id", "method", "url", "body"]);
200
+ /** Validated JSONL of `batches.create({requests})`: nonempty, supported envelope, unique ids and the bounds above.
201
+ * The result is held in memory (at most `MAX_BATCH_INPUT_BYTES`). Never sends anything.
202
+ */
203
+ function serializeBatchRequests(requests) {
204
+ if (!requests || typeof requests !== "object" || typeof requests[Symbol.iterator] !== "function") {
205
+ throw new TypeError("requests must be an iterable of batch records");
206
+ }
207
+ const parts = [];
208
+ const seen = new Set();
209
+ let bytes = 0;
210
+ for (const line of requests) {
211
+ const at = `requests[${parts.length}]`;
212
+ if (parts.length >= exports.MAX_BATCH_REQUESTS)
213
+ throw new TypeError(`requests must have at most ${exports.MAX_BATCH_REQUESTS} records`);
214
+ if (!line || typeof line !== "object" || Array.isArray(line))
215
+ throw new TypeError(`${at} must be an object`);
216
+ for (const key of Object.keys(line)) {
217
+ if (!LINE_KEYS.has(key))
218
+ throw new TypeError(`${at} has unsupported field ${JSON.stringify(key)}`);
219
+ }
220
+ const { custom_id: id, body } = line;
221
+ // Lone surrogates have no UTF-8 form; the server compares ids byte for byte.
222
+ if (typeof id !== "string" || !id || /\p{Cs}/u.test(id) || encoder.encode(id).length > 256) {
223
+ throw new TypeError(`${at}.custom_id must be a string of 1-256 UTF-8 bytes`);
224
+ }
225
+ if (seen.has(id))
226
+ throw new TypeError(`${at}.custom_id duplicates an earlier record`);
227
+ seen.add(id);
228
+ if (line.method !== undefined && line.method !== "POST")
229
+ throw new TypeError(`${at}.method must be POST`);
230
+ if (line.url !== undefined && line.url !== "/v1/basal")
231
+ throw new TypeError(`${at}.url must be /v1/basal`);
232
+ if (!body || typeof body !== "object" || Array.isArray(body))
233
+ throw new TypeError(`${at}.body must be a native request object`);
234
+ if (body.stream === true)
235
+ throw new TypeError(`${at}.body.stream must not be true`);
236
+ let json;
237
+ try {
238
+ json = JSON.stringify({ custom_id: id, method: "POST", url: "/v1/basal", body });
239
+ }
240
+ catch (cause) {
241
+ throw new TypeError(`${at}.body is not serializable as JSON`, { cause });
242
+ }
243
+ const encoded = encoder.encode(json + "\n");
244
+ bytes += encoded.byteLength;
245
+ if (bytes > exports.MAX_BATCH_INPUT_BYTES)
246
+ throw new TypeError(`requests exceed ${exports.MAX_BATCH_INPUT_BYTES} bytes of JSONL`);
247
+ parts.push(encoded);
248
+ }
249
+ if (!parts.length)
250
+ throw new TypeError("requests must contain at least one record");
251
+ return new Blob(parts, { type: "application/jsonl" });
252
+ }
253
+ /** Result lines of one downloaded file, decoded and checked one line at a time (no list of all lines). A final LF is
254
+ * optional; any other empty line, invalid UTF-8 (a BOM included), JSON or envelope raises `BasalBatchResultError`.
255
+ * Unknown fields are preserved.
256
+ */
257
+ function* readBatchResultLines(content, fileId) {
258
+ const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
259
+ let start = 0;
260
+ for (let number = 1; start < content.byteLength; number++) {
261
+ // UTF-8 never encodes another code point with byte 0x0A, so splitting bytes at LF is exact.
262
+ let end = content.indexOf(0x0a, start);
263
+ if (end < 0)
264
+ end = content.byteLength;
265
+ const bytes = content.subarray(start, end);
266
+ start = end + 1;
267
+ let text;
268
+ try {
269
+ text = decoder.decode(bytes);
270
+ }
271
+ catch (cause) {
272
+ throw new errors_cjs_1.BasalBatchResultError(fileId, number, "is not UTF-8", { cause });
273
+ }
274
+ let value;
275
+ try {
276
+ value = JSON.parse(text);
277
+ }
278
+ catch (cause) {
279
+ throw new errors_cjs_1.BasalBatchResultError(fileId, number, "is not JSON", { cause });
280
+ }
281
+ const problem = envelopeProblem(value);
282
+ if (problem)
283
+ throw new errors_cjs_1.BasalBatchResultError(fileId, number, problem);
284
+ yield value;
285
+ }
286
+ }
287
+ function isObject(value) {
288
+ return value !== null && typeof value === "object" && !Array.isArray(value);
289
+ }
290
+ function envelopeProblem(value) {
291
+ if (!isObject(value))
292
+ return "is not a JSON object";
293
+ if (typeof value.id !== "string" || !value.id)
294
+ return "has no string id";
295
+ if (typeof value.custom_id !== "string" || !value.custom_id)
296
+ return "has no string custom_id";
297
+ const { response, error } = value;
298
+ if (response === undefined || error === undefined)
299
+ return "lacks response or error";
300
+ if (response !== null && (!isObject(response) || !Number.isSafeInteger(response.status_code)
301
+ || response.status_code < 100 || response.status_code > 599
302
+ || typeof response.request_id !== "string" || !response.request_id || !isObject(response.body)))
303
+ return "has an invalid response";
304
+ if (error !== null && (!isObject(error) || typeof error.code !== "string" || !error.code || typeof error.message !== "string")) {
305
+ return "has an invalid error";
306
+ }
307
+ if (response === null && error === null)
308
+ return "has neither response nor error";
309
+ if (response !== null && error !== null)
310
+ return "has both response and error";
311
+ return undefined;
312
+ }
@@ -146,6 +146,45 @@ export interface UploadFileRequest {
146
146
  /** File lifetime (server default 30 days). */
147
147
  expires_after?: ExpiresAfter;
148
148
  }
149
+ /** Parameters shared by both `batches.create` forms. Defaults: `endpoint: "/v1/basal"`, `completion_window: "24h"`. */
150
+ export interface BatchCreateCommonParams {
151
+ endpoint?: "/v1/basal";
152
+ completion_window?: "24h";
153
+ metadata?: Metadata | null;
154
+ /** Lifetime of each result file, anchored at its creation. */
155
+ output_expires_after?: ExpiresAfter | null;
156
+ }
157
+ /** Create a batch from an uploaded input file; the same request as `createBatch`. */
158
+ export interface BatchCreateFromFileParams extends BatchCreateCommonParams {
159
+ input_file_id: string;
160
+ requests?: never;
161
+ }
162
+ /** Create a batch from records: the SDK writes JSONL in memory, uploads it (`purpose=batch`), then creates the batch. */
163
+ export interface BatchCreateFromRequestsParams extends BatchCreateCommonParams {
164
+ /** 1–50 000 records, unique `custom_id` (1–256 UTF-8 bytes), at most 200 000 000 bytes of JSONL in total. */
165
+ requests: Iterable<BatchInputLine>;
166
+ input_file_id?: never;
167
+ }
168
+ /** Exactly one of `input_file_id` or `requests`. */
169
+ export type BatchCreateParams = BatchCreateFromFileParams | BatchCreateFromRequestsParams;
170
+ export interface BatchCreateOptions extends CreateBatchOptions {
171
+ /** Deadline of the input upload (`requests` form only); defaults to the client `timeoutMs`. */
172
+ uploadTimeoutMs?: number;
173
+ }
174
+ export interface BatchWaitOptions extends RequestOptions {
175
+ /** Deadline of the whole wait, including in-flight retrieves and sleeps; default 600 000 ms. */
176
+ timeoutMs?: number;
177
+ /** Delay between retrieves; default 5000 ms. The first retrieve is immediate. */
178
+ pollIntervalMs?: number;
179
+ }
180
+ /** Each result file is downloaded whole into memory (up to `maxBytes`, default the client `maxResponseBytes`) and
181
+ * parsed one line at a time; `timeoutMs` is the deadline of each download.
182
+ */
183
+ export type BatchResultsOptions = DownloadOptions;
184
+ /** Client-side bounds of `batches.create({requests})`, equal to the server defaults; a server may be configured lower. */
185
+ export declare const MAX_BATCH_REQUESTS = 50000;
186
+ export declare const MAX_BATCH_INPUT_BYTES = 200000000;
187
+ export declare const TERMINAL_BATCH_STATUSES: readonly BatchStatus[];
149
188
  /** Path segment of a resource id. `.` and `..` would be resolved as dot segments by URL parsing. */
150
189
  export declare function resourcePath(prefix: string, id: string, suffix?: string): string;
151
190
  export declare function listPath(path: string, options: ListFilesOptions): string;
@@ -164,3 +203,12 @@ export declare function uploadForm(request: UploadFileRequest): Multipart;
164
203
  export declare function batchInput(lines: Iterable<BatchInputLine>): Uint8Array;
165
204
  /** Parse downloaded result bytes (output or error file) into lines. Never fetches anything. */
166
205
  export declare function parseBatchResults(content: Uint8Array): BatchResultLine[];
206
+ /** Validated JSONL of `batches.create({requests})`: nonempty, supported envelope, unique ids and the bounds above.
207
+ * The result is held in memory (at most `MAX_BATCH_INPUT_BYTES`). Never sends anything.
208
+ */
209
+ export declare function serializeBatchRequests(requests: Iterable<BatchInputLine>): Blob;
210
+ /** Result lines of one downloaded file, decoded and checked one line at a time (no list of all lines). A final LF is
211
+ * optional; any other empty line, invalid UTF-8 (a BOM included), JSON or envelope raises `BasalBatchResultError`.
212
+ * Unknown fields are preserved.
213
+ */
214
+ export declare function readBatchResultLines(content: Uint8Array, fileId: string): Generator<BatchResultLine, void, undefined>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BasalResponseTooLargeError = exports.BasalProtocolError = exports.BasalTransportError = exports.BasalHTTPError = exports.BasalError = void 0;
3
+ exports.BasalBatchResultError = exports.BasalBatchNotReadyError = exports.BasalBatchTimeoutError = exports.BasalBatchSubmissionError = exports.BasalResponseTooLargeError = exports.BasalProtocolError = exports.BasalTransportError = exports.BasalHTTPError = exports.BasalError = void 0;
4
4
  class BasalError extends Error {
5
5
  }
6
6
  exports.BasalError = BasalError;
@@ -29,3 +29,69 @@ exports.BasalProtocolError = BasalProtocolError;
29
29
  class BasalResponseTooLargeError extends BasalError {
30
30
  }
31
31
  exports.BasalResponseTooLargeError = BasalResponseTooLargeError;
32
+ /** `batches.create({requests})` uploaded the input file, but creating the batch failed (HTTP, transport or abort).
33
+ * The SDK neither retries nor deletes the file. The create may still have succeeded on the server, so resume with
34
+ * the same parameters, `{input_file_id: error.fileId}` and `{idempotencyKey: error.idempotencyKey}`; the original
35
+ * failure is in `cause`.
36
+ */
37
+ class BasalBatchSubmissionError extends BasalError {
38
+ file;
39
+ idempotencyKey;
40
+ fileId;
41
+ constructor(file, idempotencyKey, options) {
42
+ super(`Basal batch creation failed after uploading input file ${file.id}`, options);
43
+ this.file = file;
44
+ this.idempotencyKey = idempotencyKey;
45
+ this.name = "BasalBatchSubmissionError";
46
+ this.fileId = file.id;
47
+ }
48
+ }
49
+ exports.BasalBatchSubmissionError = BasalBatchSubmissionError;
50
+ /** `batches.wait` reached its deadline. The batch keeps running on the server; nothing is cancelled.
51
+ * `lastBatch` is the last retrieved state (null if no retrieve finished) and is non-enumerable, like `BasalHTTPError.body`.
52
+ */
53
+ class BasalBatchTimeoutError extends BasalError {
54
+ batchId;
55
+ lastBatch;
56
+ timeoutMs;
57
+ constructor(batchId, lastBatch, timeoutMs, options) {
58
+ super(`Basal batch did not reach a terminal status within ${timeoutMs} ms`, options);
59
+ this.batchId = batchId;
60
+ this.lastBatch = lastBatch;
61
+ this.timeoutMs = timeoutMs;
62
+ this.name = "BasalBatchTimeoutError";
63
+ Object.defineProperty(this, "lastBatch", { enumerable: false });
64
+ }
65
+ }
66
+ exports.BasalBatchTimeoutError = BasalBatchTimeoutError;
67
+ /** `batches.results` was called for a batch that is not `completed`, `failed`, `expired` or `cancelled`.
68
+ * `batch` (non-enumerable) is the retrieved state; `status` is its raw status.
69
+ */
70
+ class BasalBatchNotReadyError extends BasalError {
71
+ batchId;
72
+ batch;
73
+ status;
74
+ constructor(batchId, batch) {
75
+ super("Basal batch has not reached a terminal status");
76
+ this.batchId = batchId;
77
+ this.batch = batch;
78
+ this.name = "BasalBatchNotReadyError";
79
+ this.status = String(batch.status);
80
+ Object.defineProperty(this, "batch", { enumerable: false });
81
+ }
82
+ }
83
+ exports.BasalBatchNotReadyError = BasalBatchNotReadyError;
84
+ /** A result file line that is not UTF-8, not JSON or not a result envelope. `line` is 1-based; the content is not
85
+ * copied into the error.
86
+ */
87
+ class BasalBatchResultError extends BasalProtocolError {
88
+ fileId;
89
+ line;
90
+ constructor(fileId, line, reason, options) {
91
+ super(`Batch result file ${fileId} line ${line} ${reason}`, options);
92
+ this.fileId = fileId;
93
+ this.line = line;
94
+ this.name = "BasalBatchResultError";
95
+ }
96
+ }
97
+ exports.BasalBatchResultError = BasalBatchResultError;
@@ -1,3 +1,4 @@
1
+ import type { Batch, FileObject } from "./batches.cjs";
1
2
  export declare class BasalError extends Error {
2
3
  }
3
4
  /** Non-2xx response. Server body and Retry-After are available without logging them. */
@@ -13,3 +14,46 @@ export declare class BasalProtocolError extends BasalError {
13
14
  }
14
15
  export declare class BasalResponseTooLargeError extends BasalError {
15
16
  }
17
+ /** `batches.create({requests})` uploaded the input file, but creating the batch failed (HTTP, transport or abort).
18
+ * The SDK neither retries nor deletes the file. The create may still have succeeded on the server, so resume with
19
+ * the same parameters, `{input_file_id: error.fileId}` and `{idempotencyKey: error.idempotencyKey}`; the original
20
+ * failure is in `cause`.
21
+ */
22
+ export declare class BasalBatchSubmissionError extends BasalError {
23
+ readonly file: FileObject;
24
+ readonly idempotencyKey: string;
25
+ readonly fileId: string;
26
+ constructor(file: FileObject, idempotencyKey: string, options: {
27
+ cause: unknown;
28
+ });
29
+ }
30
+ /** `batches.wait` reached its deadline. The batch keeps running on the server; nothing is cancelled.
31
+ * `lastBatch` is the last retrieved state (null if no retrieve finished) and is non-enumerable, like `BasalHTTPError.body`.
32
+ */
33
+ export declare class BasalBatchTimeoutError extends BasalError {
34
+ readonly batchId: string;
35
+ readonly lastBatch: Batch | null;
36
+ readonly timeoutMs: number;
37
+ constructor(batchId: string, lastBatch: Batch | null, timeoutMs: number, options?: {
38
+ cause: unknown;
39
+ });
40
+ }
41
+ /** `batches.results` was called for a batch that is not `completed`, `failed`, `expired` or `cancelled`.
42
+ * `batch` (non-enumerable) is the retrieved state; `status` is its raw status.
43
+ */
44
+ export declare class BasalBatchNotReadyError extends BasalError {
45
+ readonly batchId: string;
46
+ readonly batch: Batch;
47
+ readonly status: string;
48
+ constructor(batchId: string, batch: Batch);
49
+ }
50
+ /** A result file line that is not UTF-8, not JSON or not a result envelope. `line` is 1-based; the content is not
51
+ * copied into the error.
52
+ */
53
+ export declare class BasalBatchResultError extends BasalProtocolError {
54
+ readonly fileId: string;
55
+ readonly line: number;
56
+ constructor(fileId: string, line: number, reason: string, options?: {
57
+ cause: unknown;
58
+ });
59
+ }
@@ -14,17 +14,24 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.BasalClient = exports.parseBatchResults = exports.batchInput = void 0;
17
+ exports.BasalClient = exports.Files = exports.Batches = exports.TERMINAL_BATCH_STATUSES = exports.parseBatchResults = exports.MAX_BATCH_REQUESTS = exports.MAX_BATCH_INPUT_BYTES = exports.batchInput = void 0;
18
18
  const questions_cjs_1 = require("./questions.cjs");
19
19
  const errors_cjs_1 = require("./errors.cjs");
20
20
  const batches_cjs_1 = require("./batches.cjs");
21
+ const resources_cjs_1 = require("./resources.cjs");
21
22
  __exportStar(require("./questions.cjs"), exports);
22
23
  __exportStar(require("./media.cjs"), exports);
23
24
  __exportStar(require("./tasks.cjs"), exports);
24
25
  __exportStar(require("./errors.cjs"), exports);
25
26
  var batches_cjs_2 = require("./batches.cjs");
26
27
  Object.defineProperty(exports, "batchInput", { enumerable: true, get: function () { return batches_cjs_2.batchInput; } });
28
+ Object.defineProperty(exports, "MAX_BATCH_INPUT_BYTES", { enumerable: true, get: function () { return batches_cjs_2.MAX_BATCH_INPUT_BYTES; } });
29
+ Object.defineProperty(exports, "MAX_BATCH_REQUESTS", { enumerable: true, get: function () { return batches_cjs_2.MAX_BATCH_REQUESTS; } });
27
30
  Object.defineProperty(exports, "parseBatchResults", { enumerable: true, get: function () { return batches_cjs_2.parseBatchResults; } });
31
+ Object.defineProperty(exports, "TERMINAL_BATCH_STATUSES", { enumerable: true, get: function () { return batches_cjs_2.TERMINAL_BATCH_STATUSES; } });
32
+ var resources_cjs_2 = require("./resources.cjs");
33
+ Object.defineProperty(exports, "Batches", { enumerable: true, get: function () { return resources_cjs_2.Batches; } });
34
+ Object.defineProperty(exports, "Files", { enumerable: true, get: function () { return resources_cjs_2.Files; } });
28
35
  async function readBody(response, limit, signal) {
29
36
  // Count bytes from the actual stream, including decompressed responses; never trust Content-Length alone.
30
37
  const reader = response.body?.getReader();
@@ -88,6 +95,10 @@ class BasalClient {
88
95
  timeoutMs;
89
96
  maxResponseBytes;
90
97
  fetch;
98
+ /** Files API under resource names: `create`, `retrieve`, `list`, `delete`, `content`. */
99
+ files;
100
+ /** Batch API under resource names, with `create({requests})`, `wait` and `results`. */
101
+ batches;
91
102
  constructor(options = {}) {
92
103
  const url = new URL(options.baseUrl ?? "http://127.0.0.1:8000");
93
104
  if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("?") || url.href.includes("#")) {
@@ -112,6 +123,8 @@ class BasalClient {
112
123
  throw new TypeError("apiKey must be a nonempty, single-line token");
113
124
  this.headers.Authorization = `Bearer ${options.apiKey}`;
114
125
  }
126
+ this.files = new resources_cjs_1.Files(this);
127
+ this.batches = new resources_cjs_1.Batches(this);
115
128
  }
116
129
  request(method, path, body, signal) {
117
130
  return this.call({ method, path, json: body, signal });
@@ -1,11 +1,13 @@
1
1
  import { type QuestionSet, type TypedDecisionResponse, type DecisionOptions } from "./questions.cjs";
2
2
  import { type Batch, type BatchList, type CreateBatchOptions, type CreateBatchRequest, type DeletedFile, type DownloadOptions, type FileList, type FileObject, type ListFilesOptions, type ListOptions, type RequestOptions, type TransferOptions, type UploadFileRequest } from "./batches.cjs";
3
+ import { Batches, Files } from "./resources.cjs";
3
4
  export * from "./questions.cjs";
4
5
  export * from "./media.cjs";
5
6
  export * from "./tasks.cjs";
6
7
  export * from "./errors.cjs";
7
- export { batchInput, parseBatchResults } from "./batches.cjs";
8
- export type { Batch, BatchErrorCode, BatchErrorEntry, BatchErrors, BatchInputLine, BatchList, BatchResultLine, BatchStatus, CreateBatchOptions, CreateBatchRequest, DeletedFile, DownloadOptions, ExpiresAfter, FileList, FileObject, FilePurpose, ListFilesOptions, ListOptions, ListPage, Metadata, RequestCounts, RequestOptions, TransferOptions, UploadContent, UploadFileRequest, } from "./batches.cjs";
8
+ export { batchInput, MAX_BATCH_INPUT_BYTES, MAX_BATCH_REQUESTS, parseBatchResults, TERMINAL_BATCH_STATUSES, } from "./batches.cjs";
9
+ export { Batches, Files } from "./resources.cjs";
10
+ export type { Batch, BatchCreateCommonParams, BatchCreateFromFileParams, BatchCreateFromRequestsParams, BatchCreateOptions, BatchCreateParams, BatchErrorCode, BatchErrorEntry, BatchErrors, BatchInputLine, BatchList, BatchResultLine, BatchResultsOptions, BatchStatus, BatchWaitOptions, CreateBatchOptions, CreateBatchRequest, DeletedFile, DownloadOptions, ExpiresAfter, FileList, FileObject, FilePurpose, ListFilesOptions, ListOptions, ListPage, Metadata, RequestCounts, RequestOptions, TransferOptions, UploadContent, UploadFileRequest, } from "./batches.cjs";
9
11
  import type { TaskAnswer } from "./tasks.cjs";
10
12
  /** Native Basal wire types. Criterion order is significant; do not sort keys. */
11
13
  export type JsonValue = string | number | boolean | null | JsonValue[] | {
@@ -189,6 +191,10 @@ export declare class BasalClient {
189
191
  private readonly timeoutMs;
190
192
  private readonly maxResponseBytes;
191
193
  private readonly fetch;
194
+ /** Files API under resource names: `create`, `retrieve`, `list`, `delete`, `content`. */
195
+ readonly files: Files;
196
+ /** Batch API under resource names, with `create({requests})`, `wait` and `results`. */
197
+ readonly batches: Batches;
192
198
  constructor(options?: BasalClientOptions);
193
199
  private request;
194
200
  private call;