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 CHANGED
@@ -31,24 +31,23 @@ const LeadInsights = z.object({
31
31
  });
32
32
  ```
33
33
 
34
- **3. Declare the prompt.** Turn it into a typed function:
34
+ **3. Call the API.** Use `list()` for array operations:
35
35
 
36
36
  ```ts
37
- const classifyLeads = new Nua().createArrayFn({
38
- prompt: 'Classify each lead with industry and company_size bucket.',
39
- output: {
40
- name: 'leadInsights',
41
- schema: LeadInsights,
42
- },
37
+ const nua = Nua.gateway({ apiKey: 'YOUR_API_KEY' });
38
+
39
+ const result = await nua.list('Classify each lead with industry and company_size bucket.', {
40
+ input: leads,
41
+ primaryKey: 'id',
42
+ output: { name: 'leadInsights', schema: LeadInsights },
43
43
  });
44
44
  ```
45
45
 
46
- **4. Invoke.** Call it like any other async function:
46
+ **4. Use the result.** Check for success and access typed data:
47
47
 
48
48
  ```ts
49
- const result = await classifyLeads.now(leads, 'id');
50
- if (result.isError) throw new Error(result.error);
51
- console.log(result.data[0].insights);
49
+ if (!result.success) throw new Error(result.error);
50
+ console.log(result.data[0].leadInsights);
52
51
  // -> { industry: 'Software', company_size: 'Mid-market' }
53
52
  ```
54
53
 
@@ -62,7 +61,7 @@ npm install nuabase zod
62
61
 
63
62
  2. Get your API key from the [Nuabase Console](https://console.nuabase.com/dashboard/api-keys/new).
64
63
 
65
- 3. Set `NUABASE_API_KEY` environment variable, or pass it directly in `new Nua({apiKey: "KEY"})`):
64
+ 3. Set `NUABASE_API_KEY` environment variable, or pass it directly in `Nua.gateway({ apiKey: "KEY" })`:
66
65
 
67
66
  ## Lead Enrichment Example
68
67
 
@@ -70,7 +69,7 @@ npm install nuabase zod
70
69
  import { Nua } from 'nuabase';
71
70
  import { z } from 'zod';
72
71
 
73
- const nua = new Nua({ apiKey: 'API-KEY' });
72
+ const nua = Nua.gateway({ apiKey: 'API-KEY' });
74
73
 
75
74
  const LeadInsights = z.object({
76
75
  company_name: z.string(),
@@ -79,15 +78,6 @@ const LeadInsights = z.object({
79
78
  recommended_follow_up: z.enum(['Call', 'Email', 'Event']),
80
79
  });
81
80
 
82
- const enrichLeads = nua.createArrayFn({
83
- prompt:
84
- 'Summarize each inbound lead by extracting company_name, industry, company_size bucket (SMB, Mid-market, Enterprise), and the recommended_follow_up channel (Call, Email, or Event) based on their notes.',
85
- output: {
86
- name: 'leadInsights',
87
- schema: LeadInsights,
88
- },
89
- });
90
-
91
81
  const rows = [
92
82
  {
93
83
  leadId: 'lead-101',
@@ -107,22 +97,29 @@ const rows = [
107
97
  },
108
98
  ];
109
99
 
110
- const response = await enrichLeads.now(rows, 'leadId'); // `leadId` is the primary key field
100
+ const response = await nua.list(
101
+ 'Summarize each inbound lead by extracting company_name, industry, company_size bucket (SMB, Mid-market, Enterprise), and the recommended_follow_up channel (Call, Email, or Event) based on their notes.',
102
+ {
103
+ input: rows,
104
+ primaryKey: 'leadId',
105
+ output: { name: 'leadInsights', schema: LeadInsights },
106
+ }
107
+ );
111
108
 
112
- if (response.isError) {
109
+ if (!response.success) {
113
110
  console.error(response.error);
114
111
  return;
115
112
  }
116
113
 
117
- response.data.forEach(({ id, leadInsights }) => {
114
+ response.data.forEach(({ leadId, leadInsights }) => {
118
115
  // leadInsights satisfies the LeadInsights schema
119
- console.log(id, leadInsights.company_name, leadInsights.industry, leadInsights.company_size);
116
+ console.log(leadId, leadInsights.company_name, leadInsights.industry, leadInsights.company_size);
120
117
  });
121
118
 
122
119
  console.log(response.data);
123
120
  // -> [
124
121
  // {
125
- // id: 'lead-101',
122
+ // leadId: 'lead-101',
126
123
  // leadInsights: {
127
124
  // company_name: 'Acme Analytics',
128
125
  // industry: 'Software',
@@ -134,7 +131,7 @@ console.log(response.data);
134
131
  // ];
135
132
  ```
136
133
 
137
- `map(data, primaryKey)` submits an asynchronous mapping job. But `map.now(data, primaryKey)` is immediate — it waits for completion and returns the full result.
134
+ The default invocation waits for completion and returns the full result. Use `nua.queueList()` to submit an asynchronous job and receive streaming updates via SSE.
138
135
 
139
136
  ## Why Nuabase
140
137
 
@@ -145,55 +142,103 @@ console.log(response.data);
145
142
 
146
143
  ## API Response
147
144
 
148
- Every call returns a discriminated union. When `isError` is `true`, you get a flat error object. Otherwise `isSuccess` is `true`, and `data` contains rows merged with your typed output—along with metadata for observability and caching.
145
+ Every call returns a discriminated union. When `success` is `false`, you get an error object. Otherwise `success` is `true`, and `data` contains your typed output along with metadata.
149
146
 
150
147
  **Success**
151
148
 
152
- | Field | Type | Description |
153
- | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
154
- | `isSuccess` | `true` | Indicates that the request completed successfully. |
155
- | `data` | `Array<{ [primaryKey]: unknown; [outputName]: z.infer<typeof output> }>` | Rows that merged the original primary key with the validated schema output. |
156
- | `llmRequestId` | `string` | Unique identifier for tracing each Nuabase LLM execution. |
157
- | `cacheHits` | `number` | Count of input rows served from Nuabase response cache. |
158
- | `rowsWithNoResults` | `string[]` | Primary keys that could not be resolved by the model. |
159
- | `isError` | `false \| undefined` | Absent on success; included for type narrowing. |
149
+ | Field | Type | Description |
150
+ | ----------- | --------------------------------------------------------- | ------------------------------------------------------- |
151
+ | `success` | `true` | Indicates that the request completed successfully. |
152
+ | `data` | `T` (for `get`) or `Array<{ [pk]: value; [output]: T }>` (for `list`) | The typed result matching your schema. |
153
+ | `usage` | `{ promptTokens, completionTokens, totalTokens }` | Token usage statistics for the LLM request. |
154
+ | `model` | `string` | The LLM model used for this request. |
155
+ | `latencyMs` | `number` | Request latency in milliseconds. |
156
+ | `source` | `'gateway'` \| `'direct'` | Which backend processed the request. |
157
+ | `meta` | `object` | Additional metadata (varies by source). |
158
+
159
+ **Gateway-specific metadata** (`meta` when `source` is `'gateway'`):
160
+
161
+ | Field | Type | Description |
162
+ | ------------ | --------- | ---------------------------------------------- |
163
+ | `requestId` | `string` | Unique identifier for tracing. |
164
+ | `cached` | `boolean` | Whether the result was served from cache. |
165
+ | `llmUsage` | `object` | Token usage from LLM calls. |
166
+ | `cacheUsage` | `object` | Token usage served from cache. |
160
167
 
161
168
  **Error**
162
169
 
163
- | Field | Type | Description |
164
- | --------- | -------- | -------------------------------------------------------- |
165
- | `isError` | `true` | Indicates the request failed. |
166
- | `error` | `string` | Message describing the error returned by the API or SDK. |
170
+ | Field | Type | Description |
171
+ | ----------- | ----------------------------- | -------------------------------------------------------- |
172
+ | `success` | `false` | Indicates the request failed. |
173
+ | `error` | `string` | Message describing the error. |
174
+ | `source` | `'gateway'` \| `'direct'` | Which backend returned the error. |
175
+ | `latencyMs` | `number` | Time until failure in milliseconds. |
167
176
 
168
177
  ## SDK API
169
178
 
170
- **`new Nua(config?)`**
171
- Creates a client bound to your Nuabase account. Provide:
179
+ ### Constructors
180
+
181
+ **`Nua.gateway(config?)`**
182
+ Creates a client that connects to the Nuabase API gateway. Use this for production deployments with caching, request tracking, and async job support.
172
183
 
173
184
  - `apiKey?: string` – API key for authentication. Defaults to `process.env.NUABASE_API_KEY`.
174
185
  - `baseUrl?: string` – Override the API host. Defaults to `https://api.nuabase.com`.
175
186
 
176
- **`nua.map({ name, prompt, output })`**
177
- Declares a typed mapping function backed by Nuabase. Parameters:
187
+ **`Nua.direct(config)`**
188
+ Creates a client that calls LLM providers directly (in-process). Use this for serverless, edge functions, or CLI tools where you don't need the gateway infrastructure.
189
+
190
+ - `model: string` – The model to use (e.g., `'gpt-4o-mini'`).
191
+ - `providers: { openai?: { apiKey: string }, ... }` – Provider credentials.
192
+
193
+ ### Methods
194
+
195
+ **`nua.get(prompt)`**
196
+ Returns a simple string response from the LLM.
197
+
198
+ ```ts
199
+ const result = await nua.get("Tell me a joke");
200
+ if (result.success) console.log(result.data); // string
201
+ ```
202
+
203
+ **`nua.get(prompt, options)`**
204
+ Returns a typed single value. Parameters:
178
205
 
179
- - `name: string` – Label applied to the enriched payload in each response row (e.g., `result.data[i][name]`).
180
206
  - `prompt: string` – Natural-language instructions sent to the LLM.
181
- - `output: ZodSchema` – Zod schema describing the output shape. Nuabase stores the JSON Schema twin and validates responses against it before returning.
207
+ - `options.input?: unknown` – Optional input data to include in the prompt.
208
+ - `options.output: { name: string; schema: ZodSchema }` – Output name and Zod schema.
182
209
 
183
- Returns a callable object (the mapper) with two entry points:
210
+ ```ts
211
+ const result = await nua.get("Extract the address", {
212
+ input: "123 Main St, Springfield, IL 62701",
213
+ output: { name: 'address', schema: AddressSchema },
214
+ });
215
+ if (result.success) console.log(result.data); // typed as z.infer<typeof AddressSchema>
216
+ ```
184
217
 
185
- - `mapper(data, primaryKey)` – Submits the job asynchronously and returns immediately with metadata and eventual results.
186
- - `mapper.now(data, primaryKey)` – Runs the job and waits until the full enriched result set is ready.
218
+ **`nua.list(prompt, options)`**
219
+ Processes an array of items. Parameters:
187
220
 
188
- Both entry points expect:
221
+ - `prompt: string` – Natural-language instructions for each item.
222
+ - `options.input: Array<Record<string, unknown>>` – Rows to process.
223
+ - `options.primaryKey: string` – Field that uniquely identifies each row.
224
+ - `options.output: { name: string; schema: ZodSchema }` – Output configuration.
189
225
 
190
- - `data: Array<Record<string, unknown>>` – Rows you want Nuabase to enrich. Each row must include the primary key.
191
- - `primaryKey: string` – Field name that uniquely identifies each row within `data`. The SDK throws if the field is missing on any item.
226
+ ```ts
227
+ const result = await nua.list("Classify each lead", {
228
+ input: leads,
229
+ primaryKey: 'id',
230
+ output: { name: 'classification', schema: ClassificationSchema },
231
+ });
232
+ if (result.success) {
233
+ result.data.forEach(row => console.log(row.id, row.classification));
234
+ }
235
+ ```
192
236
 
193
- Both entry points resolve to either:
237
+ **`nua.queueGet(prompt, options?)`** *(Gateway mode only)*
238
+ Submits an async job for single-value operations. Returns `{ success: true, jobId }`.
194
239
 
195
- - **Success** – `{ isSuccess: true, data, llmRequestId, cacheHits, rowsWithNoResults }`.
196
- - **Error** – `{ isError: true, error }`.
240
+ **`nua.queueList(prompt, options)`** *(Gateway mode only)*
241
+ Submits an async job for array operations. Returns `{ success: true, jobId }`.
197
242
 
198
243
  ## Next Steps
199
244
 
@@ -204,6 +249,10 @@ Both entry points resolve to either:
204
249
 
205
250
  Email us at [hello@nuabase.com](mailto:hello@nuabase.com). On X at [@NuabaseHQ](x.com/NuabaseHQ).
206
251
 
252
+ ## Tests
253
+
254
+ See [TESTING.md](TESTING.md)
255
+
207
256
  ## Credits
208
257
 
209
258
  The template for this package comes from https://github.com/rtivital/ts-package-template