@itsoltech/basal-client 0.3.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.
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BasalBatchResultError = exports.BasalBatchNotReadyError = exports.BasalBatchTimeoutError = exports.BasalBatchSubmissionError = exports.BasalResponseTooLargeError = exports.BasalProtocolError = exports.BasalTransportError = exports.BasalHTTPError = exports.BasalError = void 0;
4
+ class BasalError extends Error {
5
+ }
6
+ exports.BasalError = BasalError;
7
+ /** Non-2xx response. Server body and Retry-After are available without logging them. */
8
+ class BasalHTTPError extends BasalError {
9
+ statusCode;
10
+ body;
11
+ retryAfter;
12
+ constructor(statusCode, body, retryAfter) {
13
+ super(`Basal HTTP ${statusCode}`);
14
+ this.statusCode = statusCode;
15
+ this.body = body;
16
+ this.retryAfter = retryAfter;
17
+ this.name = "BasalHTTPError";
18
+ // Node's default inspection and JSON.stringify must not print reflected state or credentials.
19
+ Object.defineProperty(this, "body", { enumerable: false });
20
+ }
21
+ }
22
+ exports.BasalHTTPError = BasalHTTPError;
23
+ class BasalTransportError extends BasalError {
24
+ }
25
+ exports.BasalTransportError = BasalTransportError;
26
+ class BasalProtocolError extends BasalError {
27
+ }
28
+ exports.BasalProtocolError = BasalProtocolError;
29
+ class BasalResponseTooLargeError extends BasalError {
30
+ }
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;
@@ -0,0 +1,59 @@
1
+ import type { Batch, FileObject } from "./batches.cjs";
2
+ export declare class BasalError extends Error {
3
+ }
4
+ /** Non-2xx response. Server body and Retry-After are available without logging them. */
5
+ export declare class BasalHTTPError extends BasalError {
6
+ readonly statusCode: number;
7
+ readonly body: unknown;
8
+ readonly retryAfter: string | null;
9
+ constructor(statusCode: number, body: unknown, retryAfter: string | null);
10
+ }
11
+ export declare class BasalTransportError extends BasalError {
12
+ }
13
+ export declare class BasalProtocolError extends BasalError {
14
+ }
15
+ export declare class BasalResponseTooLargeError extends BasalError {
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,49 +14,33 @@ 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.BasalResponseTooLargeError = exports.BasalProtocolError = exports.BasalTransportError = exports.BasalHTTPError = exports.BasalError = 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
+ const errors_cjs_1 = require("./errors.cjs");
20
+ const batches_cjs_1 = require("./batches.cjs");
21
+ const resources_cjs_1 = require("./resources.cjs");
19
22
  __exportStar(require("./questions.cjs"), exports);
20
23
  __exportStar(require("./media.cjs"), exports);
21
24
  __exportStar(require("./tasks.cjs"), exports);
22
- class BasalError extends Error {
23
- }
24
- exports.BasalError = BasalError;
25
- /** Non-2xx response. Server body and Retry-After are available without logging them. */
26
- class BasalHTTPError extends BasalError {
27
- statusCode;
28
- body;
29
- retryAfter;
30
- constructor(statusCode, body, retryAfter) {
31
- super(`Basal HTTP ${statusCode}`);
32
- this.statusCode = statusCode;
33
- this.body = body;
34
- this.retryAfter = retryAfter;
35
- this.name = "BasalHTTPError";
36
- // Node's default inspection and JSON.stringify must not print reflected state or credentials.
37
- Object.defineProperty(this, "body", { enumerable: false });
38
- }
39
- }
40
- exports.BasalHTTPError = BasalHTTPError;
41
- class BasalTransportError extends BasalError {
42
- }
43
- exports.BasalTransportError = BasalTransportError;
44
- class BasalProtocolError extends BasalError {
45
- }
46
- exports.BasalProtocolError = BasalProtocolError;
47
- class BasalResponseTooLargeError extends BasalError {
48
- }
49
- exports.BasalResponseTooLargeError = BasalResponseTooLargeError;
25
+ __exportStar(require("./errors.cjs"), exports);
26
+ var batches_cjs_2 = require("./batches.cjs");
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; } });
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; } });
50
35
  async function readBody(response, limit, signal) {
51
36
  // Count bytes from the actual stream, including decompressed responses; never trust Content-Length alone.
52
37
  const reader = response.body?.getReader();
53
38
  if (!reader)
54
- return "";
39
+ return new Uint8Array();
55
40
  const cancel = () => { void reader.cancel().catch(() => { }); };
56
41
  signal.addEventListener("abort", cancel, { once: true });
57
42
  if (signal.aborted)
58
43
  cancel();
59
- const decoder = new TextDecoder("utf-8", { fatal: true });
60
44
  const parts = [];
61
45
  let bytes = 0;
62
46
  let complete = false;
@@ -69,20 +53,38 @@ async function readBody(response, limit, signal) {
69
53
  }
70
54
  bytes += value.byteLength;
71
55
  if (bytes > limit) {
72
- throw new BasalResponseTooLargeError(`Basal response exceeds ${limit} bytes`);
56
+ throw new errors_cjs_1.BasalResponseTooLargeError(`Basal response exceeds ${limit} bytes`);
73
57
  }
74
- parts.push(decoder.decode(value, { stream: true }));
58
+ parts.push(value);
75
59
  }
76
- parts.push(decoder.decode());
77
- return parts.join("");
78
60
  }
79
61
  finally {
80
62
  signal.removeEventListener("abort", cancel);
81
- // A decoder/read failure must also stop the underlying HTTP body, before releasing ownership.
63
+ // A read failure must also stop the underlying HTTP body, before releasing ownership.
82
64
  if (!complete)
83
65
  cancel();
84
66
  reader.releaseLock();
85
67
  }
68
+ if (parts.length === 1)
69
+ return parts[0];
70
+ const out = new Uint8Array(bytes);
71
+ let offset = 0;
72
+ for (const part of parts) {
73
+ out.set(part, offset);
74
+ offset += part.byteLength;
75
+ }
76
+ return out;
77
+ }
78
+ function positiveTimeout(value, name) {
79
+ if (!Number.isFinite(value) || value <= 0 || value > 2_147_483_647) {
80
+ throw new TypeError(`${name} must be positive and at most 2147483647`);
81
+ }
82
+ return value;
83
+ }
84
+ function byteLimit(value, name) {
85
+ if (!Number.isSafeInteger(value) || value <= 0)
86
+ throw new TypeError(`${name} must be a positive safe integer`);
87
+ return value;
86
88
  }
87
89
  /** Reusable fetch client. Server root URL, optional proxy prefix, without /v1.
88
90
  * No automatic retries. AbortSignal cancels a request; timeout includes body reading.
@@ -93,6 +95,10 @@ class BasalClient {
93
95
  timeoutMs;
94
96
  maxResponseBytes;
95
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;
96
102
  constructor(options = {}) {
97
103
  const url = new URL(options.baseUrl ?? "http://127.0.0.1:8000");
98
104
  if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("?") || url.href.includes("#")) {
@@ -117,56 +123,82 @@ class BasalClient {
117
123
  throw new TypeError("apiKey must be a nonempty, single-line token");
118
124
  this.headers.Authorization = `Bearer ${options.apiKey}`;
119
125
  }
126
+ this.files = new resources_cjs_1.Files(this);
127
+ this.batches = new resources_cjs_1.Batches(this);
128
+ }
129
+ request(method, path, body, signal) {
130
+ return this.call({ method, path, json: body, signal });
120
131
  }
121
- async request(method, path, body, signal) {
122
- // Serialization errors are local input errors, not failures of the HTTP transport.
123
- const encoded = body === undefined ? undefined : JSON.stringify(body);
132
+ async call(call) {
133
+ // Serialization and option errors are local input errors, not failures of the HTTP transport.
134
+ const encoded = call.json === undefined ? undefined : JSON.stringify(call.json);
135
+ const timeoutMs = call.timeoutMs === undefined ? this.timeoutMs : positiveTimeout(call.timeoutMs, "timeoutMs");
136
+ const limit = call.maxBytes === undefined ? this.maxResponseBytes : byteLimit(call.maxBytes, "maxBytes");
137
+ const headers = { ...this.headers, ...call.headers };
138
+ if (encoded !== undefined)
139
+ headers["Content-Type"] = "application/json";
140
+ const { signal } = call;
124
141
  const controller = new AbortController();
125
142
  const abort = () => controller.abort(signal?.reason);
126
143
  signal?.addEventListener("abort", abort, { once: true });
127
144
  if (signal?.aborted)
128
145
  abort();
129
- const timer = setTimeout(() => controller.abort(new Error("Basal request timed out")), this.timeoutMs);
146
+ const timer = setTimeout(() => controller.abort(new Error("Basal request timed out")), timeoutMs);
130
147
  let onAbort = () => { };
131
148
  const aborted = new Promise((_, reject) => {
132
- onAbort = () => reject(new BasalTransportError("Basal HTTP request aborted", { cause: controller.signal.reason }));
149
+ onAbort = () => reject(new errors_cjs_1.BasalTransportError("Basal HTTP request aborted", { cause: controller.signal.reason }));
133
150
  controller.signal.addEventListener("abort", onAbort, { once: true });
134
151
  if (controller.signal.aborted)
135
152
  onAbort();
136
153
  });
137
154
  const work = async () => {
138
155
  let response;
139
- let raw;
156
+ let content;
157
+ let raw = "";
140
158
  try {
141
- response = await this.fetch(this.baseUrl + path, {
142
- method, headers: body === undefined ? this.headers : { ...this.headers, "Content-Type": "application/json" },
143
- ...(encoded === undefined ? {} : { body: encoded }),
144
- signal: controller.signal, redirect: "error", credentials: "omit", cache: "no-store",
145
- });
159
+ const init = {
160
+ method: call.method, headers, signal: controller.signal, redirect: "error", credentials: "omit", cache: "no-store",
161
+ };
162
+ if (encoded !== undefined)
163
+ init.body = encoded;
164
+ else if (call.body instanceof Blob)
165
+ init.body = call.body;
166
+ else if (call.body !== undefined) {
167
+ // Streamed request bodies require half-duplex fetch (Node.js, Chromium over HTTP/2).
168
+ init.body = call.body(controller.signal);
169
+ init.duplex = "half";
170
+ }
171
+ response = await this.fetch(this.baseUrl + call.path, init);
146
172
  if (response.redirected || ([301, 302, 303, 307, 308].includes(response.status) && response.headers.has("Location"))) {
147
173
  await response.body?.cancel().catch(() => { });
148
- throw new BasalTransportError("Basal transport returned a redirect");
174
+ throw new errors_cjs_1.BasalTransportError("Basal transport returned a redirect");
149
175
  }
150
- raw = await readBody(response, this.maxResponseBytes, controller.signal);
176
+ // A per-download cap limits successful artifact bytes. Error envelopes retain the client's normal cap
177
+ // so a small artifact cap does not hide an actionable 404/429 and its Retry-After.
178
+ content = await readBody(response, response.ok ? limit : this.maxResponseBytes, controller.signal);
179
+ if (!call.bytes || !response.ok)
180
+ raw = new TextDecoder("utf-8", { fatal: true }).decode(content);
151
181
  }
152
182
  catch (cause) {
153
- if (cause instanceof BasalError)
183
+ if (cause instanceof errors_cjs_1.BasalError)
154
184
  throw cause;
155
- throw new BasalTransportError("Basal HTTP transport failed", { cause });
185
+ throw new errors_cjs_1.BasalTransportError("Basal HTTP transport failed", { cause });
156
186
  }
187
+ if (call.bytes && response.ok)
188
+ return content;
157
189
  let data;
158
190
  try {
159
191
  data = JSON.parse(raw);
160
192
  }
161
193
  catch (cause) {
162
194
  if (response.ok)
163
- throw new BasalProtocolError("Basal returned invalid JSON", { cause });
195
+ throw new errors_cjs_1.BasalProtocolError("Basal returned invalid JSON", { cause });
164
196
  data = raw;
165
197
  }
166
198
  if (!response.ok)
167
- throw new BasalHTTPError(response.status, data, response.headers.get("Retry-After"));
199
+ throw new errors_cjs_1.BasalHTTPError(response.status, data, response.headers.get("Retry-After"));
168
200
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
169
- throw new BasalProtocolError("Basal returned a JSON value other than an object");
201
+ throw new errors_cjs_1.BasalProtocolError("Basal returned a JSON value other than an object");
170
202
  }
171
203
  return data;
172
204
  };
@@ -179,6 +211,9 @@ class BasalClient {
179
211
  controller.signal.removeEventListener("abort", onAbort);
180
212
  clearTimeout(timer);
181
213
  signal?.removeEventListener("abort", abort);
214
+ // An answer can arrive before a streamed upload is fully sent (e.g. 413); stop its source.
215
+ if (typeof call.body === "function")
216
+ controller.abort(new Error("Basal request finished"));
182
217
  }
183
218
  }
184
219
  async decide(state, questionsOrSignal, options = {}) {
@@ -198,7 +233,7 @@ class BasalClient {
198
233
  parsed.set(id, question.read(response, id));
199
234
  }
200
235
  catch (cause) {
201
- throw new BasalProtocolError("Invalid typed Basal answer", { cause });
236
+ throw new errors_cjs_1.BasalProtocolError("Invalid typed Basal answer", { cause });
202
237
  }
203
238
  const typed = { ...response, answers: Object.fromEntries(parsed) };
204
239
  Object.defineProperty(typed, "raw", { value: response });
@@ -213,5 +248,46 @@ class BasalClient {
213
248
  return typed;
214
249
  }
215
250
  models(signal) { return this.request("GET", "v1/models", undefined, signal); }
251
+ /** Upload a JSONL input file (`purpose=batch`) from caller-owned bytes, a Blob or a stream; never fetches URLs. */
252
+ async uploadFile(request, options = {}) {
253
+ const form = (0, batches_cjs_1.uploadForm)(request);
254
+ return await this.call({
255
+ method: "POST", path: "v1/files", body: form.body, headers: { "Content-Type": form.contentType },
256
+ signal: options.signal, timeoutMs: options.timeoutMs,
257
+ });
258
+ }
259
+ async listFiles(options = {}) {
260
+ return await this.call({ method: "GET", path: (0, batches_cjs_1.listPath)("v1/files", options), signal: options.signal });
261
+ }
262
+ async getFile(fileId, options = {}) {
263
+ return await this.call({ method: "GET", path: (0, batches_cjs_1.resourcePath)("v1/files", fileId), signal: options.signal });
264
+ }
265
+ async deleteFile(fileId, options = {}) {
266
+ return await this.call({ method: "DELETE", path: (0, batches_cjs_1.resourcePath)("v1/files", fileId), signal: options.signal });
267
+ }
268
+ /** Raw file bytes (JSONL), buffered up to `maxBytes` (default `maxResponseBytes`); never JSON-parsed. */
269
+ async downloadFile(fileId, options = {}) {
270
+ return await this.call({
271
+ method: "GET", path: (0, batches_cjs_1.resourcePath)("v1/files", fileId, "/content"), bytes: true,
272
+ headers: { Accept: "application/jsonl, application/json" },
273
+ signal: options.signal, timeoutMs: options.timeoutMs, maxBytes: options.maxBytes,
274
+ });
275
+ }
276
+ async createBatch(request, options = {}) {
277
+ const headers = (0, batches_cjs_1.idempotencyHeader)(options.idempotencyKey);
278
+ return await this.call({ method: "POST", path: "v1/batches", json: (0, batches_cjs_1.createBody)(request), headers, signal: options.signal });
279
+ }
280
+ async listBatches(options = {}) {
281
+ const { after, limit } = options;
282
+ const query = { ...(after === undefined ? {} : { after }), ...(limit === undefined ? {} : { limit }) };
283
+ return await this.call({ method: "GET", path: (0, batches_cjs_1.listPath)("v1/batches", query), signal: options.signal });
284
+ }
285
+ async getBatch(batchId, options = {}) {
286
+ return await this.call({ method: "GET", path: (0, batches_cjs_1.resourcePath)("v1/batches", batchId), signal: options.signal });
287
+ }
288
+ /** Request cancellation; the batch moves to `cancelling` and later `cancelled`. Does not wait. */
289
+ async cancelBatch(batchId, options = {}) {
290
+ return await this.call({ method: "POST", path: (0, batches_cjs_1.resourcePath)("v1/batches", batchId, "/cancel"), signal: options.signal });
291
+ }
216
292
  }
217
293
  exports.BasalClient = BasalClient;
@@ -1,7 +1,13 @@
1
1
  import { type QuestionSet, type TypedDecisionResponse, type DecisionOptions } from "./questions.cjs";
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";
2
4
  export * from "./questions.cjs";
3
5
  export * from "./media.cjs";
4
6
  export * from "./tasks.cjs";
7
+ export * from "./errors.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";
5
11
  import type { TaskAnswer } from "./tasks.cjs";
6
12
  /** Native Basal wire types. Criterion order is significant; do not sort keys. */
7
13
  export type JsonValue = string | number | boolean | null | JsonValue[] | {
@@ -164,21 +170,6 @@ export interface ModelMetadata {
164
170
  export interface ModelsResponse {
165
171
  models: ModelMetadata[];
166
172
  }
167
- export declare class BasalError extends Error {
168
- }
169
- /** Non-2xx response. Server body and Retry-After are available without logging them. */
170
- export declare class BasalHTTPError extends BasalError {
171
- readonly statusCode: number;
172
- readonly body: unknown;
173
- readonly retryAfter: string | null;
174
- constructor(statusCode: number, body: unknown, retryAfter: string | null);
175
- }
176
- export declare class BasalTransportError extends BasalError {
177
- }
178
- export declare class BasalProtocolError extends BasalError {
179
- }
180
- export declare class BasalResponseTooLargeError extends BasalError {
181
- }
182
173
  /** Web Fetch input accepted by browsers and server runtimes. */
183
174
  export type RequestInput = string | URL | Request;
184
175
  /** A transport adapter must honor signal/redirect and return a standard Web Response. */
@@ -200,9 +191,26 @@ export declare class BasalClient {
200
191
  private readonly timeoutMs;
201
192
  private readonly maxResponseBytes;
202
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;
203
198
  constructor(options?: BasalClientOptions);
204
199
  private request;
200
+ private call;
205
201
  decide(request: DecisionRequest, signal?: AbortSignal): Promise<DecisionResponse>;
206
202
  decide<const Q extends QuestionSet>(state: JsonValue, questions: Q, options?: DecisionOptions): Promise<TypedDecisionResponse<Q>>;
207
203
  models(signal?: AbortSignal): Promise<ModelsResponse>;
204
+ /** Upload a JSONL input file (`purpose=batch`) from caller-owned bytes, a Blob or a stream; never fetches URLs. */
205
+ uploadFile(request: UploadFileRequest, options?: TransferOptions): Promise<FileObject>;
206
+ listFiles(options?: ListFilesOptions): Promise<FileList>;
207
+ getFile(fileId: string, options?: RequestOptions): Promise<FileObject>;
208
+ deleteFile(fileId: string, options?: RequestOptions): Promise<DeletedFile>;
209
+ /** Raw file bytes (JSONL), buffered up to `maxBytes` (default `maxResponseBytes`); never JSON-parsed. */
210
+ downloadFile(fileId: string, options?: DownloadOptions): Promise<Uint8Array>;
211
+ createBatch(request: CreateBatchRequest, options?: CreateBatchOptions): Promise<Batch>;
212
+ listBatches(options?: ListOptions): Promise<BatchList>;
213
+ getBatch(batchId: string, options?: RequestOptions): Promise<Batch>;
214
+ /** Request cancellation; the batch moves to `cancelling` and later `cancelled`. Does not wait. */
215
+ cancelBatch(batchId: string, options?: RequestOptions): Promise<Batch>;
208
216
  }