@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 +77 -3
- package/dist/cjs/batches.cjs +121 -0
- package/dist/cjs/batches.d.cts +48 -0
- package/dist/cjs/errors.cjs +67 -1
- package/dist/cjs/errors.d.cts +44 -0
- package/dist/cjs/index.cjs +14 -1
- package/dist/cjs/index.d.cts +8 -2
- package/dist/cjs/resources.cjs +206 -0
- package/dist/cjs/resources.d.cts +48 -0
- package/dist/esm/batches.d.ts +48 -0
- package/dist/esm/batches.js +119 -1
- package/dist/esm/errors.d.ts +44 -0
- package/dist/esm/errors.js +62 -0
- package/dist/esm/index.d.ts +8 -2
- package/dist/esm/index.js +9 -1
- package/dist/esm/resources.d.ts +48 -0
- package/dist/esm/resources.js +201 -0
- package/package.json +1 -1
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.
|
|
83
|
-
|
|
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
|
-
|
|
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.
|
package/dist/cjs/batches.cjs
CHANGED
|
@@ -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
|
+
}
|
package/dist/cjs/batches.d.cts
CHANGED
|
@@ -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>;
|
package/dist/cjs/errors.cjs
CHANGED
|
@@ -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;
|
package/dist/cjs/errors.d.cts
CHANGED
|
@@ -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
|
+
}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -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 });
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -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
|
|
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;
|