nuabase 1.1.0 → 2.0.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.
@@ -1,4 +1,78 @@
1
+ import { NuaLlmClient, wrapArraySchema } from 'nua-llm-core';
1
2
  import { z } from 'zod';
3
+ export { z } from 'zod';
4
+
5
+ const normalizedUsageZero = {
6
+ promptTokens: 0,
7
+ completionTokens: 0,
8
+ totalTokens: 0
9
+ };
10
+ class DirectBackend {
11
+ constructor(config) {
12
+ if (!config.model) {
13
+ throw new Error("model is required for direct mode");
14
+ }
15
+ this.model = config.model;
16
+ this.client = new NuaLlmClient({ providers: config.providers });
17
+ }
18
+ async castValue(params) {
19
+ const startTime = Date.now();
20
+ const result = await this.client.castValue({
21
+ model: this.model,
22
+ input: { prompt: params.prompt, data: params.data },
23
+ output: { name: params.outputName, effectiveSchema: params.outputSchema }
24
+ });
25
+ const latencyMs = Date.now() - startTime;
26
+ if (!result.success) {
27
+ return {
28
+ success: false,
29
+ error: result.error || "Unknown error",
30
+ source: "direct",
31
+ latencyMs
32
+ };
33
+ }
34
+ return {
35
+ success: true,
36
+ data: result.data,
37
+ usage: result.usage || normalizedUsageZero,
38
+ model: this.model,
39
+ latencyMs,
40
+ source: "direct",
41
+ meta: {}
42
+ };
43
+ }
44
+ async castArray(params) {
45
+ const startTime = Date.now();
46
+ const wrappedSchema = wrapArraySchema(params.outputSchema, {
47
+ primaryKey: params.primaryKey,
48
+ outputName: params.outputName
49
+ });
50
+ const result = await this.client.castArray({
51
+ model: this.model,
52
+ data: params.data,
53
+ input: { prompt: params.prompt, primaryKey: params.primaryKey },
54
+ output: { name: params.outputName, effectiveSchema: wrappedSchema }
55
+ });
56
+ const latencyMs = Date.now() - startTime;
57
+ if (!result.success) {
58
+ return {
59
+ success: false,
60
+ error: result.error || "Unknown error",
61
+ source: "direct",
62
+ latencyMs
63
+ };
64
+ }
65
+ return {
66
+ success: true,
67
+ data: result.data,
68
+ usage: result.usage || normalizedUsageZero,
69
+ model: this.model,
70
+ latencyMs,
71
+ source: "direct",
72
+ meta: {}
73
+ };
74
+ }
75
+ }
2
76
 
3
77
  function resolveConfigValue(config, key, envVar) {
4
78
  if (config[key]) return config[key];
@@ -10,6 +84,50 @@ function resolveConfigValue(config, key, envVar) {
10
84
  return void 0;
11
85
  }
12
86
 
87
+ const isBrowserEnvironment = () => typeof window !== "undefined" && !!window.document;
88
+ class AuthTokenManager {
89
+ constructor(config) {
90
+ this.apiKey = resolveConfigValue(config, "apiKey", "NUABASE_API_KEY") || void 0;
91
+ this.fetchToken = config.fetchToken;
92
+ if (this.apiKey && this.fetchToken) {
93
+ throw new Error("Provide either an apiKey or a fetchToken function, but not both.");
94
+ }
95
+ if (!this.apiKey && !this.fetchToken) {
96
+ throw new Error(
97
+ "Authentication is required. Provide config.apiKey/NUABASE_API_KEY or a fetchToken function."
98
+ );
99
+ }
100
+ if (this.apiKey && isBrowserEnvironment()) {
101
+ throw new Error(
102
+ "found config.apiKey. It is a private secret that must only be used in server environments."
103
+ );
104
+ }
105
+ }
106
+ async getToken() {
107
+ if (this.apiKey) {
108
+ return this.apiKey;
109
+ }
110
+ if (!this.fetchToken) {
111
+ throw new Error("Unable to resolve API token because no fetchToken function is configured.");
112
+ }
113
+ if (this.apiToken) {
114
+ return this.apiToken;
115
+ }
116
+ if (!this.pendingTokenPromise) {
117
+ this.pendingTokenPromise = this.fetchToken().then((token) => {
118
+ if (!token) {
119
+ throw new Error("fetchToken must resolve a non-empty API token.");
120
+ }
121
+ this.apiToken = token;
122
+ return token;
123
+ }).finally(() => {
124
+ this.pendingTokenPromise = void 0;
125
+ });
126
+ }
127
+ return this.pendingTokenPromise;
128
+ }
129
+ }
130
+
13
131
  async function parseErrorResponse(response, urlPath) {
14
132
  const fallbackMessage = `Request to ${urlPath} failed with status ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
15
133
  let responseBody = "";
@@ -38,9 +156,17 @@ function safeParseJson(payload) {
38
156
  }
39
157
  }
40
158
  function extractErrorMessage(body) {
41
- const e = body["error"];
42
- if (e && typeof e === "string") return e;
43
- return void 0;
159
+ const parts = [];
160
+ const error = body["error"];
161
+ if (typeof error === "string" && error.trim()) {
162
+ parts.push(error.trim());
163
+ }
164
+ const message = body["message"];
165
+ if (typeof message === "string" && message.trim()) {
166
+ parts.push(message.trim());
167
+ }
168
+ if (parts.length === 0) return void 0;
169
+ return parts.join(". ");
44
170
  }
45
171
 
46
172
  function isErrorWithMessage(error) {
@@ -53,398 +179,210 @@ function getErrorMessageFromException(error) {
53
179
  return String(error);
54
180
  }
55
181
 
56
- class NuabaseAPIClient {
57
- constructor(config = {}) {
58
- this.apiKey = resolveConfigValue(config, "apiKey", "NUABASE_API_KEY") || "";
182
+ function isErrorResponse(response) {
183
+ return Boolean(response && typeof response === "object" && "error" in response);
184
+ }
185
+ class GatewayBackend {
186
+ constructor(config) {
59
187
  this.baseUrl = resolveConfigValue(config, "baseUrl", "NUABASE_API_URL") || "https://api.nuabase.com";
60
- if (!this.apiKey) {
61
- throw new Error(
62
- "API key is required. Provide it via config.apiKey or NUABASE_API_KEY environment variable."
63
- );
188
+ this.authManager = new AuthTokenManager(config);
189
+ }
190
+ async castValue(params) {
191
+ const startTime = Date.now();
192
+ const response = await this.post("cast/value/now", {
193
+ input: { prompt: params.prompt, data: params.data },
194
+ output: { name: params.outputName, schema: params.outputSchema }
195
+ });
196
+ const latencyMs = Date.now() - startTime;
197
+ if (isErrorResponse(response)) {
198
+ return { success: false, error: response.error, source: "gateway", latencyMs };
199
+ }
200
+ const apiResponse = response;
201
+ const usage = {
202
+ promptTokens: apiResponse.llmUsage.promptTokens + apiResponse.cacheUsage.promptTokens,
203
+ completionTokens: apiResponse.llmUsage.completionTokens + apiResponse.cacheUsage.completionTokens,
204
+ totalTokens: apiResponse.llmUsage.totalTokens + apiResponse.cacheUsage.totalTokens
205
+ };
206
+ return {
207
+ success: true,
208
+ data: apiResponse.data,
209
+ usage,
210
+ model: apiResponse.model ?? "unknown",
211
+ latencyMs,
212
+ source: "gateway",
213
+ meta: {
214
+ requestId: apiResponse.llmRequestId,
215
+ cached: apiResponse.isCacheHit,
216
+ llmUsage: apiResponse.llmUsage,
217
+ cacheUsage: apiResponse.cacheUsage
218
+ }
219
+ };
220
+ }
221
+ async castArray(params) {
222
+ const startTime = Date.now();
223
+ const response = await this.post("cast/array/now", {
224
+ input: { prompt: params.prompt, data: params.data, primaryKey: params.primaryKey },
225
+ output: { name: params.outputName, schema: params.outputSchema }
226
+ });
227
+ const latencyMs = Date.now() - startTime;
228
+ if (isErrorResponse(response)) {
229
+ return { success: false, error: response.error, source: "gateway", latencyMs };
230
+ }
231
+ const apiResponse = response;
232
+ const usage = {
233
+ promptTokens: apiResponse.llmUsage.promptTokens + apiResponse.cacheUsage.promptTokens,
234
+ completionTokens: apiResponse.llmUsage.completionTokens + apiResponse.cacheUsage.completionTokens,
235
+ totalTokens: apiResponse.llmUsage.totalTokens + apiResponse.cacheUsage.totalTokens
236
+ };
237
+ return {
238
+ success: true,
239
+ data: apiResponse.data,
240
+ usage,
241
+ model: apiResponse.model ?? "unknown",
242
+ latencyMs,
243
+ source: "gateway",
244
+ meta: {
245
+ requestId: apiResponse.llmRequestId,
246
+ cached: apiResponse.cacheHits === apiResponse.data.length,
247
+ llmUsage: apiResponse.llmUsage,
248
+ cacheUsage: apiResponse.cacheUsage
249
+ }
250
+ };
251
+ }
252
+ async queueCastValue(params) {
253
+ const response = await this.post("cast/value", {
254
+ input: { prompt: params.prompt, data: params.data },
255
+ output: { name: params.outputName, schema: params.outputSchema }
256
+ });
257
+ if (isErrorResponse(response)) {
258
+ return { success: false, error: response.error, source: "gateway" };
64
259
  }
260
+ const apiResponse = response;
261
+ return { success: true, jobId: apiResponse.jobId, source: "gateway" };
65
262
  }
66
- async request(method, urlPath, params) {
67
- const url = `${this.baseUrl}/${urlPath}`;
263
+ async queueCastArray(params) {
264
+ const response = await this.post("cast/array", {
265
+ input: { prompt: params.prompt, data: params.data, primaryKey: params.primaryKey },
266
+ output: { name: params.outputName, schema: params.outputSchema }
267
+ });
268
+ if (isErrorResponse(response)) {
269
+ return { success: false, error: response.error, source: "gateway" };
270
+ }
271
+ const apiResponse = response;
272
+ return { success: true, jobId: apiResponse.jobId, source: "gateway" };
273
+ }
274
+ async post(path, body) {
275
+ const url = `${this.baseUrl}/${path}`;
68
276
  let response;
69
- const hasBody = method !== "GET" && params !== void 0;
70
277
  const headers = {
71
- Authorization: `Bearer ${this.apiKey}`
278
+ Authorization: `Bearer ${await this.authManager.getToken()}`,
279
+ "Content-Type": "application/json"
72
280
  };
73
- if (hasBody) {
74
- headers["Content-Type"] = "application/json";
75
- }
76
281
  try {
77
282
  response = await fetch(url, {
78
- method,
283
+ method: "POST",
79
284
  headers,
80
- body: hasBody ? JSON.stringify(params) : void 0
285
+ body: JSON.stringify(body)
81
286
  });
82
287
  } catch (e) {
83
288
  return { error: `Error calling Nuabase API: ${getErrorMessageFromException(e)}` };
84
289
  }
85
- let result;
86
290
  if (!response.ok) {
87
- return await parseErrorResponse(response, urlPath);
291
+ return await parseErrorResponse(response, path);
88
292
  }
89
293
  try {
90
- result = await response.json();
294
+ return await response.json();
91
295
  } catch {
92
296
  return { error: "Invalid response received from Nuabase API call, unable to parse" };
93
297
  }
94
- return result;
95
298
  }
96
299
  }
97
300
 
98
- const zs_NuaQueuedResponse = z.object({
99
- id: z.string(),
100
- sseUrl: z.string().min(1)
101
- }).strict();
102
-
103
- const validateArrayRequestParams = (data, primaryKeyName) => {
104
- if (!Array.isArray(data)) {
105
- throw new Error("`data` must be an array of objects.");
301
+ class Nua {
302
+ constructor(backend) {
303
+ this.backend = backend;
106
304
  }
107
- if (!primaryKeyName || typeof primaryKeyName !== "string") {
108
- throw new Error("`primaryKeyName` must be a non-empty string.");
305
+ static gateway(config) {
306
+ return new Nua(new GatewayBackend(config));
109
307
  }
110
- data.forEach((item, index) => {
111
- if (item === null || typeof item !== "object" || Array.isArray(item)) {
112
- throw new Error(`data[${index}] must be a non-null object.`);
113
- }
114
- if (!(primaryKeyName in item)) {
115
- throw new Error(`data[${index}] must contain property '${primaryKeyName}'.`);
116
- }
117
- });
118
- };
119
-
120
- const zs_ResponseRecord = (primaryKeyName, outputKey, outputSchema) => {
121
- const primaryKeySchema = z.any();
122
- const shape = {
123
- [primaryKeyName]: primaryKeySchema,
124
- [outputKey]: outputSchema
125
- };
126
- return z.object(shape).strict();
127
- };
128
- const createNuaApiResponseCastArray = (primaryKeyName, outputKey, outputSchema) => {
129
- const recordSchema = zs_ResponseRecord(
130
- primaryKeyName,
131
- outputKey,
132
- outputSchema
133
- );
134
- const dataSchema = z.array(recordSchema);
135
- return z.object({
136
- llmRequestId: z.string(),
137
- kind: z.literal("cast/array"),
138
- data: dataSchema,
139
- cacheHits: z.number(),
140
- rowsWithNoResults: z.array(z.string()),
141
- isSuccess: z.literal(true),
142
- isError: z.optional(z.literal(false))
143
- }).strict();
144
- };
145
- const zs_NuaApiResponse_CastArray = createNuaApiResponseCastArray;
146
-
147
- const zs_ArrayFnDef = z.object({
148
- prompt: z.string(),
149
- output: z.object({
150
- name: z.string(),
151
- schema: z.custom(
152
- (value) => value instanceof z.ZodType,
153
- "Expected a Zod schema"
154
- )
155
- })
156
- });
157
- const validateArrayFnDef = (fnDef) => {
158
- const parsed = zs_ArrayFnDef.safeParse(fnDef);
159
- if (!parsed.success) {
160
- const message = z.prettifyError(parsed.error);
161
- throw new TypeError(`Invalid array function definition: ${message}`);
308
+ static direct(config) {
309
+ return new Nua(new DirectBackend(config));
162
310
  }
163
- return parsed.data;
164
- };
165
-
166
- function addOriginalInputRows(inputRows, outputRows, primaryKeyName) {
167
- const lookup = /* @__PURE__ */ new Map();
168
- for (const row of inputRows) {
169
- lookup.set(row[primaryKeyName], row);
170
- }
171
- return outputRows.map((row) => {
172
- const primaryKeyValue = row[primaryKeyName];
173
- const sourceRow = lookup.get(primaryKeyValue);
174
- if (!sourceRow) {
175
- throw new Error(
176
- `Unable to locate source row for primary key "${String(primaryKeyValue)}" in cast array response.`
177
- );
311
+ // Implementation
312
+ async get(prompt, options) {
313
+ if (typeof prompt !== "string" || prompt.trim() === "") {
314
+ throw new TypeError("Prompt must be a non-empty string");
178
315
  }
179
- return {
180
- ...row,
181
- sourceRow
182
- };
183
- });
184
- }
185
- const toCastArrayApiRequest = (prompt, data, primaryKeyName, outputName, outputSchema) => ({
186
- input: {
187
- prompt,
188
- data,
189
- primaryKey: primaryKeyName
190
- },
191
- output: {
192
- schema: outputSchema,
193
- name: outputName
316
+ const outputSchema = options?.output?.schema ?? z.string();
317
+ const outputName = options?.output?.name ?? "result";
318
+ const jsonSchema = z.toJSONSchema(outputSchema);
319
+ return this.backend.castValue({
320
+ prompt,
321
+ data: options?.input ?? null,
322
+ outputName,
323
+ outputSchema: jsonSchema
324
+ });
194
325
  }
195
- });
196
- const createArrayFn = (client, inputFnDef) => {
197
- const fnDef = validateArrayFnDef(inputFnDef);
198
- const outputJsonSchema = z.toJSONSchema(fnDef.output.schema);
199
- const toNuabaseError = (response) => {
200
- if (response && typeof response === "object" && "error" in response)
201
- return { error: String(response.error), isError: true };
202
- return void 0;
203
- };
204
- const baseFn = async (data, primaryKeyName) => {
205
- validateArrayRequestParams(data, primaryKeyName);
206
- const response = await client.request(
207
- "POST",
208
- "cast/array",
209
- toCastArrayApiRequest(
210
- fnDef.prompt,
211
- data,
212
- primaryKeyName,
213
- fnDef.output.name,
214
- outputJsonSchema
215
- )
216
- );
217
- const error = toNuabaseError(response);
218
- if (error) return error;
219
- const parsedResponse = zs_NuaQueuedResponse.safeParse(response);
220
- if (!parsedResponse.success) {
221
- const emsg = z.prettifyError(parsedResponse.error);
222
- return { error: `Invalid queued response received from Nuabase API: ${emsg}`, isError: true };
326
+ // ========== list() - Array Operations ==========
327
+ async list(prompt, options) {
328
+ if (typeof prompt !== "string" || prompt.trim() === "") {
329
+ throw new TypeError("Prompt must be a non-empty string");
223
330
  }
224
- return parsedResponse.data;
225
- };
226
- const nowFn = async (data, primaryKeyName) => {
227
- validateArrayRequestParams(data, primaryKeyName);
228
- const response = await client.request(
229
- "POST",
230
- "cast/array/now",
231
- toCastArrayApiRequest(
232
- fnDef.prompt,
233
- data,
234
- primaryKeyName,
235
- fnDef.output.name,
236
- outputJsonSchema
237
- )
238
- );
239
- const error = toNuabaseError(response);
240
- if (error) return error;
241
- const outputKey = fnDef.output.name;
242
- const successSchema = zs_NuaApiResponse_CastArray(primaryKeyName, outputKey, fnDef.output.schema);
243
- const parsedResponse = successSchema.safeParse(response);
244
- if (!parsedResponse.success) {
245
- const emsg = z.prettifyError(parsedResponse.error);
246
- return { error: `Invalid data received from Nuabase API: ${emsg}`, isError: true };
331
+ if (!Array.isArray(options.input)) {
332
+ throw new TypeError("Input must be an array for list()");
247
333
  }
248
- return {
249
- isSuccess: true,
250
- llmRequestId: parsedResponse.data.llmRequestId,
251
- kind: parsedResponse.data.kind,
252
- data: addOriginalInputRows(
253
- data,
254
- parsedResponse.data.data,
255
- primaryKeyName
256
- ),
257
- rowsWithNoResults: parsedResponse.data.rowsWithNoResults,
258
- cacheHits: parsedResponse.data.cacheHits
259
- };
260
- };
261
- return Object.assign(baseFn, {
262
- now: nowFn
263
- });
264
- };
265
-
266
- const createNuaApiResponseCastValue = (outputKey, outputSchema) => {
267
- return z.object({
268
- llmRequestId: z.string(),
269
- kind: z.literal("cast/value"),
270
- data: outputSchema,
271
- isCacheHit: z.boolean(),
272
- isSuccess: z.literal(true),
273
- isError: z.optional(z.literal(false))
274
- }).strict();
275
- };
276
- const zs_NuaApiResponse_CastValue = createNuaApiResponseCastValue;
277
-
278
- const zs_ValueFnDef = z.object({
279
- prompt: z.string(),
280
- output: z.object({
281
- name: z.string(),
282
- schema: z.custom(
283
- (value) => value instanceof z.ZodType,
284
- "Expected a Zod schema for `output.schema`"
285
- )
286
- })
287
- });
288
- const validateValueFnDef = (fnDef) => {
289
- const parsed = zs_ValueFnDef.safeParse(fnDef);
290
- if (!parsed.success) {
291
- const message = z.prettifyError(parsed.error);
292
- throw new TypeError(`Invalid value function definition: ${message}`);
334
+ if (typeof options.primaryKey !== "string" || options.primaryKey.trim() === "") {
335
+ throw new TypeError("primaryKey must be a non-empty string");
336
+ }
337
+ const jsonSchema = z.toJSONSchema(options.output.schema);
338
+ return this.backend.castArray({
339
+ prompt,
340
+ data: options.input,
341
+ primaryKey: options.primaryKey,
342
+ outputName: options.output.name,
343
+ outputSchema: jsonSchema
344
+ });
293
345
  }
294
- return parsed.data;
295
- };
296
-
297
- const toCastValueApiRequest = (prompt, data, outputName, outputSchema) => ({
298
- input: {
299
- prompt,
300
- data
301
- },
302
- output: {
303
- schema: outputSchema,
304
- name: outputName
346
+ // Implementation
347
+ async queueGet(prompt, options) {
348
+ if (typeof prompt !== "string" || prompt.trim() === "") {
349
+ throw new TypeError("Prompt must be a non-empty string");
350
+ }
351
+ if (!this.backend.queueCastValue) {
352
+ throw new Error("Queue operations are only supported in gateway mode");
353
+ }
354
+ const outputSchema = options?.output?.schema ?? z.string();
355
+ const outputName = options?.output?.name ?? "result";
356
+ const jsonSchema = z.toJSONSchema(outputSchema);
357
+ return this.backend.queueCastValue({
358
+ prompt,
359
+ data: options?.input ?? null,
360
+ outputName,
361
+ outputSchema: jsonSchema
362
+ });
305
363
  }
306
- });
307
- const createValueFn = (client, inputFnDef) => {
308
- const fnDef = validateValueFnDef(inputFnDef);
309
- const outputJsonSchema = z.toJSONSchema(fnDef.output.schema);
310
- const toNuabaseError = (response) => {
311
- if (response && typeof response === "object" && "error" in response)
312
- return { error: String(response.error), isError: true };
313
- return void 0;
314
- };
315
- const sendRequest = async (path, data) => client.request(
316
- "POST",
317
- path,
318
- toCastValueApiRequest(fnDef.prompt, data, fnDef.output.name, outputJsonSchema)
319
- );
320
- const baseFn = async (data) => {
321
- const response = await sendRequest("cast/value", data);
322
- const error = toNuabaseError(response);
323
- if (error) return error;
324
- const parsedResponse = zs_NuaQueuedResponse.safeParse(response);
325
- if (!parsedResponse.success) {
326
- const emsg = z.prettifyError(parsedResponse.error);
327
- return { error: `Invalid queued response received from Nuabase API: ${emsg}`, isError: true };
364
+ // ========== queueList() - Async Array Operations ==========
365
+ async queueList(prompt, options) {
366
+ if (typeof prompt !== "string" || prompt.trim() === "") {
367
+ throw new TypeError("Prompt must be a non-empty string");
328
368
  }
329
- return parsedResponse.data;
330
- };
331
- const nowFn = async (data) => {
332
- const response = await sendRequest("cast/value/now", data);
333
- const error = toNuabaseError(response);
334
- if (error) return error;
335
- const outputKey = fnDef.output.name;
336
- const successSchema = zs_NuaApiResponse_CastValue(
337
- outputKey,
338
- fnDef.output.schema
339
- );
340
- const parsedResponse = successSchema.safeParse(response);
341
- if (!parsedResponse.success) {
342
- const emsg = z.prettifyError(parsedResponse.error);
343
- return { error: `Invalid data received from Nuabase API: ${emsg}`, isError: true };
369
+ if (!this.backend.queueCastArray) {
370
+ throw new Error("Queue operations are only supported in gateway mode");
344
371
  }
345
- return {
346
- isSuccess: true,
347
- llmRequestId: parsedResponse.data.llmRequestId,
348
- kind: parsedResponse.data.kind,
349
- data: parsedResponse.data.data,
350
- isCacheHit: parsedResponse.data.isCacheHit
351
- };
352
- };
353
- return Object.assign(baseFn, {
354
- now: nowFn
355
- });
356
- };
357
-
358
- const errorParseFailed = {
359
- kind: "internal-error",
360
- message: "Unable to parse stored LLM result"
361
- };
362
- const dateFromIso = z.preprocess(
363
- (value) => {
364
- if (value == null) return null;
365
- if (value instanceof Date) return value;
366
- if (typeof value === "string") {
367
- const parsed = new Date(value);
368
- if (!Number.isNaN(parsed.getTime())) return parsed;
372
+ if (!Array.isArray(options.input)) {
373
+ throw new TypeError("Input must be an array for queueList()");
369
374
  }
370
- return z.NEVER;
371
- },
372
- z.union([z.date(), z.null()])
373
- );
374
- const mandatoryDateFromIso = z.preprocess((value) => {
375
- if (value instanceof Date) return value;
376
- if (typeof value === "string") {
377
- const parsed = new Date(value);
378
- if (!Number.isNaN(parsed.getTime())) return parsed;
379
- }
380
- return z.NEVER;
381
- }, z.date());
382
- const apiResponseSchema = z.object({
383
- id: z.string(),
384
- requestType: z.string(),
385
- llmStatus: z.union([
386
- z.literal("pending"),
387
- z.literal("processing"),
388
- z.literal("success"),
389
- z.literal("failed")
390
- ]),
391
- sseStatus: z.union([
392
- z.literal("n/a"),
393
- z.literal("pending"),
394
- z.literal("sent"),
395
- z.literal("failed")
396
- ]),
397
- webhookStatus: z.union([
398
- z.literal("n/a"),
399
- z.literal("pending"),
400
- z.literal("sent"),
401
- z.literal("failed")
402
- ]),
403
- input: z.object({
404
- prompt: z.union([z.string(), z.null()]),
405
- data: z.union([z.string(), z.null()]),
406
- primaryKey: z.union([z.string(), z.null()])
407
- }),
408
- output: z.object({
409
- name: z.string(),
410
- schema: z.string(),
411
- effectiveSchema: z.string()
412
- }),
413
- result: z.union([z.record(z.string(), z.unknown()), z.null()]).optional(),
414
- error: z.union([z.string(), z.null()]),
415
- fullPrompt: z.string(),
416
- model: z.string(),
417
- provider: z.string(),
418
- startedAt: dateFromIso,
419
- finishedAt: dateFromIso,
420
- createdAt: mandatoryDateFromIso,
421
- updatedAt: mandatoryDateFromIso
422
- });
423
- const isNuabaseError = (value) => Boolean(value && typeof value === "object" && "isError" in value && value.isError);
424
- async function getRequest(client, llmRequestId) {
425
- const response = await client.request("GET", `requests/${encodeURIComponent(llmRequestId)}`);
426
- if (isNuabaseError(response)) {
427
- return response;
428
- }
429
- const parsedResponse = apiResponseSchema.safeParse(response);
430
- if (!parsedResponse.success) {
431
- return errorParseFailed;
432
- }
433
- return parsedResponse.data;
434
- }
435
-
436
- class Nua {
437
- constructor(config) {
438
- this.apiClient = new NuabaseAPIClient(config);
439
- }
440
- createArrayFn(fnDef) {
441
- return createArrayFn(this.apiClient, fnDef);
442
- }
443
- createFn(fnDef) {
444
- return createValueFn(this.apiClient, fnDef);
445
- }
446
- async getRequest(llmRequestId) {
447
- return getRequest(this.apiClient, llmRequestId);
375
+ if (typeof options.primaryKey !== "string" || options.primaryKey.trim() === "") {
376
+ throw new TypeError("primaryKey must be a non-empty string");
377
+ }
378
+ const jsonSchema = z.toJSONSchema(options.output.schema);
379
+ return this.backend.queueCastArray({
380
+ prompt,
381
+ data: options.input,
382
+ primaryKey: options.primaryKey,
383
+ outputName: options.output.name,
384
+ outputSchema: jsonSchema
385
+ });
448
386
  }
449
387
  }
450
388