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