@omnilink/sdk
v1.0.1
Published
Omnilink Node.js SDK — Remote script execution, script management, and tenant operations
Downloads
260
Readme
@omnilink/sdk
Enterprise-grade Node.js SDK for Omnilink — remote script execution, script management, and tenant operations.
Features
- Await Mode:
const result = await client.execute({...})— senkron kullanım - Stream Mode: Event-based execution lifecycle (
start,row,end,error) - Script Management: Full CRUD, versioning, tenant overrides
- Tenant Operations: List, detail, extension queries
- Enterprise Ready: Retry with exponential backoff, rate limit handling, typed errors, pluggable logger, abort support
- Zero Dependencies: Uses Node.js native
fetchandEventEmitter - Dual Build: ESM + CJS, tree-shakeable, full TypeScript declarations
Installation
npm install @omnilink/sdk
# or
yarn add @omnilink/sdkRequirements: Node.js >= 20.0.0
Quick Start
import { OmnilinkClient } from '@omnilink/sdk';
const client = new OmnilinkClient({
apiKey: 'omni_live_abc123...',
baseUrl: 'https://omnilink.sisteminiz.com.tr',
});
const result = await client.execute({
tenantId: 'clx123...',
extensionId: 'mssql-prod',
scriptPath: 'mssql/reports/sales.sql',
params: { startDate: '2024-01-01' },
});
console.log(result.data);Configuration
const client = new OmnilinkClient({
// Required
apiKey: 'omni_live_...', // API key (web panel'den oluşturulur)
baseUrl: 'https://omnilink.sisteminiz.com.tr',
// Optional
timeout: 30000, // Request timeout (ms). Default: 30000
retries: 3, // Retry count for network/5xx errors. Default: 3
pollInterval: 1000, // Execute status polling interval (ms). Default: 1000
maxPollAttempts: 300, // Max polling attempts (5 min). Default: 300
logger: customLogger, // Custom logger instance
onRequest: (init) => init, // Request interceptor
onResponse: (res) => {}, // Response interceptor
});Execute — Await Mode
The simplest way to run a script and get the result:
// Basic usage
const result = await client.execute({
tenantId: 'clx123...',
extensionId: 'mssql-prod',
scriptPath: 'mssql/reports/sales.sql',
params: { startDate: '2024-01-01', limit: 100 },
});
console.log(result.data); // Query result
console.log(result.executionId); // Unique execution ID
console.log(result.durationMs); // Total duration in ms
// With TypeScript generics for type-safe responses
interface SalesRow {
id: number;
amount: number;
date: string;
}
const typed = await client.execute<{ rows: SalesRow[]; rowCount: number }>({
tenantId: 'clx123...',
extensionId: 'mssql-prod',
scriptPath: 'mssql/reports/sales.sql',
});
// typed.data.rows → SalesRow[]
// With abort support
const controller = new AbortController();
setTimeout(() => controller.abort(), 10000); // 10s timeout
const abortable = await client.execute({
tenantId: '...',
extensionId: '...',
scriptPath: '...',
}, { signal: controller.signal });Execute — Stream Mode
For real-time execution tracking and row-by-row processing:
const stream = client.executeStream({
tenantId: 'clx123...',
extensionId: 'mssql-prod',
scriptPath: 'mssql/reports/large-dataset.sql',
params: { limit: 10000 },
});
stream.on('start', ({ executionId }) => {
console.log(`Execution started: ${executionId}`);
});
stream.on('checking_status', ({ attempt, maxAttempts, status }) => {
console.log(`Polling ${attempt}/${maxAttempts}: ${status}`);
});
stream.on('downloading', ({ downloadUrl }) => {
console.log('Downloading result from S3...');
});
// Process each SQL row individually (memory-efficient for large datasets)
stream.on('row', (row) => {
processRow(row);
});
stream.on('end', ({ executionId, durationMs, totalRows }) => {
console.log(`Done! ${totalRows} rows in ${durationMs}ms`);
});
stream.on('error', (error) => {
console.error('Failed:', error.code, error.message);
});
// Cancel execution
stream.abort();
// Or use as a promise
const result = await client.executeStream({ ... }).toPromise();Script Management
Full CRUD operations for scripts, versioning, and tenant overrides.
Requires manage_scripts permission on the API key.
// List all scripts
const scripts = await client.scripts.list();
// Get script details (with all content versions)
const script = await client.scripts.get('script-id');
// Create a new script
const newScript = await client.scripts.create({
name: 'Monthly Sales Report',
categoryTag: 'mssql',
initialContent: 'SELECT * FROM sales WHERE month = {{month}}',
initialVersion: 'v1.0.0',
params: [{ name: 'month', isOptional: false }],
});
// Update script metadata
await client.scripts.update('script-id', {
name: 'Updated Name',
description: 'New description',
});
// Delete script
await client.scripts.delete('script-id');Versioning
// List base versions
const versions = await client.scripts.listVersions('script-id');
// Add a new version
await client.scripts.addVersion('script-id', {
version: 'v2.0.0',
content: 'SELECT * FROM sales_v2 WHERE month = {{month}}',
changelog: 'Migration to new table',
isStable: true,
});
// Mark a version as stable (used for execution)
await client.scripts.setStable('script-id', 'content-id');
// Update content text
await client.scripts.updateContent('script-id', 'content-id', {
content: 'SELECT * FROM updated_table...',
params: [{ name: 'month', isOptional: false }],
});
// Delete a content version
await client.scripts.deleteContent('script-id', 'content-id');Tenant Overrides
Override script content for specific tenants:
// List overrides
const overrides = await client.scripts.listOverrides('script-id');
const tenantOverrides = await client.scripts.listOverrides('script-id', {
tenantId: 'tenant-123',
});
// Add tenant-specific override
await client.scripts.addOverride('script-id', {
tenantId: 'tenant-123',
version: 'v1.0.0-custom',
content: 'SELECT * FROM tenant_specific_table...',
isStable: true,
});Tenant Management
List and query tenants and their extensions.
Requires read_tenants permission on the API key.
// List all tenants
const tenants = await client.tenants.list();
for (const t of tenants) {
console.log(`${t.machineName} — online: ${t.isOnline}`);
}
// Get tenant details
const tenant = await client.tenants.get('tenant-id');
// Get tenant extensions
const extensions = await client.tenants.extensions('tenant-id');
// Filter by extension type
const mssqlExts = await client.tenants.extensions('tenant-id', { type: 'mssql' });Error Handling
All errors extend OmnilinkError with code, statusCode, and optional requestId:
import {
OmnilinkError,
AuthenticationError,
PermissionError,
ValidationError,
NotFoundError,
RateLimitError,
ExecutionError,
TimeoutError,
NetworkError,
AbortError,
} from '@omnilink/sdk';
try {
await client.execute({ ... });
} catch (error) {
if (error instanceof AuthenticationError) {
// 401 — Invalid or expired API key
} else if (error instanceof PermissionError) {
// 403 — Insufficient permissions
} else if (error instanceof NotFoundError) {
// 404 — Script, tenant, or execution not found
} else if (error instanceof RateLimitError) {
// 429 — Rate limit exceeded
console.log('Retry after:', error.retryAfter, 'seconds');
} else if (error instanceof ExecutionError) {
// Script execution failed
console.log('Error code:', error.code);
} else if (error instanceof TimeoutError) {
// Execution or request timeout
} else if (error instanceof AbortError) {
// Request was cancelled
} else if (error instanceof NetworkError) {
// Network connectivity issue
}
}Advanced
Custom Logger
Inject a custom logger (compatible with winston, pino, etc.):
import { OmnilinkClient, type Logger } from '@omnilink/sdk';
const logger: Logger = {
debug: (msg, meta) => myLogger.debug(msg, meta),
info: (msg, meta) => myLogger.info(msg, meta),
warn: (msg, meta) => myLogger.warn(msg, meta),
error: (msg, meta) => myLogger.error(msg, meta),
};
const client = new OmnilinkClient({
apiKey: '...',
baseUrl: '...',
logger,
});Request/Response Interceptors
Add custom logic before each request or after each response:
const client = new OmnilinkClient({
apiKey: '...',
baseUrl: '...',
onRequest: (init) => {
// Add custom headers, log, etc.
(init.headers as Record<string, string>)['x-correlation-id'] = generateId();
return init;
},
onResponse: async (response) => {
// Log response times, metrics, etc.
metrics.track('api_call', { status: response.status });
},
});Abort / Cancel
Cancel any in-flight operation using AbortController:
const controller = new AbortController();
// Cancel after 15 seconds
setTimeout(() => controller.abort(), 15000);
try {
const result = await client.execute({ ... }, {
signal: controller.signal,
});
} catch (error) {
if (error instanceof AbortError) {
console.log('Execution was cancelled');
}
}
// For streams
const stream = client.executeStream({ ... });
stream.abort(); // Cancel at any timeError Codes
| Code | Description |
|------|-------------|
| API_KEY_INVALID | Invalid API key |
| API_KEY_EXPIRED | API key has expired |
| API_KEY_PERMISSION_DENIED | Insufficient permissions |
| SCRIPT_NOT_FOUND | Script not found |
| SCRIPT_VERSION_NOT_FOUND | Script version not found |
| TENANT_NOT_FOUND | Tenant not found |
| TENANT_OFFLINE | Tenant is offline |
| EXTENSION_NOT_FOUND | Extension not found |
| EXECUTION_TIMEOUT | Execution timed out |
| EXECUTION_FAILED | Script execution failed |
| RATE_LIMIT_EXCEEDED | Too many requests |
| VALIDATION_ERROR | Invalid input data |
| NETWORK_ERROR | Network connectivity issue |
API Key Permissions
| Permission | Endpoints |
|-----------|-----------|
| execute | POST /execute, GET /executions/:id |
| manage_scripts | All /scripts/* endpoints |
| read_tenants | All /tenants/* endpoints |
License
MIT
