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

@stwd/sdk

v0.5.0

Published

TypeScript SDK for Steward — agent wallet infrastructure with policy enforcement

Readme

@stwd/sdk

TypeScript client for the Steward API. Use this in your agents, bots, or platform integrations to create wallets, set policies, and submit transactions for signing.

Installation

npm install @stwd/sdk
# bun add @stwd/sdk
# pnpm add @stwd/sdk

Quick Start

import { StewardClient } from '@stwd/sdk';

const steward = new StewardClient({
  baseUrl: 'https://api.steward.fi',
  tenantId: 'my-platform',
  apiKey: 'sk-...',
});

const agent = await steward.createWallet('agent-1', 'My Trading Bot');
console.log(agent.walletAddress); // 0x...

const result = await steward.signTransaction(agent.id, {
  to: '0xSomeContract',
  value: '10000000000000000', // 0.01 ETH in wei
  chainId: 8453,
});

if ('txHash' in result) {
  console.log('Broadcast:', result.txHash);
} else {
  // result.status === 'pending_approval'
  console.log('Queued for human review');
}

Constructor

new StewardClient(config: StewardClientConfig)

StewardClientConfig

| Field | Type | Required | Description | |-------|------|----------|-------------| | baseUrl | string | ✅ | Base URL of the Steward API (e.g. https://api.steward.fi) | | apiKey | string | — | API key sent as X-Steward-Key header | | tenantId | string | — | Tenant ID sent as X-Steward-Tenant header |


Methods

createWallet

Create a new agent wallet. Steward generates a keypair, encrypts it in the vault, and returns the agent identity.

createWallet(agentId: string, name: string, platformId?: string): Promise<AgentIdentity>

| Param | Description | |-------|-------------| | agentId | Unique identifier for the agent within your tenant | | name | Human-readable label (e.g. "DeFi Scout Bot") | | platformId | Optional external ID (e.g. your platform's agent UUID) |

Returns: AgentIdentity

const agent = await steward.createWallet('scout-1', 'DeFi Scout', 'ext-uuid-123');
// { id: 'scout-1', walletAddress: '0x...', tenantId: '...', name: '...', createdAt: Date }

getAgent

Fetch an agent by ID.

getAgent(agentId: string): Promise<AgentIdentity>

listAgents

List all agents for the authenticated tenant.

listAgents(): Promise<AgentIdentity[]>

signTransaction

Submit a transaction for policy evaluation and signing.

signTransaction(agentId: string, tx: SignTransactionInput): Promise<SignTransactionResult>

SignTransactionInput

| Field | Type | Required | Description | |-------|------|----------|-------------| | to | string | ✅ | Destination address | | value | string | ✅ | Value in wei (as string to avoid BigInt issues) | | data | string | — | Hex-encoded calldata | | chainId | number | — | EVM chain ID (defaults to the server's configured chain) |

SignTransactionResult

The return type is a discriminated union:

type SignTransactionResult =
  | { txHash: string }           // signed and broadcast
  | { status: 'pending_approval'; results: PolicyResult[] }  // queued
const result = await steward.signTransaction('scout-1', {
  to: '0xDEX...',
  value: '50000000000000000', // 0.05 ETH
  chainId: 8453,
});

if ('txHash' in result) {
  // Transaction was auto-approved and broadcast
  console.log('tx:', result.txHash);
} else {
  // Value exceeded auto-approve threshold — needs human sign-off
  console.log('queued, policy results:', result.results);
}

Throws: StewardApiError with status 400 if a hard policy rejects the transaction. error.data.results contains per-policy details.


signMessage

Sign an arbitrary message (EIP-191 personal sign) with the agent's key.

signMessage(agentId: string, message: string): Promise<SignMessageResult>
const { signature } = await steward.signMessage('scout-1', 'Hello Steward');

getPolicies

Retrieve the current policy rules for an agent.

getPolicies(agentId: string): Promise<PolicyRule[]>

setPolicies

Replace the full policy set for an agent (PUT semantics — replaces all existing policies).

setPolicies(agentId: string, policies: PolicyRule[]): Promise<void>
await steward.setPolicies('scout-1', [
  {
    id: 'daily-cap',
    type: 'spending-limit',
    enabled: true,
    config: {
      maxPerTx:   '100000000000000000',  // 0.1 ETH
      maxPerDay:  '500000000000000000',  // 0.5 ETH
      maxPerWeek: '2000000000000000000', // 2 ETH
    },
  },
  {
    id: 'whitelist',
    type: 'approved-addresses',
    enabled: true,
    config: {
      mode: 'whitelist',
      addresses: [
        '0xUniswapRouter...',
        '0xAavePool...',
      ],
    },
  },
  {
    id: 'hours',
    type: 'time-window',
    enabled: true,
    config: {
      allowedHours: [{ start: 9, end: 17 }], // 09:00–17:00 UTC
      allowedDays: [1, 2, 3, 4, 5],           // Mon–Fri
    },
  },
  {
    id: 'rate',
    type: 'rate-limit',
    enabled: true,
    config: {
      maxTxPerHour: 10,
      maxTxPerDay: 50,
    },
  },
  {
    id: 'auto',
    type: 'auto-approve-threshold',
    enabled: true,
    config: {
      threshold: '10000000000000000', // auto-sign below 0.01 ETH, queue above
    },
  },
]);

getBalance

Get the on-chain native balance for an agent wallet. Optionally pass a chainId to query a specific network (defaults to the server's active chain).

getBalance(agentId: string, chainId?: number): Promise<AgentBalance>
const balance = await steward.getBalance('scout-1');
// { balance: '1500000000000000000', formatted: '1.5', symbol: 'ETH', chainId: 8453 }

// Query a specific chain
const bscBalance = await steward.getBalance('scout-1', 56);

getHistory

Retrieve signing history for an agent.

getHistory(agentId: string): Promise<StewardHistoryEntry[]>
interface StewardHistoryEntry {
  timestamp: number; // Unix ms
  value: string;     // wei
}

createWalletBatch

Create multiple agent wallets in a single request. Optionally supply a shared policy set to apply to every created agent.

createWalletBatch(
  agents: BatchAgentSpec[],
  policies?: PolicyRule[]
): Promise<BatchCreateResult>

BatchAgentSpec

| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | ✅ | Unique identifier for the agent | | name | string | ✅ | Human-readable label | | platformId | string | — | Optional external ID |

BatchCreateResult

interface BatchCreateResult {
  created: AgentIdentity[];
  errors: Array<{ id: string; error: string }>;
}
const result = await steward.createWalletBatch(
  [
    { id: 'agent-1', name: 'Scout Alpha' },
    { id: 'agent-2', name: 'Scout Beta' },
    { id: 'agent-3', name: 'Scout Gamma' },
  ],
  [
    {
      id: 'spend',
      type: 'spending-limit',
      enabled: true,
      config: { maxPerTx: '100000000000000000', maxPerDay: '500000000000000000' },
    },
  ]
);

console.log(`Created ${result.created.length} agents`);
if (result.errors.length) {
  console.warn('Failures:', result.errors);
}

Types

AgentIdentity

interface AgentIdentity {
  id: string;
  tenantId: string;
  name: string;
  walletAddress: string;   // checksummed EVM address
  platformId?: string;     // your external agent ID, if provided
  erc8004TokenId?: string; // on-chain agent NFT ID, if registered
  createdAt: Date;
}

PolicyRule

interface PolicyRule {
  id: string;
  type: PolicyType;
  enabled: boolean;
  config: Record<string, unknown>; // see policy config types below
}

type PolicyType =
  | 'spending-limit'
  | 'approved-addresses'
  | 'auto-approve-threshold'
  | 'time-window'
  | 'rate-limit';

Policy Config Types

interface SpendingLimitConfig {
  maxPerTx: string;   // wei string
  maxPerDay: string;
  maxPerWeek: string;
}

interface ApprovedAddressesConfig {
  addresses: string[];
  mode: 'whitelist' | 'blacklist';
}

interface AutoApproveConfig {
  threshold: string; // wei — transactions at or below this are auto-signed
}

interface TimeWindowConfig {
  allowedHours: { start: number; end: number }[]; // UTC 24h
  allowedDays: number[]; // 0 = Sunday … 6 = Saturday
}

interface RateLimitConfig {
  maxTxPerHour: number;
  maxTxPerDay: number;
}

PolicyResult

Returned in rejection errors and pending-approval responses so you can see exactly which policy blocked or queued the transaction.

interface PolicyResult {
  policyId: string;
  type: PolicyType;
  passed: boolean;
  reason?: string; // human-readable explanation on failure
}

Error Handling

All methods throw StewardApiError on failure.

class StewardApiError<TData = unknown> extends Error {
  readonly status: number;  // HTTP status code (0 = network error)
  readonly data?: TData;    // parsed response body, if available
}

Common Status Codes

| Status | Meaning | |--------|---------| | 0 | Network error / connection refused | | 400 | Hard policy rejection — check error.data.results | | 401 | Invalid or missing API key | | 404 | Agent not found | | 409 | Agent ID already exists | | 500 | Server error |

Example

import { StewardClient, StewardApiError } from '@stwd/sdk';
import type { PolicyResult } from '@stwd/sdk';

try {
  const result = await steward.signTransaction('agent-1', tx);
} catch (err) {
  if (err instanceof StewardApiError) {
    if (err.status === 400) {
      const failed = (err.data as { results: PolicyResult[] })?.results
        ?.filter(r => !r.passed);
      console.error('Rejected by policies:', failed?.map(r => r.reason));
    } else if (err.status === 0) {
      console.error('Could not reach Steward API');
    } else {
      console.error(`API error ${err.status}:`, err.message);
    }
  }
}

Request Headers

The SDK sets these headers automatically:

| Header | Value | |--------|-------| | Content-Type | application/json | | Accept | application/json | | X-Steward-Key | Your apiKey | | X-Steward-Tenant | Your tenantId |


Policy Hard vs Soft Gates

Understanding how policies interact:

  • Hard policies (spending-limit, approved-addresses, rate-limit, time-window) — any failure rejects the transaction immediately with HTTP 400
  • Soft policy (auto-approve-threshold) — failure queues the transaction for manual approval (HTTP 202), but does not reject

This means you can set conservative limits that block dangerous transactions outright, while still letting moderately large (but in-policy) transactions go to a human reviewer rather than being auto-executed.


License

MIT