@getabrain/sdk 0.1.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 ADDED
@@ -0,0 +1,59 @@
1
+ # @getabrain/sdk
2
+
3
+ Official Node/TypeScript SDK for [GetABrain.ai](https://getabrain.ai) — real human judgment as an API.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @getabrain/sdk
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ import { GetABrain } from '@getabrain/sdk'
15
+
16
+ const gab = new GetABrain({ apiKey: 'gab_k_…', apiSecret: 'gab_s_…' })
17
+
18
+ // Submit a question (returns immediately)
19
+ const query = await gab.queries.create({
20
+ type: 'ab_test',
21
+ title: 'Which headline converts better?',
22
+ content_data: {
23
+ question: 'Which is more compelling?',
24
+ variant_a: { description: 'Save 20% today' },
25
+ variant_b: { description: 'Your future self will thank you' },
26
+ },
27
+ required_responses: 5,
28
+ bid_amount_cents: 25,
29
+ })
30
+
31
+ // Wait for humans to answer (polls for you)
32
+ const responses = await gab.queries.waitForResponses(query.id, { minResponses: 5 })
33
+ console.log(responses.map((r) => r.response_data))
34
+ ```
35
+
36
+ ## Errors
37
+
38
+ ```ts
39
+ import { InsufficientBalanceError, RateLimitError } from '@getabrain/sdk'
40
+
41
+ try {
42
+ await gab.queries.create(/* … */)
43
+ } catch (e) {
44
+ if (e instanceof InsufficientBalanceError) {
45
+ // top up your balance at https://getabrain.ai
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## API
51
+
52
+ - `gab.queries.create(input)` / `.get(id)` / `.list({ status?, limit?, offset? })` / `.cancel(id)`
53
+ - `gab.queries.waitForResponses(id, { minResponses, timeoutMs?, pollIntervalMs? })`
54
+ - `gab.responses.rate(queryId, responseId, { score, feedback_text? })` / `.getRating(queryId, responseId)`
55
+ - `gab.account.stats()` / `.balance()`
56
+
57
+ Full reference: https://getabrain.ai/docs/api
58
+
59
+ > The SDK types the **13 first-class query types**. Two legacy types (`custom`, `headline_test`) exist server-side but are deprecated and intentionally not typed by the SDK — use a first-class type instead.
package/dist/index.cjs ADDED
@@ -0,0 +1,292 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/index.ts
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ AccountResource: () => AccountResource,
23
+ AuthError: () => AuthError,
24
+ ConflictError: () => ConflictError,
25
+ DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
26
+ ForbiddenError: () => ForbiddenError,
27
+ GetABrain: () => GetABrain,
28
+ GetABrainError: () => GetABrainError,
29
+ InsufficientBalanceError: () => InsufficientBalanceError,
30
+ NetworkError: () => NetworkError,
31
+ NotFoundError: () => NotFoundError,
32
+ QUERY_TYPES: () => QUERY_TYPES,
33
+ QueriesResource: () => QueriesResource,
34
+ RateLimitError: () => RateLimitError,
35
+ ResponsesResource: () => ResponsesResource,
36
+ ServerError: () => ServerError,
37
+ TimeoutError: () => TimeoutError,
38
+ ValidationError: () => ValidationError,
39
+ errorFromResponse: () => errorFromResponse
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/errors.ts
44
+ var GetABrainError = class extends Error {
45
+ constructor(message, status, code = "error", requestId) {
46
+ super(message);
47
+ this.status = status;
48
+ this.code = code;
49
+ this.requestId = requestId;
50
+ this.name = new.target.name;
51
+ }
52
+ };
53
+ var ValidationError = class extends GetABrainError {
54
+ };
55
+ var AuthError = class extends GetABrainError {
56
+ };
57
+ var InsufficientBalanceError = class extends GetABrainError {
58
+ };
59
+ var ForbiddenError = class extends GetABrainError {
60
+ };
61
+ var NotFoundError = class extends GetABrainError {
62
+ };
63
+ var ConflictError = class extends GetABrainError {
64
+ };
65
+ var ServerError = class extends GetABrainError {
66
+ };
67
+ var RateLimitError = class extends GetABrainError {
68
+ constructor(message, status, code, retryAfterMs, requestId) {
69
+ super(message, status, code, requestId);
70
+ this.retryAfterMs = retryAfterMs;
71
+ }
72
+ };
73
+ var TimeoutError = class extends GetABrainError {
74
+ constructor(message = "Request timed out") {
75
+ super(message, 0, "timeout");
76
+ }
77
+ };
78
+ var NetworkError = class extends GetABrainError {
79
+ constructor(message = "Network request failed") {
80
+ super(message, 0, "network");
81
+ }
82
+ };
83
+ function errorFromResponse(status, body, retryAfterMs) {
84
+ const message = body && body.message || body && body.error || `HTTP ${status}`;
85
+ const code = body && body.error || "error";
86
+ switch (status) {
87
+ case 400:
88
+ return new ValidationError(message, status, code);
89
+ case 401:
90
+ return new AuthError(message, status, code);
91
+ case 402:
92
+ return new InsufficientBalanceError(message, status, code);
93
+ case 403:
94
+ return new ForbiddenError(message, status, code);
95
+ case 404:
96
+ return new NotFoundError(message, status, code);
97
+ case 409:
98
+ return new ConflictError(message, status, code);
99
+ case 429:
100
+ return new RateLimitError(message, status, code, retryAfterMs);
101
+ default:
102
+ if (status >= 500) return new ServerError(message, status, code);
103
+ return new GetABrainError(message, status, code);
104
+ }
105
+ }
106
+
107
+ // src/http.ts
108
+ var DEFAULT_BASE_URL = "https://www.getabrain.ai/api/v1";
109
+ var realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
110
+ function createTransport(config) {
111
+ var _a, _b, _c, _d, _e;
112
+ const baseUrl = ((_a = config.baseUrl) != null ? _a : DEFAULT_BASE_URL).replace(/\/+$/, "");
113
+ const doFetch = (_b = config.fetch) != null ? _b : globalThis.fetch;
114
+ const timeoutMs = (_c = config.timeoutMs) != null ? _c : 3e4;
115
+ const maxRetries = (_d = config.maxRetries) != null ? _d : 2;
116
+ const sleep = (_e = config.sleep) != null ? _e : realSleep;
117
+ if (typeof doFetch !== "function") {
118
+ throw new GetABrainError("No fetch available \u2014 use Node 18+ or pass { fetch }", 0, "config");
119
+ }
120
+ return async function request(method, path, opts = {}) {
121
+ const url = new URL(baseUrl + path);
122
+ if (opts.query) {
123
+ for (const [k, v] of Object.entries(opts.query)) if (v !== void 0) url.searchParams.set(k, String(v));
124
+ }
125
+ const isRead = method.toUpperCase() === "GET";
126
+ let attempt = 0;
127
+ for (; ; ) {
128
+ const controller = new AbortController();
129
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
130
+ let res;
131
+ try {
132
+ res = await doFetch(url.toString(), {
133
+ method,
134
+ headers: { "X-API-Key": config.apiKey, "X-API-Secret": config.apiSecret, "Content-Type": "application/json" },
135
+ body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0,
136
+ signal: controller.signal
137
+ });
138
+ } catch (err) {
139
+ clearTimeout(timer);
140
+ if ((err == null ? void 0 : err.name) === "AbortError") throw new TimeoutError();
141
+ if (isRead && attempt < maxRetries) {
142
+ attempt++;
143
+ await sleep(backoff(attempt));
144
+ continue;
145
+ }
146
+ throw new NetworkError((err == null ? void 0 : err.message) || "fetch failed");
147
+ }
148
+ clearTimeout(timer);
149
+ if (res.ok) {
150
+ if (res.status === 204) return void 0;
151
+ return await res.json();
152
+ }
153
+ const retryAfterMs = parseRetryAfter(res.headers.get("retry-after"));
154
+ if (isRead && (res.status === 429 || res.status >= 500) && attempt < maxRetries) {
155
+ attempt++;
156
+ await sleep(retryAfterMs != null ? retryAfterMs : backoff(attempt));
157
+ continue;
158
+ }
159
+ let body = null;
160
+ try {
161
+ body = await res.json();
162
+ } catch (e) {
163
+ }
164
+ throw errorFromResponse(res.status, body, retryAfterMs);
165
+ }
166
+ };
167
+ }
168
+ function backoff(attempt) {
169
+ return Math.min(1e3 * 2 ** (attempt - 1), 8e3);
170
+ }
171
+ function parseRetryAfter(h) {
172
+ if (!h) return void 0;
173
+ const n = Number(h);
174
+ return Number.isFinite(n) ? n * 1e3 : void 0;
175
+ }
176
+
177
+ // src/resources/queries.ts
178
+ var TERMINAL = /* @__PURE__ */ new Set(["completed", "cancelled", "failed", "expired"]);
179
+ var realSleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
180
+ var QueriesResource = class {
181
+ constructor(request) {
182
+ this.request = request;
183
+ }
184
+ create(input) {
185
+ return this.request("POST", "/requestor/queries", { body: input });
186
+ }
187
+ get(id) {
188
+ return this.request("GET", `/requestor/queries/${encodeURIComponent(id)}`);
189
+ }
190
+ list(params = {}) {
191
+ return this.request("GET", "/requestor/queries", { query: { status: params.status, limit: params.limit, offset: params.offset } });
192
+ }
193
+ cancel(id) {
194
+ return this.request("PUT", `/requestor/queries/${encodeURIComponent(id)}`, { body: { action: "cancel" } });
195
+ }
196
+ // Poll until `minResponses` responses arrive, the query reaches a terminal
197
+ // status, or the timeout elapses (throws TimeoutError).
198
+ async waitForResponses(id, opts) {
199
+ var _a, _b, _c, _d, _e, _f;
200
+ const timeoutMs = (_a = opts.timeoutMs) != null ? _a : 6e5;
201
+ const pollIntervalMs = (_b = opts.pollIntervalMs) != null ? _b : 5e3;
202
+ const sleep = (_c = opts.sleep) != null ? _c : realSleep2;
203
+ const now = (_d = opts.now) != null ? _d : Date.now;
204
+ const deadline = now() + timeoutMs;
205
+ for (; ; ) {
206
+ const query = await this.get(id);
207
+ const responses = (_e = query.responses) != null ? _e : [];
208
+ if (((_f = query.completed_responses) != null ? _f : responses.length) >= opts.minResponses) return responses;
209
+ if (TERMINAL.has(query.status)) return responses;
210
+ if (now() >= deadline) throw new TimeoutError(`waitForResponses timed out after ${timeoutMs}ms for query ${id}`);
211
+ await sleep(pollIntervalMs);
212
+ }
213
+ }
214
+ };
215
+
216
+ // src/resources/responses.ts
217
+ var ResponsesResource = class {
218
+ constructor(request) {
219
+ this.request = request;
220
+ }
221
+ rate(queryId, responseId, input) {
222
+ const q = encodeURIComponent(queryId);
223
+ const r = encodeURIComponent(responseId);
224
+ return this.request("POST", `/requestor/queries/${q}/responses/${r}/rate`, { body: input });
225
+ }
226
+ getRating(queryId, responseId) {
227
+ const q = encodeURIComponent(queryId);
228
+ const r = encodeURIComponent(responseId);
229
+ return this.request("GET", `/requestor/queries/${q}/responses/${r}/rate`);
230
+ }
231
+ };
232
+
233
+ // src/resources/account.ts
234
+ var AccountResource = class {
235
+ constructor(request) {
236
+ this.request = request;
237
+ }
238
+ stats() {
239
+ return this.request("GET", "/requestor/stats");
240
+ }
241
+ balance() {
242
+ return this.request("GET", "/requestor/billing");
243
+ }
244
+ };
245
+
246
+ // src/client.ts
247
+ var GetABrain = class {
248
+ constructor(config) {
249
+ const request = createTransport(config);
250
+ this.queries = new QueriesResource(request);
251
+ this.responses = new ResponsesResource(request);
252
+ this.account = new AccountResource(request);
253
+ }
254
+ };
255
+
256
+ // src/types.ts
257
+ var QUERY_TYPES = [
258
+ "text",
259
+ "multiple_choice",
260
+ "rating_scale",
261
+ "image_comparison",
262
+ "ranking",
263
+ "yes_no",
264
+ "sentiment",
265
+ "image_selection",
266
+ "free_form_text",
267
+ "video_review",
268
+ "audio_review",
269
+ "image_analysis",
270
+ "ab_test"
271
+ ];
272
+ // Annotate the CommonJS export names for ESM import in node:
273
+ 0 && (module.exports = {
274
+ AccountResource,
275
+ AuthError,
276
+ ConflictError,
277
+ DEFAULT_BASE_URL,
278
+ ForbiddenError,
279
+ GetABrain,
280
+ GetABrainError,
281
+ InsufficientBalanceError,
282
+ NetworkError,
283
+ NotFoundError,
284
+ QUERY_TYPES,
285
+ QueriesResource,
286
+ RateLimitError,
287
+ ResponsesResource,
288
+ ServerError,
289
+ TimeoutError,
290
+ ValidationError,
291
+ errorFromResponse
292
+ });
@@ -0,0 +1,329 @@
1
+ declare const DEFAULT_BASE_URL = "https://www.getabrain.ai/api/v1";
2
+ interface TransportConfig {
3
+ apiKey: string;
4
+ apiSecret: string;
5
+ baseUrl?: string;
6
+ fetch?: typeof fetch;
7
+ timeoutMs?: number;
8
+ maxRetries?: number;
9
+ /** Injectable for deterministic tests; defaults to real setTimeout. */
10
+ sleep?: (ms: number) => Promise<void>;
11
+ }
12
+ interface RequestOptions {
13
+ body?: unknown;
14
+ query?: Record<string, string | number | undefined>;
15
+ }
16
+ type RequestFn = <T = any>(method: string, path: string, opts?: RequestOptions) => Promise<T>;
17
+
18
+ declare const QUERY_TYPES: readonly ["text", "multiple_choice", "rating_scale", "image_comparison", "ranking", "yes_no", "sentiment", "image_selection", "free_form_text", "video_review", "audio_review", "image_analysis", "ab_test"];
19
+ type QueryType = (typeof QUERY_TYPES)[number];
20
+ interface SharedContent {
21
+ question: string;
22
+ instructions?: string;
23
+ context?: string;
24
+ }
25
+ interface TextContent extends SharedContent {
26
+ min_words?: number;
27
+ max_words?: number;
28
+ }
29
+ interface MultipleChoiceContent extends SharedContent {
30
+ options: {
31
+ id: string;
32
+ text: string;
33
+ image_url?: string;
34
+ }[];
35
+ allow_multiple?: boolean;
36
+ min_selections?: number;
37
+ max_selections?: number;
38
+ }
39
+ interface RatingScaleContent extends SharedContent {
40
+ scale_type: '1-5' | '1-10' | '0-100' | 'stars';
41
+ scale_min: number;
42
+ scale_max: number;
43
+ scale_labels?: {
44
+ min_label?: string;
45
+ mid_label?: string;
46
+ max_label?: string;
47
+ };
48
+ criteria?: string[];
49
+ }
50
+ interface ImageComparisonContent extends SharedContent {
51
+ images: {
52
+ id: string;
53
+ url: string;
54
+ label?: string;
55
+ description?: string;
56
+ }[];
57
+ comparison_type: 'preference' | 'quality' | 'relevance' | 'custom';
58
+ require_reasoning?: boolean;
59
+ }
60
+ interface RankingContent extends SharedContent {
61
+ items: {
62
+ id: string;
63
+ text: string;
64
+ image_url?: string;
65
+ description?: string;
66
+ }[];
67
+ max_items: number;
68
+ require_all?: boolean;
69
+ }
70
+ interface YesNoContent extends SharedContent {
71
+ require_explanation?: boolean;
72
+ min_explanation_words?: number;
73
+ }
74
+ interface SentimentContent extends SharedContent {
75
+ subject: string;
76
+ sentiment_options: ('very_positive' | 'positive' | 'neutral' | 'negative' | 'very_negative')[];
77
+ require_reasoning?: boolean;
78
+ }
79
+ interface ImageSelectionContent extends SharedContent {
80
+ images: {
81
+ id: string;
82
+ url: string;
83
+ caption?: string;
84
+ }[];
85
+ min_selections: number;
86
+ max_selections: number;
87
+ selection_criteria: string;
88
+ }
89
+ interface FreeFormTextContent extends SharedContent {
90
+ prompt: string;
91
+ min_characters?: number;
92
+ max_characters?: number;
93
+ format_guidelines?: string;
94
+ }
95
+ interface VideoReviewContent extends SharedContent {
96
+ video_url: string;
97
+ video_duration_seconds: number;
98
+ review_aspects: string[];
99
+ min_watch_time_seconds?: number;
100
+ }
101
+ interface AudioReviewContent extends SharedContent {
102
+ audio_url: string;
103
+ audio_duration_seconds: number;
104
+ review_aspects: string[];
105
+ transcription_required?: boolean;
106
+ }
107
+ interface ImageAnalysisContent {
108
+ question: string;
109
+ image_url: string;
110
+ }
111
+ interface AbTestContent {
112
+ question: string;
113
+ variant_a: {
114
+ description: string;
115
+ image_url?: string;
116
+ url?: string;
117
+ };
118
+ variant_b: {
119
+ description: string;
120
+ image_url?: string;
121
+ url?: string;
122
+ };
123
+ }
124
+ interface CreateQueryBase {
125
+ title: string;
126
+ description?: string;
127
+ required_responses: number;
128
+ bid_amount_cents: number;
129
+ bonus_amount_cents?: number;
130
+ min_worker_quality?: number;
131
+ required_languages?: string[];
132
+ required_location_countries?: string[];
133
+ required_skills?: string[];
134
+ excluded_worker_ids?: string[];
135
+ expires_in_hours?: number;
136
+ }
137
+ type CreateQueryInput = (CreateQueryBase & {
138
+ type: 'text';
139
+ content_data: TextContent;
140
+ }) | (CreateQueryBase & {
141
+ type: 'multiple_choice';
142
+ content_data: MultipleChoiceContent;
143
+ }) | (CreateQueryBase & {
144
+ type: 'rating_scale';
145
+ content_data: RatingScaleContent;
146
+ }) | (CreateQueryBase & {
147
+ type: 'image_comparison';
148
+ content_data: ImageComparisonContent;
149
+ }) | (CreateQueryBase & {
150
+ type: 'ranking';
151
+ content_data: RankingContent;
152
+ }) | (CreateQueryBase & {
153
+ type: 'yes_no';
154
+ content_data: YesNoContent;
155
+ }) | (CreateQueryBase & {
156
+ type: 'sentiment';
157
+ content_data: SentimentContent;
158
+ }) | (CreateQueryBase & {
159
+ type: 'image_selection';
160
+ content_data: ImageSelectionContent;
161
+ }) | (CreateQueryBase & {
162
+ type: 'free_form_text';
163
+ content_data: FreeFormTextContent;
164
+ }) | (CreateQueryBase & {
165
+ type: 'video_review';
166
+ content_data: VideoReviewContent;
167
+ }) | (CreateQueryBase & {
168
+ type: 'audio_review';
169
+ content_data: AudioReviewContent;
170
+ }) | (CreateQueryBase & {
171
+ type: 'image_analysis';
172
+ content_data: ImageAnalysisContent;
173
+ }) | (CreateQueryBase & {
174
+ type: 'ab_test';
175
+ content_data: AbTestContent;
176
+ });
177
+ interface QueryResponse {
178
+ id: string;
179
+ response_data: Record<string, unknown>;
180
+ status: string;
181
+ submitted_at: string;
182
+ worker?: {
183
+ quality_score: number;
184
+ tier: string;
185
+ rating_count: number;
186
+ };
187
+ rating?: {
188
+ score: number;
189
+ feedback_text?: string | null;
190
+ } | null;
191
+ }
192
+ interface Query {
193
+ id: string;
194
+ type: QueryType;
195
+ title: string;
196
+ description?: string;
197
+ status: 'pending' | 'active' | 'completed' | 'cancelled' | 'failed' | 'expired';
198
+ required_responses: number;
199
+ completed_responses?: number;
200
+ bid_amount_cents: number;
201
+ bonus_amount_cents?: number;
202
+ total_cost_cents: number;
203
+ created_at: string;
204
+ expires_at?: string | null;
205
+ content_data?: Record<string, unknown>;
206
+ responses?: QueryResponse[];
207
+ }
208
+ interface QueryList {
209
+ queries: Query[];
210
+ total: number;
211
+ limit: number;
212
+ offset: number;
213
+ has_more: boolean;
214
+ }
215
+ interface RatingResult {
216
+ response_id: string;
217
+ score: number;
218
+ worker_new_quality_score: number;
219
+ worker_new_rating_count?: number;
220
+ worker_suspended: boolean;
221
+ feedback_text?: string | null;
222
+ }
223
+ interface Rating {
224
+ id: string;
225
+ response_id: string;
226
+ score: number;
227
+ feedback_text?: string | null;
228
+ created_at: string;
229
+ }
230
+ interface AccountStats {
231
+ balance_cents: number;
232
+ company_name: string;
233
+ total_queries: number;
234
+ active_queries: number;
235
+ completed_queries: number;
236
+ total_spent_cents: number;
237
+ recent_queries: Query[];
238
+ }
239
+ interface BillingInfo {
240
+ balance_cents: number;
241
+ company_name: string;
242
+ transactions: Record<string, unknown>[];
243
+ total: number;
244
+ has_more: boolean;
245
+ }
246
+
247
+ interface ListParams {
248
+ status?: string;
249
+ limit?: number;
250
+ offset?: number;
251
+ }
252
+ interface WaitOptions {
253
+ minResponses: number;
254
+ timeoutMs?: number;
255
+ pollIntervalMs?: number;
256
+ sleep?: (ms: number) => Promise<void>;
257
+ now?: () => number;
258
+ }
259
+ declare class QueriesResource {
260
+ private readonly request;
261
+ constructor(request: RequestFn);
262
+ create(input: CreateQueryInput): Promise<Query>;
263
+ get(id: string): Promise<Query>;
264
+ list(params?: ListParams): Promise<QueryList>;
265
+ cancel(id: string): Promise<{
266
+ success: boolean;
267
+ message: string;
268
+ refund_amount_cents: number;
269
+ }>;
270
+ waitForResponses(id: string, opts: WaitOptions): Promise<QueryResponse[]>;
271
+ }
272
+
273
+ declare class ResponsesResource {
274
+ private readonly request;
275
+ constructor(request: RequestFn);
276
+ rate(queryId: string, responseId: string, input: {
277
+ score: number;
278
+ feedback_text?: string;
279
+ }): Promise<RatingResult>;
280
+ getRating(queryId: string, responseId: string): Promise<Rating>;
281
+ }
282
+
283
+ declare class AccountResource {
284
+ private readonly request;
285
+ constructor(request: RequestFn);
286
+ stats(): Promise<AccountStats>;
287
+ balance(): Promise<BillingInfo>;
288
+ }
289
+
290
+ declare class GetABrain {
291
+ readonly queries: QueriesResource;
292
+ readonly responses: ResponsesResource;
293
+ readonly account: AccountResource;
294
+ constructor(config: TransportConfig);
295
+ }
296
+
297
+ declare class GetABrainError extends Error {
298
+ readonly status: number;
299
+ readonly code: string;
300
+ readonly requestId?: string;
301
+ constructor(message: string, status: number, code?: string, requestId?: string);
302
+ }
303
+ declare class ValidationError extends GetABrainError {
304
+ }
305
+ declare class AuthError extends GetABrainError {
306
+ }
307
+ declare class InsufficientBalanceError extends GetABrainError {
308
+ }
309
+ declare class ForbiddenError extends GetABrainError {
310
+ }
311
+ declare class NotFoundError extends GetABrainError {
312
+ }
313
+ declare class ConflictError extends GetABrainError {
314
+ }
315
+ declare class ServerError extends GetABrainError {
316
+ }
317
+ declare class RateLimitError extends GetABrainError {
318
+ readonly retryAfterMs?: number;
319
+ constructor(message: string, status: number, code: string, retryAfterMs?: number, requestId?: string);
320
+ }
321
+ declare class TimeoutError extends GetABrainError {
322
+ constructor(message?: string);
323
+ }
324
+ declare class NetworkError extends GetABrainError {
325
+ constructor(message?: string);
326
+ }
327
+ declare function errorFromResponse(status: number, body: any, retryAfterMs?: number): GetABrainError;
328
+
329
+ export { type AbTestContent, AccountResource, type AccountStats, type AudioReviewContent, AuthError, type BillingInfo, ConflictError, type CreateQueryBase, type CreateQueryInput, DEFAULT_BASE_URL, ForbiddenError, type FreeFormTextContent, GetABrain, GetABrainError, type ImageAnalysisContent, type ImageComparisonContent, type ImageSelectionContent, InsufficientBalanceError, type ListParams, type MultipleChoiceContent, NetworkError, NotFoundError, QUERY_TYPES, QueriesResource, type Query, type QueryList, type QueryResponse, type QueryType, type RankingContent, RateLimitError, type Rating, type RatingResult, type RatingScaleContent, type RequestOptions, ResponsesResource, type SentimentContent, ServerError, type TextContent, TimeoutError, type TransportConfig, ValidationError, type VideoReviewContent, type WaitOptions, type YesNoContent, errorFromResponse };
@@ -0,0 +1,329 @@
1
+ declare const DEFAULT_BASE_URL = "https://www.getabrain.ai/api/v1";
2
+ interface TransportConfig {
3
+ apiKey: string;
4
+ apiSecret: string;
5
+ baseUrl?: string;
6
+ fetch?: typeof fetch;
7
+ timeoutMs?: number;
8
+ maxRetries?: number;
9
+ /** Injectable for deterministic tests; defaults to real setTimeout. */
10
+ sleep?: (ms: number) => Promise<void>;
11
+ }
12
+ interface RequestOptions {
13
+ body?: unknown;
14
+ query?: Record<string, string | number | undefined>;
15
+ }
16
+ type RequestFn = <T = any>(method: string, path: string, opts?: RequestOptions) => Promise<T>;
17
+
18
+ declare const QUERY_TYPES: readonly ["text", "multiple_choice", "rating_scale", "image_comparison", "ranking", "yes_no", "sentiment", "image_selection", "free_form_text", "video_review", "audio_review", "image_analysis", "ab_test"];
19
+ type QueryType = (typeof QUERY_TYPES)[number];
20
+ interface SharedContent {
21
+ question: string;
22
+ instructions?: string;
23
+ context?: string;
24
+ }
25
+ interface TextContent extends SharedContent {
26
+ min_words?: number;
27
+ max_words?: number;
28
+ }
29
+ interface MultipleChoiceContent extends SharedContent {
30
+ options: {
31
+ id: string;
32
+ text: string;
33
+ image_url?: string;
34
+ }[];
35
+ allow_multiple?: boolean;
36
+ min_selections?: number;
37
+ max_selections?: number;
38
+ }
39
+ interface RatingScaleContent extends SharedContent {
40
+ scale_type: '1-5' | '1-10' | '0-100' | 'stars';
41
+ scale_min: number;
42
+ scale_max: number;
43
+ scale_labels?: {
44
+ min_label?: string;
45
+ mid_label?: string;
46
+ max_label?: string;
47
+ };
48
+ criteria?: string[];
49
+ }
50
+ interface ImageComparisonContent extends SharedContent {
51
+ images: {
52
+ id: string;
53
+ url: string;
54
+ label?: string;
55
+ description?: string;
56
+ }[];
57
+ comparison_type: 'preference' | 'quality' | 'relevance' | 'custom';
58
+ require_reasoning?: boolean;
59
+ }
60
+ interface RankingContent extends SharedContent {
61
+ items: {
62
+ id: string;
63
+ text: string;
64
+ image_url?: string;
65
+ description?: string;
66
+ }[];
67
+ max_items: number;
68
+ require_all?: boolean;
69
+ }
70
+ interface YesNoContent extends SharedContent {
71
+ require_explanation?: boolean;
72
+ min_explanation_words?: number;
73
+ }
74
+ interface SentimentContent extends SharedContent {
75
+ subject: string;
76
+ sentiment_options: ('very_positive' | 'positive' | 'neutral' | 'negative' | 'very_negative')[];
77
+ require_reasoning?: boolean;
78
+ }
79
+ interface ImageSelectionContent extends SharedContent {
80
+ images: {
81
+ id: string;
82
+ url: string;
83
+ caption?: string;
84
+ }[];
85
+ min_selections: number;
86
+ max_selections: number;
87
+ selection_criteria: string;
88
+ }
89
+ interface FreeFormTextContent extends SharedContent {
90
+ prompt: string;
91
+ min_characters?: number;
92
+ max_characters?: number;
93
+ format_guidelines?: string;
94
+ }
95
+ interface VideoReviewContent extends SharedContent {
96
+ video_url: string;
97
+ video_duration_seconds: number;
98
+ review_aspects: string[];
99
+ min_watch_time_seconds?: number;
100
+ }
101
+ interface AudioReviewContent extends SharedContent {
102
+ audio_url: string;
103
+ audio_duration_seconds: number;
104
+ review_aspects: string[];
105
+ transcription_required?: boolean;
106
+ }
107
+ interface ImageAnalysisContent {
108
+ question: string;
109
+ image_url: string;
110
+ }
111
+ interface AbTestContent {
112
+ question: string;
113
+ variant_a: {
114
+ description: string;
115
+ image_url?: string;
116
+ url?: string;
117
+ };
118
+ variant_b: {
119
+ description: string;
120
+ image_url?: string;
121
+ url?: string;
122
+ };
123
+ }
124
+ interface CreateQueryBase {
125
+ title: string;
126
+ description?: string;
127
+ required_responses: number;
128
+ bid_amount_cents: number;
129
+ bonus_amount_cents?: number;
130
+ min_worker_quality?: number;
131
+ required_languages?: string[];
132
+ required_location_countries?: string[];
133
+ required_skills?: string[];
134
+ excluded_worker_ids?: string[];
135
+ expires_in_hours?: number;
136
+ }
137
+ type CreateQueryInput = (CreateQueryBase & {
138
+ type: 'text';
139
+ content_data: TextContent;
140
+ }) | (CreateQueryBase & {
141
+ type: 'multiple_choice';
142
+ content_data: MultipleChoiceContent;
143
+ }) | (CreateQueryBase & {
144
+ type: 'rating_scale';
145
+ content_data: RatingScaleContent;
146
+ }) | (CreateQueryBase & {
147
+ type: 'image_comparison';
148
+ content_data: ImageComparisonContent;
149
+ }) | (CreateQueryBase & {
150
+ type: 'ranking';
151
+ content_data: RankingContent;
152
+ }) | (CreateQueryBase & {
153
+ type: 'yes_no';
154
+ content_data: YesNoContent;
155
+ }) | (CreateQueryBase & {
156
+ type: 'sentiment';
157
+ content_data: SentimentContent;
158
+ }) | (CreateQueryBase & {
159
+ type: 'image_selection';
160
+ content_data: ImageSelectionContent;
161
+ }) | (CreateQueryBase & {
162
+ type: 'free_form_text';
163
+ content_data: FreeFormTextContent;
164
+ }) | (CreateQueryBase & {
165
+ type: 'video_review';
166
+ content_data: VideoReviewContent;
167
+ }) | (CreateQueryBase & {
168
+ type: 'audio_review';
169
+ content_data: AudioReviewContent;
170
+ }) | (CreateQueryBase & {
171
+ type: 'image_analysis';
172
+ content_data: ImageAnalysisContent;
173
+ }) | (CreateQueryBase & {
174
+ type: 'ab_test';
175
+ content_data: AbTestContent;
176
+ });
177
+ interface QueryResponse {
178
+ id: string;
179
+ response_data: Record<string, unknown>;
180
+ status: string;
181
+ submitted_at: string;
182
+ worker?: {
183
+ quality_score: number;
184
+ tier: string;
185
+ rating_count: number;
186
+ };
187
+ rating?: {
188
+ score: number;
189
+ feedback_text?: string | null;
190
+ } | null;
191
+ }
192
+ interface Query {
193
+ id: string;
194
+ type: QueryType;
195
+ title: string;
196
+ description?: string;
197
+ status: 'pending' | 'active' | 'completed' | 'cancelled' | 'failed' | 'expired';
198
+ required_responses: number;
199
+ completed_responses?: number;
200
+ bid_amount_cents: number;
201
+ bonus_amount_cents?: number;
202
+ total_cost_cents: number;
203
+ created_at: string;
204
+ expires_at?: string | null;
205
+ content_data?: Record<string, unknown>;
206
+ responses?: QueryResponse[];
207
+ }
208
+ interface QueryList {
209
+ queries: Query[];
210
+ total: number;
211
+ limit: number;
212
+ offset: number;
213
+ has_more: boolean;
214
+ }
215
+ interface RatingResult {
216
+ response_id: string;
217
+ score: number;
218
+ worker_new_quality_score: number;
219
+ worker_new_rating_count?: number;
220
+ worker_suspended: boolean;
221
+ feedback_text?: string | null;
222
+ }
223
+ interface Rating {
224
+ id: string;
225
+ response_id: string;
226
+ score: number;
227
+ feedback_text?: string | null;
228
+ created_at: string;
229
+ }
230
+ interface AccountStats {
231
+ balance_cents: number;
232
+ company_name: string;
233
+ total_queries: number;
234
+ active_queries: number;
235
+ completed_queries: number;
236
+ total_spent_cents: number;
237
+ recent_queries: Query[];
238
+ }
239
+ interface BillingInfo {
240
+ balance_cents: number;
241
+ company_name: string;
242
+ transactions: Record<string, unknown>[];
243
+ total: number;
244
+ has_more: boolean;
245
+ }
246
+
247
+ interface ListParams {
248
+ status?: string;
249
+ limit?: number;
250
+ offset?: number;
251
+ }
252
+ interface WaitOptions {
253
+ minResponses: number;
254
+ timeoutMs?: number;
255
+ pollIntervalMs?: number;
256
+ sleep?: (ms: number) => Promise<void>;
257
+ now?: () => number;
258
+ }
259
+ declare class QueriesResource {
260
+ private readonly request;
261
+ constructor(request: RequestFn);
262
+ create(input: CreateQueryInput): Promise<Query>;
263
+ get(id: string): Promise<Query>;
264
+ list(params?: ListParams): Promise<QueryList>;
265
+ cancel(id: string): Promise<{
266
+ success: boolean;
267
+ message: string;
268
+ refund_amount_cents: number;
269
+ }>;
270
+ waitForResponses(id: string, opts: WaitOptions): Promise<QueryResponse[]>;
271
+ }
272
+
273
+ declare class ResponsesResource {
274
+ private readonly request;
275
+ constructor(request: RequestFn);
276
+ rate(queryId: string, responseId: string, input: {
277
+ score: number;
278
+ feedback_text?: string;
279
+ }): Promise<RatingResult>;
280
+ getRating(queryId: string, responseId: string): Promise<Rating>;
281
+ }
282
+
283
+ declare class AccountResource {
284
+ private readonly request;
285
+ constructor(request: RequestFn);
286
+ stats(): Promise<AccountStats>;
287
+ balance(): Promise<BillingInfo>;
288
+ }
289
+
290
+ declare class GetABrain {
291
+ readonly queries: QueriesResource;
292
+ readonly responses: ResponsesResource;
293
+ readonly account: AccountResource;
294
+ constructor(config: TransportConfig);
295
+ }
296
+
297
+ declare class GetABrainError extends Error {
298
+ readonly status: number;
299
+ readonly code: string;
300
+ readonly requestId?: string;
301
+ constructor(message: string, status: number, code?: string, requestId?: string);
302
+ }
303
+ declare class ValidationError extends GetABrainError {
304
+ }
305
+ declare class AuthError extends GetABrainError {
306
+ }
307
+ declare class InsufficientBalanceError extends GetABrainError {
308
+ }
309
+ declare class ForbiddenError extends GetABrainError {
310
+ }
311
+ declare class NotFoundError extends GetABrainError {
312
+ }
313
+ declare class ConflictError extends GetABrainError {
314
+ }
315
+ declare class ServerError extends GetABrainError {
316
+ }
317
+ declare class RateLimitError extends GetABrainError {
318
+ readonly retryAfterMs?: number;
319
+ constructor(message: string, status: number, code: string, retryAfterMs?: number, requestId?: string);
320
+ }
321
+ declare class TimeoutError extends GetABrainError {
322
+ constructor(message?: string);
323
+ }
324
+ declare class NetworkError extends GetABrainError {
325
+ constructor(message?: string);
326
+ }
327
+ declare function errorFromResponse(status: number, body: any, retryAfterMs?: number): GetABrainError;
328
+
329
+ export { type AbTestContent, AccountResource, type AccountStats, type AudioReviewContent, AuthError, type BillingInfo, ConflictError, type CreateQueryBase, type CreateQueryInput, DEFAULT_BASE_URL, ForbiddenError, type FreeFormTextContent, GetABrain, GetABrainError, type ImageAnalysisContent, type ImageComparisonContent, type ImageSelectionContent, InsufficientBalanceError, type ListParams, type MultipleChoiceContent, NetworkError, NotFoundError, QUERY_TYPES, QueriesResource, type Query, type QueryList, type QueryResponse, type QueryType, type RankingContent, RateLimitError, type Rating, type RatingResult, type RatingScaleContent, type RequestOptions, ResponsesResource, type SentimentContent, ServerError, type TextContent, TimeoutError, type TransportConfig, ValidationError, type VideoReviewContent, type WaitOptions, type YesNoContent, errorFromResponse };
package/dist/index.js ADDED
@@ -0,0 +1,249 @@
1
+ // src/errors.ts
2
+ var GetABrainError = class extends Error {
3
+ constructor(message, status, code = "error", requestId) {
4
+ super(message);
5
+ this.status = status;
6
+ this.code = code;
7
+ this.requestId = requestId;
8
+ this.name = new.target.name;
9
+ }
10
+ };
11
+ var ValidationError = class extends GetABrainError {
12
+ };
13
+ var AuthError = class extends GetABrainError {
14
+ };
15
+ var InsufficientBalanceError = class extends GetABrainError {
16
+ };
17
+ var ForbiddenError = class extends GetABrainError {
18
+ };
19
+ var NotFoundError = class extends GetABrainError {
20
+ };
21
+ var ConflictError = class extends GetABrainError {
22
+ };
23
+ var ServerError = class extends GetABrainError {
24
+ };
25
+ var RateLimitError = class extends GetABrainError {
26
+ constructor(message, status, code, retryAfterMs, requestId) {
27
+ super(message, status, code, requestId);
28
+ this.retryAfterMs = retryAfterMs;
29
+ }
30
+ };
31
+ var TimeoutError = class extends GetABrainError {
32
+ constructor(message = "Request timed out") {
33
+ super(message, 0, "timeout");
34
+ }
35
+ };
36
+ var NetworkError = class extends GetABrainError {
37
+ constructor(message = "Network request failed") {
38
+ super(message, 0, "network");
39
+ }
40
+ };
41
+ function errorFromResponse(status, body, retryAfterMs) {
42
+ const message = body && body.message || body && body.error || `HTTP ${status}`;
43
+ const code = body && body.error || "error";
44
+ switch (status) {
45
+ case 400:
46
+ return new ValidationError(message, status, code);
47
+ case 401:
48
+ return new AuthError(message, status, code);
49
+ case 402:
50
+ return new InsufficientBalanceError(message, status, code);
51
+ case 403:
52
+ return new ForbiddenError(message, status, code);
53
+ case 404:
54
+ return new NotFoundError(message, status, code);
55
+ case 409:
56
+ return new ConflictError(message, status, code);
57
+ case 429:
58
+ return new RateLimitError(message, status, code, retryAfterMs);
59
+ default:
60
+ if (status >= 500) return new ServerError(message, status, code);
61
+ return new GetABrainError(message, status, code);
62
+ }
63
+ }
64
+
65
+ // src/http.ts
66
+ var DEFAULT_BASE_URL = "https://www.getabrain.ai/api/v1";
67
+ var realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
68
+ function createTransport(config) {
69
+ var _a, _b, _c, _d, _e;
70
+ const baseUrl = ((_a = config.baseUrl) != null ? _a : DEFAULT_BASE_URL).replace(/\/+$/, "");
71
+ const doFetch = (_b = config.fetch) != null ? _b : globalThis.fetch;
72
+ const timeoutMs = (_c = config.timeoutMs) != null ? _c : 3e4;
73
+ const maxRetries = (_d = config.maxRetries) != null ? _d : 2;
74
+ const sleep = (_e = config.sleep) != null ? _e : realSleep;
75
+ if (typeof doFetch !== "function") {
76
+ throw new GetABrainError("No fetch available \u2014 use Node 18+ or pass { fetch }", 0, "config");
77
+ }
78
+ return async function request(method, path, opts = {}) {
79
+ const url = new URL(baseUrl + path);
80
+ if (opts.query) {
81
+ for (const [k, v] of Object.entries(opts.query)) if (v !== void 0) url.searchParams.set(k, String(v));
82
+ }
83
+ const isRead = method.toUpperCase() === "GET";
84
+ let attempt = 0;
85
+ for (; ; ) {
86
+ const controller = new AbortController();
87
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
88
+ let res;
89
+ try {
90
+ res = await doFetch(url.toString(), {
91
+ method,
92
+ headers: { "X-API-Key": config.apiKey, "X-API-Secret": config.apiSecret, "Content-Type": "application/json" },
93
+ body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0,
94
+ signal: controller.signal
95
+ });
96
+ } catch (err) {
97
+ clearTimeout(timer);
98
+ if ((err == null ? void 0 : err.name) === "AbortError") throw new TimeoutError();
99
+ if (isRead && attempt < maxRetries) {
100
+ attempt++;
101
+ await sleep(backoff(attempt));
102
+ continue;
103
+ }
104
+ throw new NetworkError((err == null ? void 0 : err.message) || "fetch failed");
105
+ }
106
+ clearTimeout(timer);
107
+ if (res.ok) {
108
+ if (res.status === 204) return void 0;
109
+ return await res.json();
110
+ }
111
+ const retryAfterMs = parseRetryAfter(res.headers.get("retry-after"));
112
+ if (isRead && (res.status === 429 || res.status >= 500) && attempt < maxRetries) {
113
+ attempt++;
114
+ await sleep(retryAfterMs != null ? retryAfterMs : backoff(attempt));
115
+ continue;
116
+ }
117
+ let body = null;
118
+ try {
119
+ body = await res.json();
120
+ } catch (e) {
121
+ }
122
+ throw errorFromResponse(res.status, body, retryAfterMs);
123
+ }
124
+ };
125
+ }
126
+ function backoff(attempt) {
127
+ return Math.min(1e3 * 2 ** (attempt - 1), 8e3);
128
+ }
129
+ function parseRetryAfter(h) {
130
+ if (!h) return void 0;
131
+ const n = Number(h);
132
+ return Number.isFinite(n) ? n * 1e3 : void 0;
133
+ }
134
+
135
+ // src/resources/queries.ts
136
+ var TERMINAL = /* @__PURE__ */ new Set(["completed", "cancelled", "failed", "expired"]);
137
+ var realSleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
138
+ var QueriesResource = class {
139
+ constructor(request) {
140
+ this.request = request;
141
+ }
142
+ create(input) {
143
+ return this.request("POST", "/requestor/queries", { body: input });
144
+ }
145
+ get(id) {
146
+ return this.request("GET", `/requestor/queries/${encodeURIComponent(id)}`);
147
+ }
148
+ list(params = {}) {
149
+ return this.request("GET", "/requestor/queries", { query: { status: params.status, limit: params.limit, offset: params.offset } });
150
+ }
151
+ cancel(id) {
152
+ return this.request("PUT", `/requestor/queries/${encodeURIComponent(id)}`, { body: { action: "cancel" } });
153
+ }
154
+ // Poll until `minResponses` responses arrive, the query reaches a terminal
155
+ // status, or the timeout elapses (throws TimeoutError).
156
+ async waitForResponses(id, opts) {
157
+ var _a, _b, _c, _d, _e, _f;
158
+ const timeoutMs = (_a = opts.timeoutMs) != null ? _a : 6e5;
159
+ const pollIntervalMs = (_b = opts.pollIntervalMs) != null ? _b : 5e3;
160
+ const sleep = (_c = opts.sleep) != null ? _c : realSleep2;
161
+ const now = (_d = opts.now) != null ? _d : Date.now;
162
+ const deadline = now() + timeoutMs;
163
+ for (; ; ) {
164
+ const query = await this.get(id);
165
+ const responses = (_e = query.responses) != null ? _e : [];
166
+ if (((_f = query.completed_responses) != null ? _f : responses.length) >= opts.minResponses) return responses;
167
+ if (TERMINAL.has(query.status)) return responses;
168
+ if (now() >= deadline) throw new TimeoutError(`waitForResponses timed out after ${timeoutMs}ms for query ${id}`);
169
+ await sleep(pollIntervalMs);
170
+ }
171
+ }
172
+ };
173
+
174
+ // src/resources/responses.ts
175
+ var ResponsesResource = class {
176
+ constructor(request) {
177
+ this.request = request;
178
+ }
179
+ rate(queryId, responseId, input) {
180
+ const q = encodeURIComponent(queryId);
181
+ const r = encodeURIComponent(responseId);
182
+ return this.request("POST", `/requestor/queries/${q}/responses/${r}/rate`, { body: input });
183
+ }
184
+ getRating(queryId, responseId) {
185
+ const q = encodeURIComponent(queryId);
186
+ const r = encodeURIComponent(responseId);
187
+ return this.request("GET", `/requestor/queries/${q}/responses/${r}/rate`);
188
+ }
189
+ };
190
+
191
+ // src/resources/account.ts
192
+ var AccountResource = class {
193
+ constructor(request) {
194
+ this.request = request;
195
+ }
196
+ stats() {
197
+ return this.request("GET", "/requestor/stats");
198
+ }
199
+ balance() {
200
+ return this.request("GET", "/requestor/billing");
201
+ }
202
+ };
203
+
204
+ // src/client.ts
205
+ var GetABrain = class {
206
+ constructor(config) {
207
+ const request = createTransport(config);
208
+ this.queries = new QueriesResource(request);
209
+ this.responses = new ResponsesResource(request);
210
+ this.account = new AccountResource(request);
211
+ }
212
+ };
213
+
214
+ // src/types.ts
215
+ var QUERY_TYPES = [
216
+ "text",
217
+ "multiple_choice",
218
+ "rating_scale",
219
+ "image_comparison",
220
+ "ranking",
221
+ "yes_no",
222
+ "sentiment",
223
+ "image_selection",
224
+ "free_form_text",
225
+ "video_review",
226
+ "audio_review",
227
+ "image_analysis",
228
+ "ab_test"
229
+ ];
230
+ export {
231
+ AccountResource,
232
+ AuthError,
233
+ ConflictError,
234
+ DEFAULT_BASE_URL,
235
+ ForbiddenError,
236
+ GetABrain,
237
+ GetABrainError,
238
+ InsufficientBalanceError,
239
+ NetworkError,
240
+ NotFoundError,
241
+ QUERY_TYPES,
242
+ QueriesResource,
243
+ RateLimitError,
244
+ ResponsesResource,
245
+ ServerError,
246
+ TimeoutError,
247
+ ValidationError,
248
+ errorFromResponse
249
+ };
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@getabrain/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Official Node/TypeScript SDK for the GetABrain.ai human-intelligence API",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
12
+ "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
13
+ }
14
+ },
15
+ "sideEffects": false,
16
+ "files": ["dist", "README.md"],
17
+ "scripts": {
18
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean --tsconfig tsconfig.build.json",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "engines": { "node": ">=18" },
22
+ "devDependencies": { "tsup": "^8.0.0" },
23
+ "license": "MIT"
24
+ }