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