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

@titon-network/kronos-sdk

v0.8.0

Published

TypeScript SDK for the Kronos automation protocol on TON — register recurring on-chain jobs, run automatons, decode events. **TESTNET ONLY — NOT AUDITED.**

Readme

@titon-network/kronos-sdk

TypeScript SDK for the Kronos automation protocol on TON — Chainlink Automation for the TON ecosystem.

Register recurring on-chain jobs, decode events, maintain a local automaton mirror. Works in browsers, Node servers, and TON sandbox tests.

npm install @titon-network/kronos-sdk @ton/core

30-second integration

Kronos is live on testnet. This block calls our deployed registry directly — copy, paste, run.

import { TonClient } from '@ton/ton';
import { Address, beginCell, toNano } from '@ton/core';
import {
    KronosClient, KronosRegistry, KRONOS_TESTNET, registerJobOpts,
} from '@titon-network/kronos-sdk';

const tonClient = new TonClient({
    endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});
const registry = tonClient.open(
    KronosRegistry.createFromAddress(KRONOS_TESTNET.registry),
);
const client = new KronosClient({ registry });
const cfg = await client.jobs.config();

await client.jobs.register(yourSender, registerJobOpts({
    target:   Address.parse('EQ...your-target-contract...'),
    message:  beginCell().storeUint(0x7001 /* OP_TICK */, 32).endCell(),
    interval: 3_600,                  // every hour
    reward:   toNano('0.05'),
    gasLimit: toNano('0.02'),
}, cfg));                             // auto-funds 100 runs

That's it. An automaton picks up your job and calls your contract every hour.

For the target contract pattern (the four invariants every Kronos receiver must follow), see examples/contracts/counter/ — a complete reference Tolk contract + sandbox test you drop into your Blueprint project.

Set up your LLM assistant — three options

Kronos is built for LLM-assisted development. Pick the path that matches your tooling:

| Tool | Setup | |---|---| | Claude Code | npx @titon-network/kronos-sdk init — installs 11 skills (/kronos-register-job, /kronos-target-receiver, /kronos-scaffold, …) into .claude/skills/. Every future Claude session in this project knows Kronos. | | Cursor / GPT / raw Claude API / Cline | Paste AGENT-PROMPT.md into your system prompt. ~3K tokens, self-contained, turns any LLM into a Kronos expert. | | Claude Desktop / MCP-aware tooling | Install @titon-network/mcp — gives the LLM 17+ live tools: kronos.preview_economics, kronos.prepare_register_job, kronos.window_state, kronos.assigned_automaton, kronos.explain_exit_code, etc. | | anything else | Fetch llms-full.txt — single-file context dump with the counter contract, full API table, every pitfall. Or llms.txt for the discoverable doc index per llmstxt.org. |

@ton/core is a peer dependency — bring your own version (>= 0.63.0). @ton/sandbox and @titon-network/forgeton-sdk are optional peers — only needed when you use @titon-network/kronos-sdk/testing or run automaton flows.

💡 Running an automaton? Install @titon-network/forgeton-sdk alongside this one. Pool-side operations (stake, slash, pool events) live there. This SDK covers the Kronos registry only.

Three layers, pick what you need

┌──────────────────────────────────────────────────────┐
│  KronosClient   registerJobOpts    decodeEvent       │  high-level
├──────────────────────────────────────────────────────┤
│  executionEconomics  assignedAutomatonIndex  isDue   │  pure helpers
├──────────────────────────────────────────────────────┤
│  KronosRegistry                                      │  contract wrapper (1:1 ABI)
└──────────────────────────────────────────────────────┘

You can drop down any layer — they're all part of the public surface.

More recipes

Decode registry events from your indexer

import { decodeEvent } from '@titon-network/kronos-sdk';

// Each `Cell` is the body of an external-out message emitted by the registry.
// For pool-side events (AutomatonRegistered, AutomatonSlashed, …) use
// `decodeEvent` from @titon-network/forgeton-sdk on the pool's external bodies.
for (const body of externalBodies) {
    const ev = decodeEvent(body);
    if (ev === null) continue;  // not a Kronos event — try @titon-network/forgeton-sdk next
    switch (ev.kind) {
        case 'JobExecuted':
            console.log(`job ${ev.jobId} run ${ev.executionCount} by ${ev.automaton}`);
            break;
        case 'AssignedAutomatonMissed':
            console.warn(`automaton ${ev.assigned} missed window for job ${ev.jobId}`);
            break;
    }
}

Run an automaton (staking via @titon-network/forgeton-sdk)

Pool operations live in @titon-network/forgeton-sdk. Use both SDKs together:

import { KronosClient, KronosRegistry } from '@titon-network/kronos-sdk';
import { ForgeTON } from '@titon-network/forgeton-sdk';

const registry = tonClient.open(KronosRegistry.createFromAddress(REGISTRY_ADDRESS));
const pool = tonClient.open(ForgeTON.createFromAddress(FORGETON_ADDRESS));
const client = new KronosClient({ registry });

// Stake to become an automaton (pool-side; @titon-network/forgeton-sdk).
const poolCfg = await pool.getConfig();
const consumerCount = await pool.getConsumerCount();
await pool.sendRegisterAutomaton(walletSender, {
    value: poolCfg.minStake
         + poolCfg.minGasForRegister
         + BigInt(consumerCount) * poolCfg.syncGasCost,
});

// Find the next due job and execute it (registry-side; @titon-network/kronos-sdk).
const jobCount = await client.jobs.count();
for (let i = 0n; i < jobCount; i++) {
    if (!(await client.jobs.exists(i))) continue;
    if (!(await client.jobs.isDue(i))) continue;

    // Check if you're the assigned automaton for the primary window.
    const assigned = await client.assignedAutomatonFor(i);
    if (assigned && !assigned.equals(myAddress)) continue;

    await client.jobs.execute(walletSender, { value: toNano('0.5'), jobId: i });
}

Check if Kronos is operational

const activeAutomatons = await client.registry.getActiveAutomatonCount();
// → current operator capacity (denominator of the assignment formula)

if (activeAutomatons >= 2) {
    // redundant capacity — safe to register new jobs
}

For execution freshness, recent activity, and per-operator reliability, query the Argus indexer's event stream rather than the contract — EvtJobExecuted + EvtAssignedAutomatonMissed against the deterministic assignment formula give a full audit trail without the gas cost of on-chain counters.

Inspect a job's window state

import { jobWindowState, isDue, nextExecutionAt } from '@titon-network/kronos-sdk';

const job = await client.jobs.get(jobId);
const cfg = await client.jobs.config();
const state = jobWindowState({
    lastExecutedAt: job!.lastExecutedAt,
    interval: job!.interval,
    windowBefore: job!.windowBefore,
    windowAfter: job!.windowAfter,
    primaryWindowSeconds: cfg.primaryWindowSeconds,
    expireAfter: job!.expireAfter,
});
// state.status: 'never-executed' | 'too-early' | 'primary' | 'fallback' | 'too-late' | 'expired'
// state.secondsToNext: countdown to next status change

Reference

KronosClient

High-level façade over the registry. Construct with an already-opened contract handle:

const client = new KronosClient({
    registry: tonClient.open(KronosRegistry.createFromAddress(REGISTRY_ADDRESS)),
});

| Namespace | Methods | |-----------|---------| | client.jobs | register, execute, fund, ensureFunded, cancel, pause, resume, withdraw, update, updateFull, cleanupExpired, sweepDust, performHousekeeping, get, exists, isDue, nextDue, balance, balanceHealth, economics, count, config | | client.mirror | snapshot, assignedFor, activeCount — registry-side reads against the dense automaton mirror maintained by inbound AutomatonSync | | client.events | decode, decodeAll |

Plus convenience methods on the client itself: assignedAutomatonFor(jobId), windowFor(jobId).

For pool-side operations (stake, unstake, slash, pool events) use @titon-network/forgeton-sdk's ForgeTON class directly.

registerJobOpts(input, cfg?)

Helper that fills in sensible defaults (30s before / 10min after window, no expiry, unlimited runs) and, if cfg is supplied, auto-computes funding for 100 runs.

registerJobOpts(
    {
        target,
        message,
        interval: 3600,
        reward: toNano('0.05'),
        gasLimit: toNano('0.02'),
        // Optional overrides — omit for defaults:
        maxExecutions: 0,      // unlimited
        windowBefore: 30,
        windowAfter: 600,
        expireAfter: 0,        // never
        funding: toNano('1'),  // or omit + pass cfg to auto-compute
    },
    cfg,
);

decodeEvent(body: Cell): KronosEvent | null

Parses an external-log message body into a typed registry event. The discriminant is event.kind. Returns null when the opcode is not a Kronos event (try @titon-network/forgeton-sdk's decodeEvent next).

All registry event kinds:

JobRegistered  JobExecuted    JobFunded       JobCancelled    JobUpdated
JobPaused      JobResumed     JobWithdrawn    JobExpired      JobDustSwept
JobHousekeepingExecuted  ForgetonSet  AutomatonMirrorUpdated   AssignedAutomatonMissed
ConfigUpdated  TreasuryUpdated  HousekeepingJobSet  FeesWithdrawn
UpgradeProposed  UpgradeCancelled  CodeUpdated  SlashRetried

Pool-side events (AutomatonRegistered, AutomatonSlashed, …) are decoded by @titon-network/forgeton-sdk's own decodeEvent. Chain both decoders if you're watching both contracts.

Pure helpers

| Function | Purpose | |----------|---------| | executionEconomics({ reward, gasLimit, protocolFeeBps }) | Returns { totalCost, protocolFee, automatonReward, gasLimit }. Mirrors on-chain JobConfig.executionEconomics. | | recommendedRegisterValue(...) | max(executions * totalCost, minFunding) + minGasReserve. The number you attach to RegisterJob. | | previewJobCost({ reward, gasLimit, interval, executions? }, cfg) | One-call UI-friendly preview — { perExecutionCost, minFunding, recommended, protocolFee, burnRatePerDay, runsAtRecommended, … }. | | estimateJobGas({ initCode, initData?, body }) or estimateJobGas({ blockchain, target, body }) | Sandbox-based gas estimator — { gasUsed, recommended } with 20% buffer. initCode mode deploys a fresh account; target mode needs the contract pre-deployed on the supplied blockchain. Requires @ton/sandbox (optional peer). | | assignedAutomatonIndex({ jobId, executionCount, activeAutomatonCount }) | The on-chain assignment formula (jobId + execCount) % activeCount. | | resolveAssignedAutomaton({ ..., automatonAddresses }) | Same, but resolves to an Address using a mirror snapshot. | | jobWindowState({ lastExecutedAt, interval, ... }) | Full window inspection: status, deadlines, secondsToNext. | | isDue(...), nextExecutionAt(...) | Convenience over jobWindowState — time/expiry only. | | isExecutable({ ..., balance, perExecutionCost, isActive }) | Faithful preview of Execute success — also checks active + funded. Use this in automaton daemons. | | validateRegisterOpts(opts, cfg) | Pre-flight foot-gun check: throws on contract-reject values (bad interval / reward / gasLimit / expireAfter), returns warnings[] for likely-buggy-but-legal inputs. Wired into registerJobOpts automatically when cfg is supplied — opt out with { validate: false }. |

JobPresets

Three spread-in profiles that collapse the windowBefore/windowAfter choice to a name:

import { registerJobOpts, JobPresets } from '@titon-network/kronos-sdk';

// Every minute, strict window.
registerJobOpts({ ..., interval: 60, ...JobPresets.tight }, cfg);

// Hourly (current defaults).
registerJobOpts({ ..., interval: 3600, ...JobPresets.default }, cfg);

// Daily / weekly, tolerant of late runs.
registerJobOpts({ ..., interval: 86_400, ...JobPresets.loose }, cfg);

JobWatcher

Long-running subscription for a single job's events — polls the registry tx stream, filters by jobId, emits typed callbacks. Plug in any transaction source (TonClient, custom indexer, sandbox for tests):

import { JobWatcher } from '@titon-network/kronos-sdk';

const watcher = new JobWatcher(client, jobId, { source: myEventSource });
watcher
    .on('JobExecuted', (ev) => console.log(`run ${ev.executionCount} by ${ev.automaton}`))
    .on('JobFunded',   (ev) => console.log(`topped up by ${ev.amount}`))
    .on('LowBalance',  (ev) => alertOps(ev.jobId, ev.runsRemaining));

const stop = watcher.start();
// ... later ...
await stop();

Test harness — @titon-network/kronos-sdk/testing

Shrinks "deploy registry + register job + fast-forward + execute" to a one-liner. Requires @ton/sandbox installed:

import { SandboxKronos } from '@titon-network/kronos-sdk/testing';

const kronos = await SandboxKronos.deploy(blockchain, { owner, treasury, via: owner.getSender() });
const jobId = await kronos.register({ target, message, interval, reward, gasLimit, via });
kronos.fastForward(301);
const res = await kronos.executeNext(jobId, automaton.getSender());

See /kronos-integration-test for the full API + patterns.

Error introspection

import { explainError, formatErrorExplanation, ERR } from '@titon-network/kronos-sdk';

const e = explainError(132);
// { code: 132, origin: 'kronos', name: 'NotJobOwner',
//   message: 'Operation requires the job owner.',
//   relatedSkill: '/kronos-job-lifecycle' }

// Single-line for logs or thrown Error messages.
throw new Error(formatErrorExplanation(e));
// → Error: [NotJobOwner] (132) Operation requires the job owner.  See /kronos-job-lifecycle

Covers every E_* from contracts/errors.tolk plus common TVM exit codes. Pool-side codes (160-199) route to origin: 'forgeton' with a pointer — install @titon-network/forgeton-sdk and call its explainError for the prose.

Bundled compiled contract

import { loadRegistryCode, KronosRegistry } from '@titon-network/kronos-sdk';

const code = loadRegistryCode();
const registry = KronosRegistry.createFromConfig({ owner, treasury }, code);
// → registry.init.code (BoC) + registry.address (deterministic from init)

Ships with the compiled KronosRegistry.compiled.json under artifacts/. For the pool's BoC (ForgeTON.compiled.json), install @titon-network/forgeton-sdk and call its loadForgetonCode().

Examples

See examples/ for full programs:

  • 01-register-job.ts — register a recurring counter-bumper job.
  • 02-automaton-register.ts — run an automaton (uses both @titon-network/kronos-sdk + @titon-network/forgeton-sdk).
  • 03-decode-events.ts — minimal indexer that prints every registry event.

Working with AI tools

This package ships AI-friendly assets alongside the runtime:

  • AGENTS.md — terse map of the SDK auto-discovered by Claude Code, Cursor, and other AI editors that follow the agents.md convention. Drop the SDK into your project and your assistant has context.

  • skills/ — drop-in .claude/skills/*.md files for Claude Code:

    Job owner workflow

    • /kronos-register-job — guided job builder
    • /kronos-job-lifecycle — update / pause / withdraw / cancel
    • /kronos-monitor-events — indexer / alerting recipes

    Contract dev workflow (writing the Kronos target)

    • /kronos-target-receiver — idiomatic Tolk receiver pattern
    • /kronos-gas-sizing — empirically size gasLimit with a 20% buffer
    • /kronos-integration-testSandboxKronos harness patterns
    • /kronos-scaffold — one-shot "bolt Kronos onto my contract"

    Operator workflow

    • /kronos-automaton-setup — run an automaton (uses both SDKs)
    • /kronos-deploy — self-host deployment + housekeeping setup

    Debugging / admin

    • /kronos-debug-exit-code — exit-code triage
    • /kronos-owner-ops — admin operations + timelocked upgrades

    (Pool-side skills — stake an automaton, slash, admit a consumer — ship with @titon-network/forgeton-sdk.)

    Install all of them in one step:

    npx @titon-network/kronos-sdk init

    This also prints a CLAUDE.md fragment you can paste into your project's instructions so the AI has day-one context.

  • JSDoc @example blocks on every public method — your IDE's hover popups show runnable snippets.

Versioning

This SDK ships its own compiled BoC under artifacts/ (regenerated on each prepublishOnly). When the on-chain ABI changes, bump the SDK's major version. While we're pre-mainnet (v0.x), expect breaking changes alongside contract upgrades.

License

MIT.