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