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

@fireonce/sdk

v0.2.0

Published

Official TypeScript SDK for the FireOnce guaranteed-execution job scheduling platform

Downloads

52

Readme

@fireonce/sdk

Official TypeScript SDK for FireOnce -- the guaranteed-execution job scheduling platform.

Zero dependencies. Supports ESM and CommonJS. TypeScript strict mode.

Installation

pnpm add @fireonce/sdk
# or
npm install @fireonce/sdk

Quick Start

import { FireOnce, defineJob } from '@fireonce/sdk';

// 1. Define a job type
const sendEmail = defineJob<{ to: string; subject: string; body: string }>({
  name: 'send-email',
  handler: 'https://api.myapp.com/webhooks/fireonce/email',
  retry: { strategy: 'exponential', maxAttempts: 3, delayMs: 1000 },
  timeout: '30s',
});

// 2. Create a client
const fireonce = new FireOnce({
  apiKey: process.env.FIREONCE_API_KEY!,
});

// 3. Schedule a job — fires in 2 days
const handle = await fireonce.schedule(sendEmail, {
  id: 'welcome-email-user-123',
  payload: { to: '[email protected]', subject: 'Welcome!', body: 'Hello...' },
}).inDays(2);

// 4. Use the handle
const job = await handle.status();
console.log(job.status); // 'scheduled'

Concepts

Job Definitions

Job definitions capture the what and how of a job without scheduling anything. They are reusable templates that describe the handler, retry strategy, and timeout.

import { defineJob } from '@fireonce/sdk';

// HTTP callback mode -- FireOnce sends a POST to your URL when the job executes
const sendEmail = defineJob<{ to: string; subject: string; body: string }>({
  name: 'send-email',
  handler: 'https://api.myapp.com/webhooks/fireonce/email',
  retry: { strategy: 'exponential', maxAttempts: 3, delayMs: 1000 },
  timeout: '30s',
});

// Local handler mode -- define the handler as a function (requires FireOnce Worker)
const processPayment = defineJob<{ orderId: string; amount: number }, { transactionId: string }>({
  name: 'process-payment',
  handler: async (payload) => {
    const result = await stripe.charges.create({ amount: payload.amount });
    return { transactionId: result.id };
  },
  retry: { strategy: 'exponential', maxAttempts: 5, delayMs: 2000 },
  timeout: '60s',
});

The first generic parameter (TPayload) types the payload. The second (TResult) types the return value and defaults to void.

Scheduling Jobs

Use fireonce.schedule() to create a job instance. Chain fluent time methods to set when it fires:

// Execute immediately
const handle = await fireonce.schedule(sendEmail, {
  payload: { to: '[email protected]', subject: 'Welcome!', body: 'Hello...' },
});

// Execute in 2 days, 3 hours, and 30 minutes
const handle = await fireonce.schedule(sendEmail, {
  id: 'welcome-email-user-123',
  payload: { to: '[email protected]', subject: 'Welcome!', body: 'Hello...' },
}).inDays(2).inHours(3).inMinutes(30);

// Execute at an absolute time
const handle = await fireonce.schedule(sendEmail, {
  payload: { to: '[email protected]', subject: 'Welcome!', body: 'Hello...' },
}).at(new Date('2024-12-25T00:00:00Z'));

// All options
const handle = await fireonce.schedule(sendEmail, {
  id: 'welcome-email-user-123',
  payload: { to: '[email protected]', subject: 'Welcome!', body: 'Hello...' },
  idempotencyKey: 'welcome-user-123',
  webhookUrl: 'https://myapp.com/job-status',
}).inDays(1);

Available time methods (all additive):

| Method | Description | |---|---| | .inWeeks(n) | Add n weeks | | .inDays(n) | Add n days | | .inHours(n) | Add n hours | | .inMinutes(n) | Add n minutes | | .inSeconds(n) | Add n seconds | | .at(date) | Set absolute time (overrides relative offsets) |

Job Handles

A JobHandle is your interface to a running (or completed) job:

// Get current status
const job = await handle.status();
console.log(job.status); // 'queued' | 'scheduled' | 'processing' | 'completed' | ...

// Cancel a pending job
await handle.cancel();

// Replay a failed job
const replayed = await handle.replay();

// Poll until the job reaches a terminal state
const result = await handle.result({ timeout: 30_000, pollInterval: 2_000 });
console.log(result.status); // 'completed' | 'failed' | 'dead_lettered' | 'cancelled'

You can also get a handle for an existing job without scheduling:

const handle = fireonce.getHandle('job-id-123');
const status = await handle.status();

Bulk Scheduling

Schedule many jobs in a single API call:

const handles = await fireonce.scheduleBulk([
  {
    job: sendEmail,
    options: {
      id: 'email-1',
      payload: { to: '[email protected]', subject: 'Hi', body: 'Hello Alice' },
    },
  },
  {
    job: sendEmail,
    options: {
      id: 'email-2',
      payload: { to: '[email protected]', subject: 'Hi', body: 'Hello Bob' },
    },
  },
]);

// Each item in the array is a JobHandle
for (const handle of handles) {
  console.log(handle.id);
}

Management APIs

API Keys

// Create a new API key
const key = await fireonce.apiKeys.create({ label: 'Production' });
console.log(key.key); // Only returned once -- store securely

// List all keys
const keys = await fireonce.apiKeys.list();

// Revoke a key
await fireonce.apiKeys.revoke('key-id');

Usage

// Current billing period
const usage = await fireonce.usage.current();
console.log(usage.jobsCreated, usage.jobsCompleted);

// Historical usage
const history = await fireonce.usage.history();

Billing

// Create a checkout session
const { url } = await fireonce.billing.checkout({ plan: 'pro' });

// Upgrade plan
const { url: upgradeUrl } = await fireonce.billing.upgrade({ plan: 'enterprise' });

Authentication

// Register
const { token, tenant } = await fireonce.auth.register({
  name: 'Acme Corp',
  email: '[email protected]',
  password: 'secure-password',
});

// Login
const { token: loginToken } = await fireonce.auth.login({
  email: '[email protected]',
  password: 'secure-password',
});

Error Handling

All API errors throw FireOnceError with structured fields:

import { FireOnceError } from '@fireonce/sdk';

try {
  await handle.cancel();
} catch (err) {
  if (err instanceof FireOnceError) {
    console.error(err.message);  // Human-readable message
    console.error(err.status);   // HTTP status (0 for network/timeout)
    console.error(err.code);     // Machine-readable code (e.g. 'NOT_FOUND')
  }
}

Error Codes

| Code | Description | |------|-------------| | CONFIG_ERROR | Invalid client configuration | | TIMEOUT | Request timed out | | NETWORK_ERROR | Network connectivity issue | | LOCAL_HANDLER_NO_CALLBACK | Local handler used without a Worker or callbackUrl fallback | | RESULT_TIMEOUT | handle.result() timed out waiting for terminal state |

Configuration

| Option | Type | Default | Description | |---|---|---|---| | apiKey | string | required | Bearer token for API authentication | | baseUrl | string | https://api.fireonce.com | Base URL of the FireOnce API | | timeout | number | 30000 | Request timeout in milliseconds | | maxRetries | number | 3 | Max retries on 429/5xx responses | | retryDelayMs | number | 500 | Initial retry delay (doubles each attempt) |

Local Handler Mode

When you define a job with a function handler, the function captures your execution intent but requires a FireOnce Worker to actually run. If you schedule a local-handler job without a Worker, provide a callbackUrl fallback:

const processPayment = defineJob<{ orderId: string }, { txId: string }>({
  name: 'process-payment',
  handler: async (payload) => {
    // This runs in the Worker, not when scheduling
    return { txId: await charge(payload.orderId) };
  },
});

// Without a Worker, provide a callbackUrl fallback
const handle = await fireonce.schedule(processPayment, {
  payload: { orderId: 'order-123' },
  callbackUrl: 'https://api.myapp.com/webhooks/fireonce/payments',
});

Requirements

  • Node.js >= 18.0.0 (uses native fetch)
  • TypeScript >= 5.0 (for best type inference)
  • Zero runtime dependencies