@rainfall-devkit/sdk 0.2.2 → 0.2.3

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.
@@ -0,0 +1,989 @@
1
+ import {
2
+ NetworkError,
3
+ RainfallError,
4
+ TimeoutError,
5
+ ValidationError,
6
+ parseErrorResponse
7
+ } from "./chunk-LJQEO3CY.mjs";
8
+
9
+ // src/validation.ts
10
+ var schemaCache = /* @__PURE__ */ new Map();
11
+ var CACHE_TTL_MS = 5 * 60 * 1e3;
12
+ async function fetchToolSchema(client, toolId) {
13
+ const cached = schemaCache.get(toolId);
14
+ if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
15
+ return cached.schema;
16
+ }
17
+ const response = await client.request(
18
+ `/olympic/subscribers/me/nodes/${toolId}/params`
19
+ );
20
+ if (!response.success || !response.params) {
21
+ throw new ValidationError(`Failed to fetch schema for tool '${toolId}'`);
22
+ }
23
+ schemaCache.set(toolId, { schema: response.params, timestamp: Date.now() });
24
+ return response.params;
25
+ }
26
+ function clearSchemaCache() {
27
+ schemaCache.clear();
28
+ }
29
+ function validateParams(schema, params, toolId) {
30
+ const errors = [];
31
+ const parameters = schema.parameters || {};
32
+ for (const [key, paramSchema] of Object.entries(parameters)) {
33
+ if (paramSchema.optional !== true && !(key in (params || {}))) {
34
+ errors.push({
35
+ path: key,
36
+ message: `Missing required parameter '${key}'`,
37
+ expected: paramSchema.type
38
+ });
39
+ }
40
+ }
41
+ if (params) {
42
+ for (const [key, value] of Object.entries(params)) {
43
+ const paramSchema = parameters[key];
44
+ if (!paramSchema) {
45
+ errors.push({
46
+ path: key,
47
+ message: `Unknown parameter '${key}'`,
48
+ received: value
49
+ });
50
+ continue;
51
+ }
52
+ const typeError = validateType(key, value, paramSchema);
53
+ if (typeError) {
54
+ errors.push(typeError);
55
+ }
56
+ }
57
+ }
58
+ return {
59
+ valid: errors.length === 0,
60
+ errors
61
+ };
62
+ }
63
+ function validateType(path, value, schema) {
64
+ if (value === null || value === void 0) {
65
+ if (schema.optional === true) {
66
+ return null;
67
+ }
68
+ return {
69
+ path,
70
+ message: `Parameter '${path}' is required but received ${value}`,
71
+ received: value,
72
+ expected: schema.type
73
+ };
74
+ }
75
+ const expectedType = schema.type;
76
+ const actualType = getJsType(value);
77
+ switch (expectedType) {
78
+ case "string":
79
+ if (typeof value !== "string") {
80
+ return {
81
+ path,
82
+ message: `Parameter '${path}' must be a string, received ${actualType}`,
83
+ received: value,
84
+ expected: "string"
85
+ };
86
+ }
87
+ break;
88
+ case "number":
89
+ if (typeof value !== "number" || isNaN(value)) {
90
+ return {
91
+ path,
92
+ message: `Parameter '${path}' must be a number, received ${actualType}`,
93
+ received: value,
94
+ expected: "number"
95
+ };
96
+ }
97
+ break;
98
+ case "boolean":
99
+ if (typeof value !== "boolean") {
100
+ return {
101
+ path,
102
+ message: `Parameter '${path}' must be a boolean, received ${actualType}`,
103
+ received: value,
104
+ expected: "boolean"
105
+ };
106
+ }
107
+ break;
108
+ case "array":
109
+ if (!Array.isArray(value)) {
110
+ return {
111
+ path,
112
+ message: `Parameter '${path}' must be an array, received ${actualType}`,
113
+ received: value,
114
+ expected: "array"
115
+ };
116
+ }
117
+ if (schema.items) {
118
+ for (let i = 0; i < value.length; i++) {
119
+ const itemError = validateType(`${path}[${i}]`, value[i], schema.items);
120
+ if (itemError) {
121
+ return itemError;
122
+ }
123
+ }
124
+ }
125
+ break;
126
+ case "object":
127
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
128
+ return {
129
+ path,
130
+ message: `Parameter '${path}' must be an object, received ${actualType}`,
131
+ received: value,
132
+ expected: "object"
133
+ };
134
+ }
135
+ if (schema.properties) {
136
+ const objValue = value;
137
+ for (const [propKey, propSchema] of Object.entries(schema.properties)) {
138
+ if (objValue[propKey] !== void 0) {
139
+ const propError = validateType(`${path}.${propKey}`, objValue[propKey], propSchema);
140
+ if (propError) {
141
+ return propError;
142
+ }
143
+ }
144
+ }
145
+ }
146
+ break;
147
+ default:
148
+ break;
149
+ }
150
+ return null;
151
+ }
152
+ function getJsType(value) {
153
+ if (value === null) return "null";
154
+ if (Array.isArray(value)) return "array";
155
+ return typeof value;
156
+ }
157
+ function formatValidationErrors(result) {
158
+ if (result.valid) return "No validation errors";
159
+ const lines = result.errors.map((err) => {
160
+ let line = ` - ${err.message}`;
161
+ if (err.received !== void 0) {
162
+ line += ` (received: ${JSON.stringify(err.received).slice(0, 50)})`;
163
+ }
164
+ return line;
165
+ });
166
+ return `Validation failed with ${result.errors.length} error(s):
167
+ ${lines.join("\n")}`;
168
+ }
169
+
170
+ // src/client.ts
171
+ var DEFAULT_BASE_URL = "https://olympic-api.pragma-digital.org/v1";
172
+ var DEFAULT_TIMEOUT = 3e4;
173
+ var DEFAULT_RETRIES = 3;
174
+ var DEFAULT_RETRY_DELAY = 1e3;
175
+ var RainfallClient = class {
176
+ apiKey;
177
+ baseUrl;
178
+ defaultTimeout;
179
+ defaultRetries;
180
+ defaultRetryDelay;
181
+ disableValidation;
182
+ lastRateLimitInfo;
183
+ subscriberId;
184
+ constructor(config) {
185
+ this.apiKey = config.apiKey;
186
+ this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
187
+ this.defaultTimeout = config.timeout || DEFAULT_TIMEOUT;
188
+ this.defaultRetries = config.retries ?? DEFAULT_RETRIES;
189
+ this.defaultRetryDelay = config.retryDelay || DEFAULT_RETRY_DELAY;
190
+ this.disableValidation = config.disableValidation ?? false;
191
+ }
192
+ /**
193
+ * Get the last rate limit info from the API
194
+ */
195
+ getRateLimitInfo() {
196
+ return this.lastRateLimitInfo;
197
+ }
198
+ /**
199
+ * Make an authenticated request to the Rainfall API
200
+ */
201
+ async request(path, options = {}, requestOptions) {
202
+ const timeout = requestOptions?.timeout ?? this.defaultTimeout;
203
+ const maxRetries = requestOptions?.retries ?? this.defaultRetries;
204
+ const retryDelay = requestOptions?.retryDelay ?? this.defaultRetryDelay;
205
+ const url = `${this.baseUrl}${path}`;
206
+ const method = options.method || "GET";
207
+ let lastError;
208
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
209
+ try {
210
+ const controller = new AbortController();
211
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
212
+ const response = await fetch(url, {
213
+ method,
214
+ headers: {
215
+ "x-api-key": this.apiKey,
216
+ "Content-Type": "application/json",
217
+ "Accept": "application/json",
218
+ "X-Rainfall-SDK-Version": "0.1.0",
219
+ ...options.headers
220
+ },
221
+ body: options.body ? JSON.stringify(options.body) : void 0,
222
+ signal: controller.signal
223
+ });
224
+ clearTimeout(timeoutId);
225
+ const limit = response.headers.get("x-ratelimit-limit");
226
+ const remaining = response.headers.get("x-ratelimit-remaining");
227
+ const reset = response.headers.get("x-ratelimit-reset");
228
+ if (limit && remaining && reset) {
229
+ this.lastRateLimitInfo = {
230
+ limit: parseInt(limit, 10),
231
+ remaining: parseInt(remaining, 10),
232
+ resetAt: new Date(parseInt(reset, 10) * 1e3)
233
+ };
234
+ }
235
+ let data;
236
+ const contentType = response.headers.get("content-type");
237
+ if (contentType?.includes("application/json")) {
238
+ data = await response.json();
239
+ } else {
240
+ data = await response.text();
241
+ }
242
+ if (!response.ok) {
243
+ throw parseErrorResponse(response, data);
244
+ }
245
+ return data;
246
+ } catch (error) {
247
+ if (error instanceof RainfallError) {
248
+ if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {
249
+ throw error;
250
+ }
251
+ if (error.statusCode === 401) {
252
+ throw error;
253
+ }
254
+ }
255
+ if (error instanceof Error && error.name === "AbortError") {
256
+ lastError = new TimeoutError(timeout);
257
+ } else if (error instanceof TypeError) {
258
+ lastError = new NetworkError(error.message);
259
+ } else {
260
+ lastError = error instanceof Error ? error : new Error(String(error));
261
+ }
262
+ if (attempt >= maxRetries) {
263
+ break;
264
+ }
265
+ const delay = retryDelay * Math.pow(2, attempt) + Math.random() * 1e3;
266
+ await this.sleep(delay);
267
+ }
268
+ }
269
+ throw lastError || new RainfallError("Request failed", "REQUEST_FAILED");
270
+ }
271
+ /**
272
+ * Execute a tool/node by ID
273
+ *
274
+ * @param toolId - The ID of the tool/node to execute
275
+ * @param params - Parameters to pass to the tool
276
+ * @param options - Request options including skipValidation to bypass param validation
277
+ */
278
+ async executeTool(toolId, params, options) {
279
+ if (!this.disableValidation && !options?.skipValidation) {
280
+ const validation = await this.validateToolParams(toolId, params);
281
+ if (!validation.valid) {
282
+ const { ValidationError: ValidationError2 } = await import("./errors-CY6HW2I5.mjs");
283
+ throw new ValidationError2(
284
+ `Parameter validation failed for tool '${toolId}': ${formatValidationErrors(validation)}`,
285
+ { toolId, errors: validation.errors }
286
+ );
287
+ }
288
+ }
289
+ const subscriberId = await this.ensureSubscriberId();
290
+ const response = await this.request(`/olympic/subscribers/${subscriberId}/nodes/${toolId}`, {
291
+ method: "POST",
292
+ body: params || {}
293
+ }, options);
294
+ if (response.success === false) {
295
+ const errorMessage = typeof response.error === "string" ? response.error : JSON.stringify(response.error);
296
+ throw new RainfallError(
297
+ `Tool execution failed: ${errorMessage}`,
298
+ "TOOL_EXECUTION_ERROR",
299
+ 400,
300
+ { toolId, error: response.error }
301
+ );
302
+ }
303
+ return response.result;
304
+ }
305
+ /**
306
+ * Validate parameters for a tool without executing it
307
+ * Fetches the tool schema and validates the provided params
308
+ *
309
+ * @param toolId - The ID of the tool to validate params for
310
+ * @param params - Parameters to validate
311
+ * @returns Validation result with detailed error information
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * const result = await client.validateToolParams('finviz-quotes', { tickers: ['AAPL'] });
316
+ * if (!result.valid) {
317
+ * console.log('Validation errors:', result.errors);
318
+ * }
319
+ * ```
320
+ */
321
+ async validateToolParams(toolId, params) {
322
+ try {
323
+ const schema = await fetchToolSchema(this, toolId);
324
+ return validateParams(schema, params, toolId);
325
+ } catch (error) {
326
+ if (error instanceof RainfallError && error.statusCode === 404) {
327
+ return {
328
+ valid: false,
329
+ errors: [{ path: toolId, message: `Tool '${toolId}' not found` }]
330
+ };
331
+ }
332
+ return { valid: true, errors: [] };
333
+ }
334
+ }
335
+ /**
336
+ * List all available tools
337
+ */
338
+ async listTools() {
339
+ const subscriberId = await this.ensureSubscriberId();
340
+ const result = await this.request(`/olympic/subscribers/${subscriberId}/nodes/_utils/node-descriptions`);
341
+ if (result.success && result.nodes) {
342
+ return Object.values(result.nodes);
343
+ }
344
+ const legacyResult = await this.request(`/olympic/subscribers/${subscriberId}/nodes/_utils/node-list`);
345
+ if (legacyResult.keys && Array.isArray(legacyResult.keys)) {
346
+ return legacyResult.keys.map((key) => ({
347
+ id: key,
348
+ name: key,
349
+ description: "",
350
+ category: "general"
351
+ }));
352
+ }
353
+ return legacyResult.nodes || [];
354
+ }
355
+ /**
356
+ * Get tool schema/parameters
357
+ *
358
+ * @param toolId - The ID of the tool to get schema for
359
+ * @returns Tool schema including parameters and output definitions
360
+ */
361
+ async getToolSchema(toolId) {
362
+ const schema = await fetchToolSchema(this, toolId);
363
+ return {
364
+ name: schema.name,
365
+ description: schema.description,
366
+ category: schema.category,
367
+ parameters: schema.parameters,
368
+ output: schema.output,
369
+ metadata: schema.metadata || {}
370
+ };
371
+ }
372
+ /**
373
+ * Get subscriber info
374
+ */
375
+ async getMe() {
376
+ const result = await this.request("/olympic/subscribers/me");
377
+ if (result.subscriber?.id) {
378
+ this.subscriberId = result.subscriber.id;
379
+ }
380
+ const subscriber = result.subscriber;
381
+ return {
382
+ id: subscriber.id,
383
+ name: subscriber.name,
384
+ email: subscriber.google_id,
385
+ billingStatus: subscriber.billing_status,
386
+ plan: subscriber.billing_status,
387
+ usage: {
388
+ callsThisMonth: subscriber.metadata?.usage?.callsThisMonth ?? 0,
389
+ callsLimit: subscriber.metadata?.usage?.callsLimit ?? 5e3
390
+ }
391
+ };
392
+ }
393
+ /**
394
+ * Ensure we have a subscriber ID, fetching it if necessary
395
+ */
396
+ async ensureSubscriberId() {
397
+ if (this.subscriberId) {
398
+ return this.subscriberId;
399
+ }
400
+ const me = await this.getMe();
401
+ if (!me.id) {
402
+ throw new RainfallError("Failed to get subscriber ID", "NO_SUBSCRIBER_ID");
403
+ }
404
+ return me.id;
405
+ }
406
+ sleep(ms) {
407
+ return new Promise((resolve) => setTimeout(resolve, ms));
408
+ }
409
+ /**
410
+ * OpenAI-compatible chat completions with tool support
411
+ */
412
+ async chatCompletions(params) {
413
+ const { subscriber_id, ...body } = params;
414
+ if (body.stream) {
415
+ const url = `${this.baseUrl}/olympic/subscribers/${subscriber_id}/v1/chat/completions`;
416
+ const response = await fetch(url, {
417
+ method: "POST",
418
+ headers: {
419
+ "x-api-key": this.apiKey,
420
+ "Content-Type": "application/json",
421
+ "Accept": "text/event-stream"
422
+ },
423
+ body: JSON.stringify(body)
424
+ });
425
+ if (!response.ok) {
426
+ const error = await response.text();
427
+ throw new RainfallError(`Chat completions failed: ${error}`, "CHAT_ERROR");
428
+ }
429
+ if (!response.body) {
430
+ throw new RainfallError("No response body", "CHAT_ERROR");
431
+ }
432
+ return response.body;
433
+ }
434
+ return this.request(
435
+ `/olympic/subscribers/${subscriber_id}/v1/chat/completions`,
436
+ {
437
+ method: "POST",
438
+ body
439
+ }
440
+ );
441
+ }
442
+ /**
443
+ * List available models (OpenAI-compatible format)
444
+ */
445
+ async listModels(subscriberId) {
446
+ const sid = subscriberId || this.subscriberId || await this.ensureSubscriberId();
447
+ const result = await this.request(
448
+ `/olympic/subscribers/${sid}/v1/models`
449
+ );
450
+ return result.data || [];
451
+ }
452
+ };
453
+
454
+ // src/namespaces/integrations.ts
455
+ function createIntegrations(client) {
456
+ return new IntegrationsNamespace(client);
457
+ }
458
+ var IntegrationsNamespace = class {
459
+ constructor(client) {
460
+ this.client = client;
461
+ }
462
+ get github() {
463
+ return {
464
+ issues: {
465
+ create: (params) => this.client.executeTool("github-create-issue", params),
466
+ list: (params) => this.client.executeTool("github-list-issues", params),
467
+ get: (params) => this.client.executeTool("github-get-issue", params),
468
+ update: (params) => this.client.executeTool("github-update-issue", params),
469
+ addComment: (params) => this.client.executeTool("github-add-issue-comment", params)
470
+ },
471
+ repos: {
472
+ get: (params) => this.client.executeTool("github-get-repository", params),
473
+ listBranches: (params) => this.client.executeTool("github-list-branches", params)
474
+ },
475
+ pullRequests: {
476
+ list: (params) => this.client.executeTool("github-list-pull-requests", params),
477
+ get: (params) => this.client.executeTool("github-get-pull-request", params)
478
+ }
479
+ };
480
+ }
481
+ get notion() {
482
+ return {
483
+ pages: {
484
+ create: (params) => this.client.executeTool("notion-pages-create", params),
485
+ retrieve: (params) => this.client.executeTool("notion-pages-retrieve", params),
486
+ update: (params) => this.client.executeTool("notion-pages-update", params)
487
+ },
488
+ databases: {
489
+ query: (params) => this.client.executeTool("notion-databases-query", params),
490
+ retrieve: (params) => this.client.executeTool("notion-databases-retrieve", params)
491
+ },
492
+ blocks: {
493
+ appendChildren: (params) => this.client.executeTool("notion-blocks-append-children", params),
494
+ retrieveChildren: (params) => this.client.executeTool("notion-blocks-retrieve-children", params)
495
+ }
496
+ };
497
+ }
498
+ get linear() {
499
+ return {
500
+ issues: {
501
+ create: (params) => this.client.executeTool("linear-core-issueCreate", params),
502
+ list: (params) => this.client.executeTool("linear-core-issues", params),
503
+ get: (params) => this.client.executeTool("linear-core-issue", params),
504
+ update: (params) => this.client.executeTool("linear-core-issueUpdate", params),
505
+ archive: (params) => this.client.executeTool("linear-core-issueArchive", params)
506
+ },
507
+ teams: {
508
+ list: () => this.client.executeTool("linear-core-teams", {})
509
+ }
510
+ };
511
+ }
512
+ get slack() {
513
+ return {
514
+ messages: {
515
+ send: (params) => this.client.executeTool("slack-core-postMessage", params),
516
+ list: (params) => this.client.executeTool("slack-core-listMessages", params)
517
+ },
518
+ channels: {
519
+ list: () => this.client.executeTool("slack-core-listChannels", {})
520
+ },
521
+ users: {
522
+ list: () => this.client.executeTool("slack-core-listUsers", {})
523
+ },
524
+ reactions: {
525
+ add: (params) => this.client.executeTool("slack-core-addReaction", params)
526
+ }
527
+ };
528
+ }
529
+ get figma() {
530
+ return {
531
+ files: {
532
+ get: (params) => this.client.executeTool("figma-files-getFile", { fileKey: params.fileKey }),
533
+ getNodes: (params) => this.client.executeTool("figma-files-getFileNodes", { fileKey: params.fileKey, nodeIds: params.nodeIds }),
534
+ getImages: (params) => this.client.executeTool("figma-files-getFileImage", { fileKey: params.fileKey, nodeIds: params.nodeIds, format: params.format }),
535
+ getComments: (params) => this.client.executeTool("figma-comments-getFileComments", { fileKey: params.fileKey }),
536
+ postComment: (params) => this.client.executeTool("figma-comments-postComment", { fileKey: params.fileKey, message: params.message, nodeId: params.nodeId })
537
+ },
538
+ projects: {
539
+ list: (params) => this.client.executeTool("figma-projects-getTeamProjects", { teamId: params.teamId }),
540
+ getFiles: (params) => this.client.executeTool("figma-projects-getProjectFiles", { projectId: params.projectId })
541
+ }
542
+ };
543
+ }
544
+ get stripe() {
545
+ return {
546
+ customers: {
547
+ create: (params) => this.client.executeTool("stripe-customers-create", params),
548
+ retrieve: (params) => this.client.executeTool("stripe-customers-retrieve", { customerId: params.customerId }),
549
+ update: (params) => this.client.executeTool("stripe-customers-update", params),
550
+ listPaymentMethods: (params) => this.client.executeTool("stripe-customers-list-payment-methods", { customerId: params.customerId })
551
+ },
552
+ paymentIntents: {
553
+ create: (params) => this.client.executeTool("stripe-payment-intents-create", params),
554
+ retrieve: (params) => this.client.executeTool("stripe-payment-intents-retrieve", { paymentIntentId: params.paymentIntentId }),
555
+ confirm: (params) => this.client.executeTool("stripe-payment-intents-confirm", { paymentIntentId: params.paymentIntentId })
556
+ },
557
+ subscriptions: {
558
+ create: (params) => this.client.executeTool("stripe-subscriptions-create", params),
559
+ retrieve: (params) => this.client.executeTool("stripe-subscriptions-retrieve", { subscriptionId: params.subscriptionId }),
560
+ cancel: (params) => this.client.executeTool("stripe-subscriptions-cancel", { subscriptionId: params.subscriptionId })
561
+ }
562
+ };
563
+ }
564
+ };
565
+
566
+ // src/namespaces/memory.ts
567
+ function createMemory(client) {
568
+ return {
569
+ create: (params) => client.executeTool("memory-create", params),
570
+ get: (params) => client.executeTool("memory-get", { memoryId: params.memoryId }),
571
+ recall: (params) => client.executeTool("memory-recall", params),
572
+ list: (params) => client.executeTool("memory-list", params ?? {}),
573
+ update: (params) => client.executeTool("memory-update", params),
574
+ delete: (params) => client.executeTool("memory-delete", { memoryId: params.memoryId })
575
+ };
576
+ }
577
+
578
+ // src/namespaces/articles.ts
579
+ function createArticles(client) {
580
+ return {
581
+ search: (params) => client.executeTool("article-search", params),
582
+ create: (params) => client.executeTool("article-create", params),
583
+ createFromUrl: (params) => client.executeTool("article-create-from-url", params),
584
+ fetch: (params) => client.executeTool("article-fetch", params),
585
+ recent: (params) => client.executeTool("article-recent", params ?? {}),
586
+ relevant: (params) => client.executeTool("article-relevant-news", params),
587
+ summarize: (params) => client.executeTool("article-summarize", params),
588
+ extractTopics: (params) => client.executeTool("article-topic-extractor", params)
589
+ };
590
+ }
591
+
592
+ // src/namespaces/web.ts
593
+ function createWeb(client) {
594
+ return {
595
+ search: {
596
+ exa: (params) => client.executeTool("exa-web-search", params),
597
+ perplexity: (params) => client.executeTool("perplexity-search", params)
598
+ },
599
+ fetch: (params) => client.executeTool("web-fetch", params),
600
+ htmlToMarkdown: (params) => client.executeTool("html-to-markdown-converter", params),
601
+ extractHtml: (params) => client.executeTool("extract-html-selector", params)
602
+ };
603
+ }
604
+
605
+ // src/namespaces/ai.ts
606
+ function createAI(client) {
607
+ return {
608
+ embeddings: {
609
+ document: (params) => client.executeTool("jina-document-embedding", params),
610
+ query: (params) => client.executeTool("jina-query-embedding", params),
611
+ image: (params) => client.executeTool("jina-image-embedding", { image: params.imageBase64 })
612
+ },
613
+ image: {
614
+ generate: (params) => client.executeTool("image-generation", params)
615
+ },
616
+ ocr: (params) => client.executeTool("ocr-text-extraction", { image: params.imageBase64 }),
617
+ vision: (params) => client.executeTool("llama-scout-vision", { image: params.imageBase64, prompt: params.prompt }),
618
+ chat: (params) => client.executeTool("xai-chat-completions", params),
619
+ complete: (params) => client.executeTool("fim", params),
620
+ classify: (params) => client.executeTool("jina-document-classifier", params),
621
+ segment: (params) => client.executeTool("jina-text-segmenter", params),
622
+ /**
623
+ * OpenAI-compatible chat completions with full tool support
624
+ * This is the recommended method for multi-turn conversations with tools
625
+ */
626
+ chatCompletions: (params) => client.chatCompletions(params)
627
+ };
628
+ }
629
+
630
+ // src/namespaces/data.ts
631
+ function createData(client) {
632
+ return {
633
+ csv: {
634
+ query: (params) => client.executeTool("query-csv", params),
635
+ convert: (params) => client.executeTool("csv-convert", params)
636
+ },
637
+ scripts: {
638
+ create: (params) => client.executeTool("create-saved-script", params),
639
+ execute: (params) => client.executeTool("execute-saved-script", params),
640
+ list: () => client.executeTool("list-saved-scripts", {}),
641
+ update: (params) => client.executeTool("update-saved-script", params),
642
+ delete: (params) => client.executeTool("delete-saved-script", params)
643
+ },
644
+ similarity: {
645
+ search: (params) => client.executeTool("duck-db-similarity-search", params),
646
+ duckDbSearch: (params) => client.executeTool("duck-db-similarity-search", params)
647
+ }
648
+ };
649
+ }
650
+
651
+ // src/namespaces/utils.ts
652
+ function createUtils(client) {
653
+ return {
654
+ mermaid: (params) => client.executeTool("mermaid-diagram-generator", { mermaid: params.diagram }),
655
+ documentConvert: (params) => client.executeTool("document-format-converter", {
656
+ base64: `data:${params.mimeType};base64,${Buffer.from(params.document).toString("base64")}`,
657
+ format: params.format
658
+ }),
659
+ regex: {
660
+ match: (params) => client.executeTool("regex-match", params),
661
+ replace: (params) => client.executeTool("regex-replace", params)
662
+ },
663
+ jsonExtract: (params) => client.executeTool("json-extract", params),
664
+ digest: (params) => client.executeTool("digest-generator", { text: params.data }),
665
+ monteCarlo: (params) => client.executeTool("monte-carlo-simulation", params)
666
+ };
667
+ }
668
+
669
+ // src/sdk.ts
670
+ var Rainfall = class {
671
+ client;
672
+ _integrations;
673
+ _memory;
674
+ _articles;
675
+ _web;
676
+ _ai;
677
+ _data;
678
+ _utils;
679
+ constructor(config) {
680
+ this.client = new RainfallClient(config);
681
+ }
682
+ /**
683
+ * Integrations namespace - GitHub, Notion, Linear, Slack, Figma, Stripe
684
+ *
685
+ * @example
686
+ * ```typescript
687
+ * // GitHub
688
+ * await rainfall.integrations.github.issues.create({
689
+ * owner: 'facebook',
690
+ * repo: 'react',
691
+ * title: 'Bug report'
692
+ * });
693
+ *
694
+ * // Slack
695
+ * await rainfall.integrations.slack.messages.send({
696
+ * channelId: 'C123456',
697
+ * text: 'Hello team!'
698
+ * });
699
+ *
700
+ * // Linear
701
+ * const issues = await rainfall.integrations.linear.issues.list();
702
+ * ```
703
+ */
704
+ get integrations() {
705
+ if (!this._integrations) {
706
+ this._integrations = createIntegrations(this.client);
707
+ }
708
+ return this._integrations;
709
+ }
710
+ /**
711
+ * Memory namespace - Semantic memory storage and retrieval
712
+ *
713
+ * @example
714
+ * ```typescript
715
+ * // Store a memory
716
+ * await rainfall.memory.create({
717
+ * content: 'User prefers dark mode',
718
+ * keywords: ['preference', 'ui']
719
+ * });
720
+ *
721
+ * // Recall similar memories
722
+ * const memories = await rainfall.memory.recall({
723
+ * query: 'user preferences',
724
+ * topK: 5
725
+ * });
726
+ * ```
727
+ */
728
+ get memory() {
729
+ if (!this._memory) {
730
+ this._memory = createMemory(this.client);
731
+ }
732
+ return this._memory;
733
+ }
734
+ /**
735
+ * Articles namespace - News aggregation and article management
736
+ *
737
+ * @example
738
+ * ```typescript
739
+ * // Search news
740
+ * const articles = await rainfall.articles.search({
741
+ * query: 'artificial intelligence'
742
+ * });
743
+ *
744
+ * // Create from URL
745
+ * const article = await rainfall.articles.createFromUrl({
746
+ * url: 'https://example.com/article'
747
+ * });
748
+ *
749
+ * // Summarize
750
+ * const summary = await rainfall.articles.summarize({
751
+ * text: article.content
752
+ * });
753
+ * ```
754
+ */
755
+ get articles() {
756
+ if (!this._articles) {
757
+ this._articles = createArticles(this.client);
758
+ }
759
+ return this._articles;
760
+ }
761
+ /**
762
+ * Web namespace - Web search, scraping, and content extraction
763
+ *
764
+ * @example
765
+ * ```typescript
766
+ * // Search with Exa
767
+ * const results = await rainfall.web.search.exa({
768
+ * query: 'latest AI research'
769
+ * });
770
+ *
771
+ * // Fetch and convert
772
+ * const html = await rainfall.web.fetch({ url: 'https://example.com' });
773
+ * const markdown = await rainfall.web.htmlToMarkdown({ html });
774
+ *
775
+ * // Extract specific elements
776
+ * const links = await rainfall.web.extractHtml({
777
+ * html,
778
+ * selector: 'a[href]'
779
+ * });
780
+ * ```
781
+ */
782
+ get web() {
783
+ if (!this._web) {
784
+ this._web = createWeb(this.client);
785
+ }
786
+ return this._web;
787
+ }
788
+ /**
789
+ * AI namespace - Embeddings, image generation, OCR, vision, chat
790
+ *
791
+ * @example
792
+ * ```typescript
793
+ * // Generate embeddings
794
+ * const embedding = await rainfall.ai.embeddings.document({
795
+ * text: 'Hello world'
796
+ * });
797
+ *
798
+ * // Generate image
799
+ * const image = await rainfall.ai.image.generate({
800
+ * prompt: 'A serene mountain landscape'
801
+ * });
802
+ *
803
+ * // OCR
804
+ * const text = await rainfall.ai.ocr({ imageBase64: '...' });
805
+ *
806
+ * // Chat
807
+ * const response = await rainfall.ai.chat({
808
+ * messages: [{ role: 'user', content: 'Hello!' }]
809
+ * });
810
+ * ```
811
+ */
812
+ get ai() {
813
+ if (!this._ai) {
814
+ this._ai = createAI(this.client);
815
+ }
816
+ return this._ai;
817
+ }
818
+ /**
819
+ * Data namespace - CSV processing, scripts, similarity search
820
+ *
821
+ * @example
822
+ * ```typescript
823
+ * // Query CSV with SQL
824
+ * const results = await rainfall.data.csv.query({
825
+ * sql: 'SELECT * FROM data WHERE value > 100'
826
+ * });
827
+ *
828
+ * // Execute saved script
829
+ * const result = await rainfall.data.scripts.execute({
830
+ * name: 'my-script',
831
+ * params: { input: 'data' }
832
+ * });
833
+ * ```
834
+ */
835
+ get data() {
836
+ if (!this._data) {
837
+ this._data = createData(this.client);
838
+ }
839
+ return this._data;
840
+ }
841
+ /**
842
+ * Utils namespace - Mermaid diagrams, document conversion, regex, JSON extraction
843
+ *
844
+ * @example
845
+ * ```typescript
846
+ * // Generate diagram
847
+ * const diagram = await rainfall.utils.mermaid({
848
+ * diagram: 'graph TD; A-->B;'
849
+ * });
850
+ *
851
+ * // Convert document
852
+ * const pdf = await rainfall.utils.documentConvert({
853
+ * document: markdownContent,
854
+ * mimeType: 'text/markdown',
855
+ * format: 'pdf'
856
+ * });
857
+ *
858
+ * // Extract JSON from text
859
+ * const json = await rainfall.utils.jsonExtract({
860
+ * text: 'Here is some data: {"key": "value"}'
861
+ * });
862
+ * ```
863
+ */
864
+ get utils() {
865
+ if (!this._utils) {
866
+ this._utils = createUtils(this.client);
867
+ }
868
+ return this._utils;
869
+ }
870
+ /**
871
+ * Get the underlying HTTP client for advanced usage
872
+ */
873
+ getClient() {
874
+ return this.client;
875
+ }
876
+ /**
877
+ * List all available tools
878
+ */
879
+ async listTools() {
880
+ return this.client.listTools();
881
+ }
882
+ /**
883
+ * Get schema for a specific tool
884
+ */
885
+ async getToolSchema(toolId) {
886
+ return this.client.getToolSchema(toolId);
887
+ }
888
+ /**
889
+ * Execute any tool by ID (low-level access)
890
+ *
891
+ * @param toolId - The ID of the tool to execute
892
+ * @param params - Parameters to pass to the tool
893
+ * @param options - Execution options including skipValidation to bypass param validation
894
+ *
895
+ * @example
896
+ * ```typescript
897
+ * // Execute with validation (default)
898
+ * const result = await rainfall.executeTool('finviz-quotes', { tickers: ['AAPL'] });
899
+ *
900
+ * // Execute without validation
901
+ * const result = await rainfall.executeTool('finviz-quotes', { tickers: ['AAPL'] }, { skipValidation: true });
902
+ * ```
903
+ */
904
+ async executeTool(toolId, params, options) {
905
+ return this.client.executeTool(toolId, params, options);
906
+ }
907
+ /**
908
+ * Validate parameters for a tool without executing it
909
+ *
910
+ * @param toolId - The ID of the tool to validate params for
911
+ * @param params - Parameters to validate
912
+ * @returns Validation result with detailed error information
913
+ *
914
+ * @example
915
+ * ```typescript
916
+ * const result = await rainfall.validateToolParams('finviz-quotes', { tickers: ['AAPL'] });
917
+ * if (!result.valid) {
918
+ * console.log('Validation errors:', result.errors);
919
+ * }
920
+ * ```
921
+ */
922
+ async validateToolParams(toolId, params) {
923
+ return this.client.validateToolParams(toolId, params);
924
+ }
925
+ /**
926
+ * Get current subscriber info and usage
927
+ */
928
+ async getMe() {
929
+ return this.client.getMe();
930
+ }
931
+ /**
932
+ * Get current rate limit info
933
+ */
934
+ getRateLimitInfo() {
935
+ return this.client.getRateLimitInfo();
936
+ }
937
+ /**
938
+ * OpenAI-compatible chat completions with tool support
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * // Simple chat
943
+ * const response = await rainfall.chatCompletions({
944
+ * subscriber_id: 'my-subscriber',
945
+ * messages: [{ role: 'user', content: 'Hello!' }],
946
+ * model: 'llama-3.3-70b-versatile'
947
+ * });
948
+ *
949
+ * // With tools
950
+ * const response = await rainfall.chatCompletions({
951
+ * subscriber_id: 'my-subscriber',
952
+ * messages: [{ role: 'user', content: 'Search for AI news' }],
953
+ * tools: [{ type: 'function', function: { name: 'web-search' } }],
954
+ * enable_stacked: true
955
+ * });
956
+ *
957
+ * // Streaming
958
+ * const stream = await rainfall.chatCompletions({
959
+ * subscriber_id: 'my-subscriber',
960
+ * messages: [{ role: 'user', content: 'Tell me a story' }],
961
+ * stream: true
962
+ * });
963
+ * ```
964
+ */
965
+ async chatCompletions(params) {
966
+ return this.client.chatCompletions(params);
967
+ }
968
+ /**
969
+ * List available models (OpenAI-compatible format)
970
+ *
971
+ * @example
972
+ * ```typescript
973
+ * const models = await rainfall.listModels();
974
+ * console.log(models); // [{ id: 'llama-3.3-70b-versatile', ... }]
975
+ * ```
976
+ */
977
+ async listModels(subscriberId) {
978
+ return this.client.listModels(subscriberId);
979
+ }
980
+ };
981
+
982
+ export {
983
+ fetchToolSchema,
984
+ clearSchemaCache,
985
+ validateParams,
986
+ formatValidationErrors,
987
+ RainfallClient,
988
+ Rainfall
989
+ };