@rainfall-devkit/sdk 0.2.3 → 0.2.4

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