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

dcp-renter-sdk

v0.1.0

Published

Official TypeScript/JavaScript SDK for GPU renters on DC1 — Saudi Arabia's compute marketplace

Readme

dc1-renter-sdk

Official TypeScript/JavaScript SDK for GPU renters on DC1 — Saudi Arabia's decentralized compute marketplace.

Installation

npm install dc1-renter-sdk

No third-party runtime dependencies. Requires Node.js 18+.

Quickstart — 5 lines to your first LLM job

import { DC1RenterClient } from 'dc1-renter-sdk';

const client = new DC1RenterClient({ apiKey: 'dc1-renter-abc123' });
const providers = await client.listProviders();
const job = await client.submitJob({
  providerId: providers[0].id,
  jobType: 'llm_inference',
  params: { prompt: 'Explain transformer attention in two sentences.' },
  durationMinutes: 2,
});
const result = await client.waitForJob(job.id);
console.log(result.result?.output);

Authentication

Get your API key from the DC1 renter dashboard. Keys look like dc1-renter-<hex>.

const client = new DC1RenterClient({ apiKey: 'dc1-renter-abc123' });

New accounts can be created programmatically:

const { apiKey } = await client.register('Ahmed Al-Rashid', '[email protected]');
// Save apiKey — it won't be shown again

API Reference

new DC1RenterClient(config)

| Field | Type | Default | Description | |-------------|----------|------------------------|-------------------------------| | apiKey | string | required | Your renter API key | | baseUrl | string | https://api.dcp.sa | Override for staging/local | | timeoutMs | number | 30000 | HTTP timeout in milliseconds |


Auth

client.me() → Promise<Wallet>

Fetch your profile and current balance.

client.register(name, email, organization?) → Promise<RegisterResult>

Register a new renter account.

const { apiKey, renterId } = await client.register('Ahmed', '[email protected]', 'Acme Corp');

Providers

client.listProviders(filters?) → Promise<Provider[]>

List all online GPU providers.

// All providers
const all = await client.listProviders();

// Filter: only providers with ≥ 24 GB VRAM
const highVram = await client.listProviders({ minVramGb: 24 });

// Filter: RTX 4090s only
const rtx4090s = await client.listProviders({ gpuModel: '4090' });

| Filter field | Type | Description | |--------------|----------|--------------------------------------| | minVramGb | number | Minimum VRAM in GB | | gpuModel | string | GPU model substring (case-insensitive) |


Jobs

client.submitJob(options) → Promise<Job>

Submit a compute job.

const job = await client.submitJob({
  providerId: 26,                    // from listProviders()
  jobType: 'llm_inference',         // see job types below
  params: { prompt: 'Hello, DC1!', model: 'microsoft/phi-2' },
  durationMinutes: 2,
  priority: 2,                       // 1=high, 2=normal, 3=low
});

Job types and params:

| jobType | Required params | Optional params | Billing | |--------------------|--------------------------|-------------------------------------------|---------------| | llm_inference | prompt: string | model: string | 15 h/min | | image_generation | prompt: string | width, height, steps, model | 20 h/min | | vllm_serve | model: string | max_model_len, dtype | 20 h/min | | rendering | scene_url: string | — | 20 h/min | | training | (custom) | — | 25 h/min | | benchmark | (none) | — | 10 h/min |

Billing note: 1 SAR = 100 halala. A 2-minute llm_inference job costs 30 halala (0.30 SAR).

Throws APIError with status 402 if balance is insufficient — call getBalance() and top up in the dashboard first.

client.getJob(jobId) → Promise<Job>

Fetch current status and result.

client.waitForJob(jobId, options?) → Promise<Job>

Poll until the job reaches a terminal state.

const result = await client.waitForJob(job.id, {
  timeout: 300_000,     // 5 min (default)
  pollInterval: 3_000,  // 3s between polls (default)
  onProgress: (status) => console.log('Status:', status),
});

// result.result?.output — text output
// result.result?.image_url — for image_generation jobs
// result.result?.endpoint_url — for vllm_serve jobs

Throws JobTimeoutError if the job doesn't finish in time.

client.getJobLogs(jobId, since?) → Promise<JobLog[]>

Fetch execution log lines written by the daemon during job execution.

const logs = await client.getJobLogs(job.id);
// Incremental tail — only lines after line 50:
const newLines = await client.getJobLogs(job.id, 50);

client.cancelJob(jobId) → Promise<{ success, jobId }>

Cancel a queued or running job. The estimated cost is refunded to your balance.


Billing

client.getBalance() → Promise<Balance>

Fetch detailed wallet balance.

const balance = await client.getBalance();
console.log(`Available: ${balance.balanceSar.toFixed(2)} SAR`);
console.log(`Held for active jobs: ${balance.heldSar.toFixed(2)} SAR`);

client.getPaymentHistory(limit?) → Promise<PaymentHistory>

Fetch job billing history (default limit=20).

const history = await client.getPaymentHistory(50);
for (const item of history.jobs) {
  console.log(`${item.jobType} — ${item.costSar} SAR — ${item.status}`);
}

Types

Job

| Field | Type | Description | |-------------------|----------------------------------------|-----------------------------------------| | id | string | Job ID (e.g. job-1234-abcdef) | | status | 'queued' \| 'running' \| 'completed' \| 'failed' \| 'cancelled' | Current state | | jobType | JobType | Job type string | | providerId | number | Provider that ran the job | | durationMinutes | number | Requested max duration | | costHalala | number | Billed amount in halala | | costSar | number | costHalala / 100 | | isDone | boolean | true when status is terminal | | result | Record<string,unknown> \| null | Parsed output | | resultType | 'text' \| 'image' \| 'endpoint' \| null | Output type | | error | string \| null | Error message if status === 'failed' | | executionTimeSec| number \| null | Actual wall-clock execution time |

Provider

| Field | Type | Description | |--------------------|----------|---------------------------------| | id | number | Numeric provider ID | | name | string | Display name | | gpuModel | string | GPU model (e.g. RTX 4090) | | vramMib | number | VRAM in MiB | | vramGb | number | VRAM in GB (rounded to 1 dp) | | status | string | online \| offline \| paused | | reliabilityScore | number | 0–100 reliability score |

Balance

| Field | Type | Description | |---------------------|----------|---------------------------------| | balanceHalala | number | Total balance in halala | | balanceSar | number | Total balance in SAR | | heldHalala | number | Funds held for active jobs | | availableHalala | number | Immediately spendable | | totalSpentHalala | number | Lifetime spend |

JobLog

| Field | Type | Description | |------------|-------------------------------------|------------------------| | lineNo | number | Sequential line number | | level | 'info' \| 'warn' \| 'error' \| 'debug' | Log level | | message | string | Log message | | loggedAt | string | ISO timestamp |


Error handling

import { DC1RenterClient, JobTimeoutError, APIError, AuthError } from 'dc1-renter-sdk';

try {
  const result = await client.waitForJob(job.id, { timeout: 60_000 });
} catch (e) {
  if (e instanceof JobTimeoutError) {
    console.log(`Still running after ${e.timeoutMs / 1000}s — cancelling...`);
    await client.cancelJob(e.jobId);
  } else if (e instanceof AuthError) {
    console.log('Invalid API key — check https://dcp.sa/renter');
  } else if (e instanceof APIError) {
    console.log(`API error ${e.statusCode}:`, e.message, e.response);
  }
}

| Error | When thrown | |------------------|------------------------------------------------------------| | AuthError | 401 — API key invalid or missing | | APIError | Non-2xx response. Has .statusCode and .response | | JobTimeoutError| waitForJob() exceeded timeout. Has .jobId |


Examples

See the examples/ directory:

npx ts-node examples/list-providers.ts
DC1_API_KEY=dc1-renter-abc123 npx ts-node examples/submit-job.ts

License

MIT © DC1 / dhnpmp-tech