@synova-cloud/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Synova Cloud
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,475 @@
1
+ # Synova Cloud SDK for Node.js
2
+
3
+ Official Node.js SDK for the [Synova Cloud](https://synova.cloud) API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @synova-cloud/sdk
9
+ # or
10
+ yarn add @synova-cloud/sdk
11
+ # or
12
+ pnpm add @synova-cloud/sdk
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { SynovaCloudSdk } from '@synova-cloud/sdk';
19
+
20
+ const client = new SynovaCloudSdk('your-api-key');
21
+
22
+ // Execute a prompt
23
+ const response = await client.prompts.execute('prm_abc123', {
24
+ provider: 'openai',
25
+ model: 'gpt-4o',
26
+ variables: { name: 'World' },
27
+ });
28
+
29
+ console.log(response.content);
30
+ ```
31
+
32
+ ## Configuration
33
+
34
+ ```typescript
35
+ import { SynovaCloudSdk } from '@synova-cloud/sdk';
36
+
37
+ const client = new SynovaCloudSdk('your-api-key', {
38
+ baseUrl: 'https://api.synova.cloud', // Custom API URL
39
+ timeout: 30000, // Request timeout in ms (default: 30000)
40
+ debug: true, // Enable debug logging
41
+ retry: {
42
+ maxRetries: 3, // Max retry attempts (default: 3)
43
+ strategy: 'exponential', // 'exponential' or 'linear' (default: 'exponential')
44
+ initialDelayMs: 1000, // Initial retry delay (default: 1000)
45
+ maxDelayMs: 30000, // Max retry delay (default: 30000)
46
+ backoffMultiplier: 2, // Multiplier for exponential backoff (default: 2)
47
+ },
48
+ });
49
+ ```
50
+
51
+ ## API Reference
52
+
53
+ ### Prompts
54
+
55
+ #### Get Prompt
56
+
57
+ Retrieve a prompt template by ID.
58
+
59
+ ```typescript
60
+ // Get latest version (default)
61
+ const prompt = await client.prompts.get('prm_abc123');
62
+
63
+ // Get by tag
64
+ const prompt = await client.prompts.get('prm_abc123', { tag: 'production' });
65
+
66
+ // Get specific version
67
+ const prompt = await client.prompts.get('prm_abc123', { version: '1.2.0' });
68
+ ```
69
+
70
+ #### Execute Prompt
71
+
72
+ Execute a prompt with an LLM provider.
73
+
74
+ ```typescript
75
+ const response = await client.prompts.execute('prm_abc123', {
76
+ provider: 'openai', // Required: 'openai', 'anthropic', 'google', etc.
77
+ model: 'gpt-4o', // Required: model ID
78
+ variables: { // Optional: template variables
79
+ userMessage: 'Hello!',
80
+ },
81
+ });
82
+
83
+ console.log(response.content); // LLM response text
84
+ console.log(response.usage); // { inputTokens, outputTokens, totalTokens }
85
+ ```
86
+
87
+ #### Execute with Tag or Version
88
+
89
+ ```typescript
90
+ // Execute specific tag
91
+ const response = await client.prompts.execute('prm_abc123', {
92
+ provider: 'anthropic',
93
+ model: 'claude-sonnet-4-20250514',
94
+ tag: 'production',
95
+ variables: { topic: 'AI' },
96
+ });
97
+
98
+ // Execute specific version
99
+ const response = await client.prompts.execute('prm_abc123', {
100
+ provider: 'openai',
101
+ model: 'gpt-4o',
102
+ version: '1.2.0',
103
+ variables: { topic: 'AI' },
104
+ });
105
+ ```
106
+
107
+ #### With Model Parameters
108
+
109
+ ```typescript
110
+ const response = await client.prompts.execute('prm_abc123', {
111
+ provider: 'openai',
112
+ model: 'gpt-4o',
113
+ variables: { topic: 'TypeScript' },
114
+ parameters: {
115
+ temperature: 0.7,
116
+ maxTokens: 1000,
117
+ topP: 0.9,
118
+ },
119
+ });
120
+ ```
121
+
122
+ #### With Metadata (Analytics)
123
+
124
+ ```typescript
125
+ const response = await client.prompts.execute('prm_abc123', {
126
+ provider: 'openai',
127
+ model: 'gpt-4o',
128
+ variables: { query: 'Hello' },
129
+ metadata: {
130
+ userId: 'user_123',
131
+ sessionId: 'sess_456',
132
+ environment: 'production',
133
+ },
134
+ });
135
+ ```
136
+
137
+ #### With Conversation History
138
+
139
+ ```typescript
140
+ const response = await client.prompts.execute('prm_chat456', {
141
+ provider: 'anthropic',
142
+ model: 'claude-sonnet-4-20250514',
143
+ variables: { topic: 'TypeScript' },
144
+ messages: [
145
+ { role: 'user', content: 'What is TypeScript?' },
146
+ { role: 'assistant', content: 'TypeScript is a typed superset of JavaScript...' },
147
+ { role: 'user', content: 'How do I use generics?' },
148
+ ],
149
+ });
150
+ ```
151
+
152
+ #### With Structured Output (JSON Schema)
153
+
154
+ ```typescript
155
+ const response = await client.prompts.execute('prm_extract789', {
156
+ provider: 'openai',
157
+ model: 'gpt-4o',
158
+ variables: { text: 'John Doe, age 30, from New York' },
159
+ responseSchema: {
160
+ type: 'object',
161
+ properties: {
162
+ name: { type: 'string' },
163
+ age: { type: 'number' },
164
+ city: { type: 'string' },
165
+ },
166
+ required: ['name', 'age', 'city'],
167
+ },
168
+ });
169
+
170
+ // Access parsed object directly
171
+ console.log(response.object); // { name: 'John Doe', age: 30, city: 'New York' }
172
+ ```
173
+
174
+ #### Image Generation
175
+
176
+ ```typescript
177
+ const response = await client.prompts.execute('prm_image123', {
178
+ provider: 'openai',
179
+ model: 'dall-e-3',
180
+ variables: { description: 'A sunset over mountains' },
181
+ });
182
+
183
+ if (response.type === 'image') {
184
+ for (const file of response.files) {
185
+ console.log('Generated image:', file.url);
186
+ console.log('MIME type:', file.mimeType);
187
+ }
188
+ }
189
+ ```
190
+
191
+ #### With Tool Calls
192
+
193
+ ```typescript
194
+ const response = await client.prompts.execute('prm_assistant012', {
195
+ provider: 'openai',
196
+ model: 'gpt-4o',
197
+ variables: { query: 'What is the weather in Tokyo?' },
198
+ });
199
+
200
+ if (response.type === 'tool_calls') {
201
+ for (const toolCall of response.toolCalls) {
202
+ console.log(`Tool: ${toolCall.name}`);
203
+ console.log(`Arguments: ${JSON.stringify(toolCall.arguments)}`);
204
+
205
+ // Execute your tool
206
+ const result = await executeMyTool(toolCall.name, toolCall.arguments);
207
+
208
+ // Continue conversation with tool results
209
+ const finalResponse = await client.prompts.execute('prm_assistant012', {
210
+ provider: 'openai',
211
+ model: 'gpt-4o',
212
+ messages: [
213
+ { role: 'user', content: 'What is the weather in Tokyo?' },
214
+ { role: 'assistant', toolCalls: [toolCall] },
215
+ { role: 'tool', toolResults: [{ toolCallId: toolCall.id, content: JSON.stringify(result) }] },
216
+ ],
217
+ });
218
+
219
+ console.log(finalResponse.content);
220
+ }
221
+ }
222
+ ```
223
+
224
+ ### Models
225
+
226
+ #### List All Models
227
+
228
+ ```typescript
229
+ const { providers } = await client.models.list();
230
+
231
+ for (const provider of providers) {
232
+ console.log(`${provider.displayName}:`);
233
+ for (const model of provider.models) {
234
+ console.log(` - ${model.displayName} (${model.id})`);
235
+ }
236
+ }
237
+ ```
238
+
239
+ #### Filter Models
240
+
241
+ ```typescript
242
+ // Filter by type
243
+ const textModels = await client.models.list({ type: 'text' });
244
+ const imageModels = await client.models.list({ type: 'image' });
245
+
246
+ // Filter by capability
247
+ const visionModels = await client.models.list({ capability: 'vision' });
248
+
249
+ // Filter by provider
250
+ const openaiModels = await client.models.list({ provider: 'openai' });
251
+ ```
252
+
253
+ #### Get Models by Provider
254
+
255
+ ```typescript
256
+ const models = await client.models.getByProvider('anthropic');
257
+
258
+ for (const model of models) {
259
+ console.log(`${model.displayName}: context=${model.limits.contextWindow}`);
260
+ }
261
+ ```
262
+
263
+ #### Get Specific Model
264
+
265
+ ```typescript
266
+ const model = await client.models.get('openai', 'gpt-4o');
267
+
268
+ console.log('Capabilities:', model.capabilities);
269
+ console.log('Context window:', model.limits.contextWindow);
270
+ console.log('Pricing:', model.pricing);
271
+ ```
272
+
273
+ ### Files
274
+
275
+ #### Upload Files
276
+
277
+ Upload files for use in prompt execution (e.g., images for vision models).
278
+
279
+ ```typescript
280
+ const result = await client.files.upload(
281
+ [file1, file2], // File[] or Blob[]
282
+ { projectId: 'prj_abc123' }
283
+ );
284
+
285
+ for (const file of result.data) {
286
+ console.log(`Uploaded: ${file.originalName}`);
287
+ console.log(` ID: ${file.id}`);
288
+ console.log(` URL: ${file.url}`);
289
+ console.log(` Size: ${file.size} bytes`);
290
+ }
291
+ ```
292
+
293
+ #### Use Uploaded Files in Messages
294
+
295
+ ```typescript
296
+ // Upload an image
297
+ const uploadResult = await client.files.upload([imageFile], { projectId: 'prj_abc123' });
298
+ const fileId = uploadResult.data[0].id;
299
+
300
+ // Use in prompt execution with vision model
301
+ const response = await client.prompts.execute('prm_vision123', {
302
+ provider: 'openai',
303
+ model: 'gpt-4o',
304
+ messages: [
305
+ {
306
+ role: 'user',
307
+ content: 'What is in this image?',
308
+ files: [{ fileId }],
309
+ },
310
+ ],
311
+ });
312
+
313
+ console.log(response.content);
314
+ ```
315
+
316
+ ## Error Handling
317
+
318
+ The SDK provides typed errors for different failure scenarios:
319
+
320
+ ```typescript
321
+ import {
322
+ SynovaCloudSdk,
323
+ SynovaError,
324
+ AuthSynovaError,
325
+ NotFoundSynovaError,
326
+ RateLimitSynovaError,
327
+ TimeoutSynovaError,
328
+ NetworkSynovaError,
329
+ ServerSynovaError,
330
+ ApiSynovaError,
331
+ } from '@synova-cloud/sdk';
332
+
333
+ try {
334
+ const response = await client.prompts.execute('prm_abc123', {
335
+ provider: 'openai',
336
+ model: 'gpt-4o',
337
+ variables: { name: 'World' },
338
+ });
339
+ } catch (error) {
340
+ if (error instanceof AuthSynovaError) {
341
+ console.error('Invalid API key');
342
+ } else if (error instanceof NotFoundSynovaError) {
343
+ console.error(`Resource not found: ${error.resourceType} ${error.resourceId}`);
344
+ } else if (error instanceof RateLimitSynovaError) {
345
+ console.error(`Rate limited. Retry after: ${error.retryAfterMs}ms`);
346
+ } else if (error instanceof TimeoutSynovaError) {
347
+ console.error(`Request timed out after ${error.timeoutMs}ms`);
348
+ } else if (error instanceof NetworkSynovaError) {
349
+ console.error(`Network error: ${error.message}`);
350
+ } else if (error instanceof ServerSynovaError) {
351
+ console.error(`Server error ${error.httpCode}: ${error.message}`);
352
+ } else if (error instanceof ApiSynovaError) {
353
+ console.error(`API error [${error.code}]: ${error.message}`);
354
+ } else if (error instanceof SynovaError) {
355
+ console.error(`Synova error: ${error.message}`);
356
+ }
357
+ }
358
+ ```
359
+
360
+ ## Retry Behavior
361
+
362
+ The SDK automatically retries requests on:
363
+ - Rate limit errors (429) - uses `Retry-After` header if available
364
+ - Server errors (5xx)
365
+ - Network errors
366
+ - Timeout errors
367
+
368
+ Non-retryable errors (fail immediately):
369
+ - Authentication errors (401)
370
+ - Not found errors (404)
371
+ - Client errors (4xx)
372
+
373
+ ### Retry Strategies
374
+
375
+ **Exponential Backoff** (default):
376
+ ```
377
+ delay = initialDelayMs * backoffMultiplier^(attempt-1)
378
+ ```
379
+ Example with defaults: 1000ms, 2000ms, 4000ms...
380
+
381
+ **Linear**:
382
+ ```
383
+ delay = initialDelayMs * attempt
384
+ ```
385
+ Example with defaults: 1000ms, 2000ms, 3000ms...
386
+
387
+ Both strategies add ±10% jitter to prevent thundering herd.
388
+
389
+ ## Custom Logger
390
+
391
+ You can provide a custom logger that implements the `ISynovaLogger` interface:
392
+
393
+ ```typescript
394
+ import { SynovaCloudSdk, ISynovaLogger } from '@synova-cloud/sdk';
395
+
396
+ const customLogger: ISynovaLogger = {
397
+ debug: (message, ...args) => myLogger.debug(message, ...args),
398
+ info: (message, ...args) => myLogger.info(message, ...args),
399
+ warn: (message, ...args) => myLogger.warn(message, ...args),
400
+ error: (messageOrError, ...args) => {
401
+ if (messageOrError instanceof Error) {
402
+ myLogger.error(messageOrError.message, messageOrError, ...args);
403
+ } else {
404
+ myLogger.error(messageOrError, ...args);
405
+ }
406
+ },
407
+ };
408
+
409
+ const client = new SynovaCloudSdk('your-api-key', {
410
+ debug: true,
411
+ logger: customLogger,
412
+ });
413
+ ```
414
+
415
+ ## TypeScript
416
+
417
+ The SDK is written in TypeScript and provides full type definitions:
418
+
419
+ ```typescript
420
+ import type {
421
+ // Config
422
+ ISynovaConfig,
423
+ ISynovaRetryConfig,
424
+ TSynovaRetryStrategy,
425
+ ISynovaLogger,
426
+ // Prompts
427
+ ISynovaPrompt,
428
+ ISynovaPromptVariable,
429
+ ISynovaGetPromptOptions,
430
+ // Execution
431
+ ISynovaExecuteOptions,
432
+ ISynovaExecuteResponse,
433
+ ISynovaUsage,
434
+ ISynovaExecutionError,
435
+ // Messages
436
+ ISynovaMessage,
437
+ ISynovaToolCall,
438
+ ISynovaToolResult,
439
+ TSynovaMessageRole,
440
+ TSynovaResponseType,
441
+ // Files
442
+ ISynovaFileAttachment,
443
+ ISynovaFileThumbnails,
444
+ ISynovaUploadedFile,
445
+ ISynovaUploadResponse,
446
+ ISynovaUploadOptions,
447
+ // Models
448
+ ISynovaModel,
449
+ ISynovaModelCapabilities,
450
+ ISynovaModelLimits,
451
+ ISynovaModelPricing,
452
+ ISynovaProvider,
453
+ ISynovaModelsResponse,
454
+ ISynovaListModelsOptions,
455
+ TSynovaModelType,
456
+ } from '@synova-cloud/sdk';
457
+ ```
458
+
459
+ ## CommonJS
460
+
461
+ The SDK supports both ESM and CommonJS:
462
+
463
+ ```javascript
464
+ const { SynovaCloudSdk } = require('@synova-cloud/sdk');
465
+
466
+ const client = new SynovaCloudSdk('your-api-key');
467
+ ```
468
+
469
+ ## Requirements
470
+
471
+ - Node.js 18+ (uses native `fetch`)
472
+
473
+ ## License
474
+
475
+ MIT