nuabase 1.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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # Nuabase TypeScript client
2
+
3
+ Nuabase turns LLM prompts into type-safe functions in under five lines.
4
+
5
+ Example use-cases:
6
+ * Enrich a list of food items with nutrition facts
7
+ * Tag sales leads with more details about the company
8
+ * Convert free-form instructions into precise order forms—directly inside your application.
9
+
10
+ You can describe the transformation once, and get back a well-typed function, and call it like any other code in your application.
11
+
12
+ You don't have to do any custom custom orchestration, or run polling, or schema validation.
13
+
14
+ Behind the scenes, Nuabase runs the async jobs, SSE streaming, webhooks, logging, caching, cost attribution, and strict JSON-schema enforcement. You also get an observability dashboard for every request so you always know what the LLM produced.
15
+
16
+ ## At a Glance
17
+
18
+ **1. Input.** Start with the data you want to send to the LLM:
19
+
20
+ ```ts
21
+ const leads = [
22
+ { id: 'lead-101', notes: 'Growth-stage SaaS, ~80 employees, wants a demo.' },
23
+ ];
24
+ ```
25
+
26
+ **2. Desired shape.** Describe the structure you expect back:
27
+
28
+ ```ts
29
+ const LeadInsights = z.object({
30
+ industry: z.string(),
31
+ company_size: z.enum(['SMB', 'Mid-market', 'Enterprise']),
32
+ });
33
+ ```
34
+
35
+ **3. Declare the prompt.** Turn it into a typed function:
36
+
37
+ ```ts
38
+ const classifyLeads = new Nua().map({
39
+ name: 'insights',
40
+ output: LeadInsights,
41
+ prompt: 'Classify each lead with industry and company_size bucket.',
42
+ });
43
+ ```
44
+
45
+ **4. Invoke.** Call it like any other async function:
46
+
47
+ ```ts
48
+ const result = await classifyLeads.now(leads, 'id');
49
+ if (result.isError) throw new Error(result.error);
50
+ console.log(result.data[0].insights);
51
+ // -> { industry: 'Software', company_size: 'Mid-market' }
52
+ ```
53
+
54
+ ## Quick Start
55
+
56
+ 1. Add the Nuabase SDK along with Zod:
57
+
58
+ ```bash
59
+ npm install nuabase zod
60
+ ```
61
+
62
+ 2. Get your API key from the [Nuabase Console](https://console.nuabase.com/dashboard/api-keys/new).
63
+
64
+ 3. Set `NUABASE_API_KEY` environment variable, or pass it directly in `new Nua({apiKey: "KEY"})`):
65
+
66
+ ## Lead Enrichment Example
67
+
68
+ ```ts
69
+ import { Nua } from 'nuabase';
70
+ import { z } from 'zod';
71
+
72
+ const nua = new Nua({ apiKey: 'API-KEY' });
73
+
74
+ const LeadInsights = z.object({
75
+ company_name: z.string(),
76
+ industry: z.string(),
77
+ company_size: z.enum(['SMB', 'Mid-market', 'Enterprise']),
78
+ recommended_follow_up: z.enum(['Call', 'Email', 'Event']),
79
+ });
80
+
81
+ const enrichLeads = nua.map({
82
+ name: 'leadInsights',
83
+ output: LeadInsights,
84
+ prompt:
85
+ '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.',
86
+ });
87
+
88
+ const rows = [
89
+ {
90
+ leadId: 'lead-101',
91
+ name: 'Acme Analytics',
92
+ notes: 'Signed up after webinar, growth-stage SaaS, 80 employees. Wants a live demo next week.',
93
+ },
94
+ {
95
+ leadId: 'lead-102',
96
+ name: 'Bright Logistics',
97
+ notes: 'Regional freight operator asking for pricing via email. 12 depots across the Midwest.',
98
+ },
99
+ {
100
+ leadId: 'lead-103',
101
+ name: 'Nimbus Retail',
102
+ notes:
103
+ 'Enterprise retailer. Mentioned they will send the procurement team to our booth at NRF.',
104
+ },
105
+ ];
106
+
107
+ const response = await enrichLeads.now(rows, 'leadId'); // `leadId` is the primary key field
108
+
109
+ if (response.isError) {
110
+ console.error(response.error);
111
+ return;
112
+ }
113
+
114
+ response.data.forEach(({ id, leadInsights }) => {
115
+ // leadInsights satisfies the LeadInsights schema
116
+ console.log(id, leadInsights.company_name, leadInsights.industry, leadInsights.company_size);
117
+ });
118
+
119
+ console.log(response.data);
120
+ // -> [
121
+ // {
122
+ // id: 'lead-101',
123
+ // leadInsights: {
124
+ // company_name: 'Acme Analytics',
125
+ // industry: 'Software',
126
+ // company_size: 'Mid-market',
127
+ // recommended_follow_up: 'Call',
128
+ // },
129
+ // },
130
+ // // ...
131
+ // ];
132
+ ```
133
+
134
+ `map(data, primaryKey)` submits an asynchronous mapping job. But `map.now(data, primaryKey)` is immediate — it waits for completion and returns the full result.
135
+
136
+ ## Why Nuabase
137
+
138
+ - Type-safe from prompt to runtime: Zod schemas compile to JSON Schema, and the SDK re-validates every response before you see it.
139
+ - Zero glue code: Nuabase runs the queueing, retries, webhooks, SSE streaming, and polling so your application code stays clean.
140
+ - Built-in performance: granular caching, cost attribution, and usage metrics come for free on every request.
141
+ - Production visibility: every run shows up in the Nuabase dashboard with logs, prompt/response history, and tracing ids.
142
+
143
+ ## API Response
144
+
145
+ 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.
146
+
147
+ **Success**
148
+
149
+ | Field | Type | Description |
150
+ | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
151
+ | `isSuccess` | `true` | Indicates that the request completed successfully. |
152
+ | `data` | `Array<{ [primaryKey]: unknown; [outputName]: z.infer<typeof output> }>` | Rows that merged the original primary key with the validated schema output. |
153
+ | `llmRequestId` | `string` | Unique identifier for tracing each Nuabase LLM execution. |
154
+ | `cacheHits` | `number` | Count of input rows served from Nuabase response cache. |
155
+ | `rowsWithNoResults` | `string[]` | Primary keys that could not be resolved by the model. |
156
+ | `isError` | `false \| undefined` | Absent on success; included for type narrowing. |
157
+
158
+ **Error**
159
+
160
+ | Field | Type | Description |
161
+ | --------- | -------- | -------------------------------------------------------- |
162
+ | `isError` | `true` | Indicates the request failed. |
163
+ | `error` | `string` | Message describing the error returned by the API or SDK. |
164
+
165
+ ## SDK API
166
+
167
+ **`new Nua(config?)`**
168
+ Creates a client bound to your Nuabase account. Provide:
169
+
170
+ - `apiKey?: string` – API key for authentication. Defaults to `process.env.NUABASE_API_KEY`.
171
+ - `baseUrl?: string` – Override the API host. Defaults to `https://api.nuabase.com`.
172
+
173
+ **`nua.map({ name, prompt, output })`**
174
+ Declares a typed mapping function backed by Nuabase. Parameters:
175
+
176
+ - `name: string` – Label applied to the enriched payload in each response row (e.g., `result.data[i][name]`).
177
+ - `prompt: string` – Natural-language instructions sent to the LLM.
178
+ - `output: ZodSchema` – Zod schema describing the output shape. Nuabase stores the JSON Schema twin and validates responses against it before returning.
179
+
180
+ Returns a callable object (the mapper) with two entry points:
181
+
182
+ - `mapper(data, primaryKey)` – Submits the job asynchronously and returns immediately with metadata and eventual results.
183
+ - `mapper.now(data, primaryKey)` – Runs the job and waits until the full enriched result set is ready.
184
+
185
+ Both entry points expect:
186
+
187
+ - `data: Array<Record<string, unknown>>` – Rows you want Nuabase to enrich. Each row must include the primary key.
188
+ - `primaryKey: string` – Field name that uniquely identifies each row within `data`. The SDK throws if the field is missing on any item.
189
+
190
+ Both entry points resolve to either:
191
+
192
+ - **Success** – `{ isSuccess: true, data, llmRequestId, cacheHits, rowsWithNoResults }`.
193
+ - **Error** – `{ isError: true, error }`.
194
+
195
+ ## Next Steps
196
+
197
+ - Create an API key or inspect request logs in the [Nuabase Console](https://console.nuabase.com/).
198
+ - Explore more SDK usage patterns (SSE streaming, webhooks, caching) in the full docs at https://docs.nuabase.com.
199
+
200
+ ## Support
201
+
202
+ Email us at [hello@nuabase.com](mailto:hello@nuabase.com). On X at [@NuabaseHQ](x.com/NuabaseHQ).
203
+
204
+ ## Credits
205
+
206
+ The template for this package comes from https://github.com/rtivital/ts-package-template
207
+
208
+ ## License
209
+
210
+ MIT
@@ -0,0 +1,178 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+
5
+ async function parseErrorResponse(response, urlPath) {
6
+ const fallbackMessage = `Request to ${urlPath} failed with status ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
7
+ let responseBody = "";
8
+ try {
9
+ responseBody = (await response.text()).trim();
10
+ } catch {
11
+ return { error: fallbackMessage, isError: true };
12
+ }
13
+ if (!responseBody) {
14
+ return { error: fallbackMessage, isError: true };
15
+ }
16
+ const parsedBody = safeParseJson(responseBody);
17
+ if (parsedBody && typeof parsedBody === "object") {
18
+ const errorMessage = extractErrorMessage(parsedBody);
19
+ if (errorMessage) {
20
+ return { error: errorMessage, isError: true };
21
+ }
22
+ }
23
+ return { error: responseBody, isError: true };
24
+ }
25
+ function safeParseJson(payload) {
26
+ try {
27
+ return JSON.parse(payload);
28
+ } catch {
29
+ return void 0;
30
+ }
31
+ }
32
+ function extractErrorMessage(body) {
33
+ const e = body["error"];
34
+ if (e && typeof e === "string") return e;
35
+ return void 0;
36
+ }
37
+
38
+ function isErrorWithMessage(error) {
39
+ return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
40
+ }
41
+ function getErrorMessageFromException(error) {
42
+ if (isErrorWithMessage(error)) {
43
+ return error.message;
44
+ }
45
+ return String(error);
46
+ }
47
+
48
+ class NuabaseAPIClient {
49
+ constructor(config = {}) {
50
+ this.apiKey = config.apiKey || process.env.NUABASE_API_KEY || "";
51
+ this.baseUrl = config.baseUrl || process.env.NUABASE_API_URL || "https://api.nuabase.com";
52
+ if (!this.apiKey) {
53
+ throw new Error(
54
+ "API key is required. Provide it via config.apiKey or NUABASE_API_KEY environment variable."
55
+ );
56
+ }
57
+ }
58
+ async request(urlPath, params) {
59
+ const url = `${this.baseUrl}/${urlPath}`;
60
+ let response;
61
+ try {
62
+ response = await fetch(url, {
63
+ method: "POST",
64
+ headers: {
65
+ "Content-Type": "application/json",
66
+ Authorization: `Bearer ${this.apiKey}`
67
+ },
68
+ body: JSON.stringify(params)
69
+ });
70
+ } catch (e) {
71
+ return { error: `Error calling Nuabase API: ${getErrorMessageFromException(e)}` };
72
+ }
73
+ let result;
74
+ if (!response.ok) {
75
+ return await parseErrorResponse(response, urlPath);
76
+ }
77
+ try {
78
+ result = await response.json();
79
+ } catch {
80
+ return { error: "Invalid response received from Nuabase API call, unable to parse" };
81
+ }
82
+ return result;
83
+ }
84
+ }
85
+
86
+ const zs_MapResponseRecord = (primaryKeyName, outputKey, outputSchema) => {
87
+ const primaryKeySchema = zod.z.any();
88
+ return zod.z.object({
89
+ [primaryKeyName]: primaryKeySchema,
90
+ [outputKey]: outputSchema
91
+ }).strict();
92
+ };
93
+ const zs_MapSuccessDataResult = (primaryKeyName, outputKey, outputSchema) => {
94
+ const recordSchema = zs_MapResponseRecord(primaryKeyName, outputKey, outputSchema);
95
+ return zod.z.array(recordSchema);
96
+ };
97
+ const zs_MapRequestApiResponse_Success = (primaryKeyName, outputKey, outputSchema) => {
98
+ const dataSchema = zs_MapSuccessDataResult(primaryKeyName, outputKey, outputSchema);
99
+ return zod.z.object({
100
+ llmRequestId: zod.z.string(),
101
+ kind: zod.z.literal("map"),
102
+ data: dataSchema,
103
+ cacheHits: zod.z.number(),
104
+ rowsWithNoResults: zod.z.array(zod.z.string()),
105
+ isSuccess: zod.z.literal(true),
106
+ isError: zod.z.optional(zod.z.literal(false))
107
+ }).strict();
108
+ };
109
+ class Nua {
110
+ constructor(config) {
111
+ this.apiClient = new NuabaseAPIClient(config);
112
+ }
113
+ // Some of the checks here mirror type validation, but since our code could be run from
114
+ // untyped JavaScript, we still want runtime checks
115
+ static validateMapRequestParams(data, primaryKeyName) {
116
+ if (!Array.isArray(data)) {
117
+ throw new Error("`data` must be an array of objects.");
118
+ }
119
+ if (!primaryKeyName || typeof primaryKeyName !== "string") {
120
+ throw new Error("`primaryKeyName` must be a non-empty string.");
121
+ }
122
+ data.forEach((item, index) => {
123
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
124
+ throw new Error(`data[${index}] must be a non-null object.`);
125
+ }
126
+ if (!(primaryKeyName in item)) {
127
+ throw new Error(`data[${index}] must contain property '${primaryKeyName}'.`);
128
+ }
129
+ });
130
+ }
131
+ map(fnDef) {
132
+ const client = this.apiClient;
133
+ const outputJsonSchema = zod.z.toJSONSchema(fnDef.output);
134
+ const makeRequest = async (path, data, primaryKeyName) => {
135
+ Nua.validateMapRequestParams(data, primaryKeyName);
136
+ const response = await client.request(path, {
137
+ input: {
138
+ prompt: fnDef.prompt,
139
+ data,
140
+ primaryKey: primaryKeyName
141
+ },
142
+ output: {
143
+ schema: outputJsonSchema,
144
+ name: fnDef.name
145
+ }
146
+ });
147
+ if (response && typeof response === "object" && "error" in response)
148
+ return { error: String(response.error), isError: true };
149
+ const outputKey = fnDef.name;
150
+ const successSchema = zs_MapRequestApiResponse_Success(primaryKeyName, outputKey, fnDef.output);
151
+ const parsedResponse = successSchema.safeParse(response);
152
+ if (!parsedResponse.success) {
153
+ const emsg = zod.z.prettifyError(parsedResponse.error);
154
+ return { error: `Invalid data received from Nuabase API: ${emsg}`, isError: true };
155
+ }
156
+ return {
157
+ isSuccess: true,
158
+ llmRequestId: parsedResponse.data.llmRequestId,
159
+ kind: parsedResponse.data.kind,
160
+ data: parsedResponse.data.data,
161
+ rowsWithNoResults: parsedResponse.data.rowsWithNoResults,
162
+ cacheHits: parsedResponse.data.cacheHits
163
+ };
164
+ };
165
+ const baseInvoker = async (data, primaryKeyName) => {
166
+ return await makeRequest("map", data, primaryKeyName);
167
+ };
168
+ const nowInvoker = async (data, primaryKeyName) => {
169
+ return await makeRequest("map/now", data, primaryKeyName);
170
+ };
171
+ const fnReturnValue = Object.assign(baseInvoker, {
172
+ now: nowInvoker
173
+ });
174
+ return fnReturnValue;
175
+ }
176
+ }
177
+
178
+ exports.Nua = Nua;
@@ -0,0 +1,176 @@
1
+ import { z } from 'zod';
2
+
3
+ async function parseErrorResponse(response, urlPath) {
4
+ const fallbackMessage = `Request to ${urlPath} failed with status ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
5
+ let responseBody = "";
6
+ try {
7
+ responseBody = (await response.text()).trim();
8
+ } catch {
9
+ return { error: fallbackMessage, isError: true };
10
+ }
11
+ if (!responseBody) {
12
+ return { error: fallbackMessage, isError: true };
13
+ }
14
+ const parsedBody = safeParseJson(responseBody);
15
+ if (parsedBody && typeof parsedBody === "object") {
16
+ const errorMessage = extractErrorMessage(parsedBody);
17
+ if (errorMessage) {
18
+ return { error: errorMessage, isError: true };
19
+ }
20
+ }
21
+ return { error: responseBody, isError: true };
22
+ }
23
+ function safeParseJson(payload) {
24
+ try {
25
+ return JSON.parse(payload);
26
+ } catch {
27
+ return void 0;
28
+ }
29
+ }
30
+ function extractErrorMessage(body) {
31
+ const e = body["error"];
32
+ if (e && typeof e === "string") return e;
33
+ return void 0;
34
+ }
35
+
36
+ function isErrorWithMessage(error) {
37
+ return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
38
+ }
39
+ function getErrorMessageFromException(error) {
40
+ if (isErrorWithMessage(error)) {
41
+ return error.message;
42
+ }
43
+ return String(error);
44
+ }
45
+
46
+ class NuabaseAPIClient {
47
+ constructor(config = {}) {
48
+ this.apiKey = config.apiKey || process.env.NUABASE_API_KEY || "";
49
+ this.baseUrl = config.baseUrl || process.env.NUABASE_API_URL || "https://api.nuabase.com";
50
+ if (!this.apiKey) {
51
+ throw new Error(
52
+ "API key is required. Provide it via config.apiKey or NUABASE_API_KEY environment variable."
53
+ );
54
+ }
55
+ }
56
+ async request(urlPath, params) {
57
+ const url = `${this.baseUrl}/${urlPath}`;
58
+ let response;
59
+ try {
60
+ response = await fetch(url, {
61
+ method: "POST",
62
+ headers: {
63
+ "Content-Type": "application/json",
64
+ Authorization: `Bearer ${this.apiKey}`
65
+ },
66
+ body: JSON.stringify(params)
67
+ });
68
+ } catch (e) {
69
+ return { error: `Error calling Nuabase API: ${getErrorMessageFromException(e)}` };
70
+ }
71
+ let result;
72
+ if (!response.ok) {
73
+ return await parseErrorResponse(response, urlPath);
74
+ }
75
+ try {
76
+ result = await response.json();
77
+ } catch {
78
+ return { error: "Invalid response received from Nuabase API call, unable to parse" };
79
+ }
80
+ return result;
81
+ }
82
+ }
83
+
84
+ const zs_MapResponseRecord = (primaryKeyName, outputKey, outputSchema) => {
85
+ const primaryKeySchema = z.any();
86
+ return z.object({
87
+ [primaryKeyName]: primaryKeySchema,
88
+ [outputKey]: outputSchema
89
+ }).strict();
90
+ };
91
+ const zs_MapSuccessDataResult = (primaryKeyName, outputKey, outputSchema) => {
92
+ const recordSchema = zs_MapResponseRecord(primaryKeyName, outputKey, outputSchema);
93
+ return z.array(recordSchema);
94
+ };
95
+ const zs_MapRequestApiResponse_Success = (primaryKeyName, outputKey, outputSchema) => {
96
+ const dataSchema = zs_MapSuccessDataResult(primaryKeyName, outputKey, outputSchema);
97
+ return z.object({
98
+ llmRequestId: z.string(),
99
+ kind: z.literal("map"),
100
+ data: dataSchema,
101
+ cacheHits: z.number(),
102
+ rowsWithNoResults: z.array(z.string()),
103
+ isSuccess: z.literal(true),
104
+ isError: z.optional(z.literal(false))
105
+ }).strict();
106
+ };
107
+ class Nua {
108
+ constructor(config) {
109
+ this.apiClient = new NuabaseAPIClient(config);
110
+ }
111
+ // Some of the checks here mirror type validation, but since our code could be run from
112
+ // untyped JavaScript, we still want runtime checks
113
+ static validateMapRequestParams(data, primaryKeyName) {
114
+ if (!Array.isArray(data)) {
115
+ throw new Error("`data` must be an array of objects.");
116
+ }
117
+ if (!primaryKeyName || typeof primaryKeyName !== "string") {
118
+ throw new Error("`primaryKeyName` must be a non-empty string.");
119
+ }
120
+ data.forEach((item, index) => {
121
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
122
+ throw new Error(`data[${index}] must be a non-null object.`);
123
+ }
124
+ if (!(primaryKeyName in item)) {
125
+ throw new Error(`data[${index}] must contain property '${primaryKeyName}'.`);
126
+ }
127
+ });
128
+ }
129
+ map(fnDef) {
130
+ const client = this.apiClient;
131
+ const outputJsonSchema = z.toJSONSchema(fnDef.output);
132
+ const makeRequest = async (path, data, primaryKeyName) => {
133
+ Nua.validateMapRequestParams(data, primaryKeyName);
134
+ const response = await client.request(path, {
135
+ input: {
136
+ prompt: fnDef.prompt,
137
+ data,
138
+ primaryKey: primaryKeyName
139
+ },
140
+ output: {
141
+ schema: outputJsonSchema,
142
+ name: fnDef.name
143
+ }
144
+ });
145
+ if (response && typeof response === "object" && "error" in response)
146
+ return { error: String(response.error), isError: true };
147
+ const outputKey = fnDef.name;
148
+ const successSchema = zs_MapRequestApiResponse_Success(primaryKeyName, outputKey, fnDef.output);
149
+ const parsedResponse = successSchema.safeParse(response);
150
+ if (!parsedResponse.success) {
151
+ const emsg = z.prettifyError(parsedResponse.error);
152
+ return { error: `Invalid data received from Nuabase API: ${emsg}`, isError: true };
153
+ }
154
+ return {
155
+ isSuccess: true,
156
+ llmRequestId: parsedResponse.data.llmRequestId,
157
+ kind: parsedResponse.data.kind,
158
+ data: parsedResponse.data.data,
159
+ rowsWithNoResults: parsedResponse.data.rowsWithNoResults,
160
+ cacheHits: parsedResponse.data.cacheHits
161
+ };
162
+ };
163
+ const baseInvoker = async (data, primaryKeyName) => {
164
+ return await makeRequest("map", data, primaryKeyName);
165
+ };
166
+ const nowInvoker = async (data, primaryKeyName) => {
167
+ return await makeRequest("map/now", data, primaryKeyName);
168
+ };
169
+ const fnReturnValue = Object.assign(baseInvoker, {
170
+ now: nowInvoker
171
+ });
172
+ return fnReturnValue;
173
+ }
174
+ }
175
+
176
+ export { Nua };
@@ -0,0 +1,3 @@
1
+ export { type NuabaseConfig } from './lib/api-client';
2
+ export { type NuabaseError } from './lib/error-response';
3
+ export { Nua } from './nua';
@@ -0,0 +1,3 @@
1
+ export { type NuabaseConfig } from './lib/api-client';
2
+ export { type NuabaseError } from './lib/error-response';
3
+ export { Nua } from './nua';
@@ -0,0 +1,11 @@
1
+ import { NuabaseError } from './error-response';
2
+ export type NuabaseConfig = {
3
+ apiKey?: string;
4
+ baseUrl?: string;
5
+ };
6
+ export declare class NuabaseAPIClient {
7
+ private readonly apiKey;
8
+ private readonly baseUrl;
9
+ constructor(config?: NuabaseConfig);
10
+ request(urlPath: string, params: object): Promise<NuabaseError | unknown>;
11
+ }
@@ -0,0 +1,6 @@
1
+ export type NuabaseError = {
2
+ error: string;
3
+ isError: true;
4
+ isSuccess?: false;
5
+ };
6
+ export declare function parseErrorResponse(response: Response, urlPath: string): Promise<NuabaseError>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Safely extracts an error message from an unknown value.
3
+ * @param error The unknown value caught in a catch block.
4
+ * @returns A string representing the error message.
5
+ */
6
+ export declare function getErrorMessageFromException(error: unknown): string;
@@ -0,0 +1,33 @@
1
+ import { NuabaseAPIClient, NuabaseConfig } from './lib/api-client';
2
+ import { NuabaseError } from './lib/error-response';
3
+ import { z } from 'zod';
4
+ type MappingFnDef<OutputName extends string, OutputZodSchema extends z.ZodTypeAny> = {
5
+ name: OutputName;
6
+ prompt: string;
7
+ output: OutputZodSchema;
8
+ };
9
+ type MapResponseRecord<OutputZodSchema extends z.ZodTypeAny, OutputName extends string, InputRecord extends Record<string, unknown>, PrimaryKeyName extends keyof InputRecord & string> = {
10
+ [Key in PrimaryKeyName | OutputName]: Key extends PrimaryKeyName ? InputRecord[PrimaryKeyName] : z.infer<OutputZodSchema>;
11
+ };
12
+ type MapSuccessDataResult<OutputZodSchema extends z.ZodTypeAny, OutputName extends string, InputRecord extends Record<string, unknown>, PrimaryKeyName extends keyof InputRecord & string> = Array<MapResponseRecord<OutputZodSchema, OutputName, InputRecord, PrimaryKeyName>>;
13
+ type MapRequestApiResponse_Success<OutputZodSchema extends z.ZodTypeAny, OutputName extends string, InputRecord extends Record<string, unknown>, PrimaryKeyName extends keyof InputRecord & string> = {
14
+ data: MapSuccessDataResult<OutputZodSchema, OutputName, InputRecord, PrimaryKeyName>;
15
+ cacheHits: number;
16
+ llmRequestId: string;
17
+ kind: 'map';
18
+ rowsWithNoResults: string[];
19
+ isSuccess: true;
20
+ isError?: false;
21
+ };
22
+ type MapResult<OutputZodSchema extends z.ZodTypeAny, OutputName extends string, InputRecord extends Record<string, unknown>, PrimaryKeyName extends keyof InputRecord & string> = NuabaseError | MapRequestApiResponse_Success<OutputZodSchema, OutputName, InputRecord, PrimaryKeyName>;
23
+ type MapInvoker<OutputZodSchema extends z.ZodTypeAny, OutputName extends string> = {
24
+ <InputRecord extends Record<string, unknown>, PrimaryKeyName extends keyof InputRecord & string>(data: InputRecord[], primaryKeyName: PrimaryKeyName): Promise<MapResult<OutputZodSchema, OutputName, InputRecord, PrimaryKeyName>>;
25
+ now: <InputRecord extends Record<string, unknown>, PrimaryKeyName extends keyof InputRecord & string>(data: InputRecord[], primaryKeyName: PrimaryKeyName) => Promise<MapResult<OutputZodSchema, OutputName, InputRecord, PrimaryKeyName>>;
26
+ };
27
+ export declare class Nua {
28
+ apiClient: NuabaseAPIClient;
29
+ constructor(config?: NuabaseConfig);
30
+ static validateMapRequestParams(data: unknown, primaryKeyName: unknown): void;
31
+ map<OutputName extends string, OutputZodSchema extends z.ZodTypeAny>(fnDef: MappingFnDef<OutputName, OutputZodSchema>): MapInvoker<OutputZodSchema, OutputName>;
32
+ }
33
+ export {};
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "nuabase",
3
+ "description": "Nuabase TypeScript client to create typed functions from LLM prompts",
4
+ "packageManager": "yarn@4.10.3+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f",
5
+ "version": "1.0.0",
6
+ "type": "module",
7
+ "author": "Jasim A Basheer <jasim@nuabase.com>",
8
+ "engines": {
9
+ "node": ">=16.6.0"
10
+ },
11
+ "keywords": [
12
+ "typescript",
13
+ "nuabase",
14
+ "ai",
15
+ "llm"
16
+ ],
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/nuabase/ts-sdk.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/nuabase/ts-sdk/issues"
24
+ },
25
+ "homepage": "https://github.com/nuabase/ts-sdk#readme",
26
+ "main": "./dist/cjs/index.cjs",
27
+ "types": "./dist/types/index.d.cts",
28
+ "module": "./dist/esm/index.mjs",
29
+ "exports": {
30
+ ".": {
31
+ "import": {
32
+ "types": "./dist/types/index.d.mts",
33
+ "default": "./dist/esm/index.mjs"
34
+ },
35
+ "require": {
36
+ "types": "./dist/types/index.d.cts",
37
+ "default": "./dist/cjs/index.cjs"
38
+ }
39
+ }
40
+ },
41
+ "peerDependencies": {
42
+ "zod": "^4.1.5"
43
+ },
44
+ "scripts": {
45
+ "clean": "rimraf dist",
46
+ "generate-dts": "tsx scripts/generate-dts",
47
+ "build": "rollup -c rollup.config.js && npm run generate-dts",
48
+ "pack:test": "tsx scripts/pack-test",
49
+ "prettier:check": "prettier --check \"**/*.{ts,tsx}\"",
50
+ "prettier:write": "prettier --write \"**/*.{ts,tsx}\"",
51
+ "typecheck": "tsc --noEmit",
52
+ "lint": "eslint --cache .",
53
+ "jest": "jest",
54
+ "test": "npm run prettier:check && npm run typecheck && npm run lint && npm run jest && npm run build && npm run pack:test",
55
+ "release": "npm test && tsx scripts/release",
56
+ "knip": "knip"
57
+ },
58
+ "devDependencies": {
59
+ "@eslint/js": "^9.35.0",
60
+ "@ianvs/prettier-plugin-sort-imports": "^4.7.0",
61
+ "@rollup/plugin-commonjs": "^28.0.6",
62
+ "@rollup/plugin-node-resolve": "^16.0.1",
63
+ "@rollup/plugin-replace": "^6.0.2",
64
+ "@types/fs-extra": "^11",
65
+ "@types/jest": "^30.0.0",
66
+ "@types/node": "^24.3.3",
67
+ "@types/signale": "^1",
68
+ "@types/yargs": "^17.0.33",
69
+ "chalk": "^5.6.2",
70
+ "esbuild": "^0.25.9",
71
+ "eslint": "^9.35.0",
72
+ "fs-extra": "^11.3.1",
73
+ "jest": "^30.1.3",
74
+ "knip": "^5.63.1",
75
+ "new-github-release-url": "^2.0.0",
76
+ "open": "^10.2.0",
77
+ "prettier": "^3.6.2",
78
+ "rimraf": "^6.0.1",
79
+ "rollup": "^4.50.1",
80
+ "rollup-plugin-esbuild": "^6.2.1",
81
+ "rollup-plugin-node-externals": "^8.1.1",
82
+ "signale": "^1.4.0",
83
+ "simple-git": "^3.28.0",
84
+ "ts-jest": "^29.4.1",
85
+ "tsx": "^4.20.5",
86
+ "typescript": "^5.9.2",
87
+ "typescript-eslint": "^8.43.0",
88
+ "version-next": "^1.0.2",
89
+ "yargs": "^18.0.0",
90
+ "zod": "^4.1.5",
91
+ "zx": "^8.8.1"
92
+ }
93
+ }