npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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 fetch and EventEmitter
  • Dual Build: ESM + CJS, tree-shakeable, full TypeScript declarations

Installation

npm install @omnilink/sdk
# or
yarn add @omnilink/sdk

Requirements: 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 time

Error 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