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

@duct-sdk/sdk

v0.5.13

Published

Duct SDK — manifest, CLI, and embed components for permissioned human and agent access to your product APIs.

Readme

██████╗  ██╗   ██╗ ╔██████  ████████╗
██╔══██╗ ██║   ██║ ╚════╗██ ╚══██╔══╝
██║  ██║ ██║   ██║      ║██    ██║
██║  ██║ ██║   ██║      ║██    ██║
██████╔╝ ╚██████╔╝ ╔██████╝    ██║
╚═════╝   ╚═════╝  ╚═════╝     ╚═╝

@duct-sdk/sdk

Let agents use your product safely.

npm version | Node 20+

The official Duct SDK and CLI. Scan your codebase, declare a manifest, push it to Duct, and embed a permissioned chat shell — so humans and AI agents call your existing APIs through one audited surface.

| Audience | What you get | | ------------- | ----------------------------------------------------------------------------------------------- | | Humans | Embedded chat shell, structured results, signed deeplink handoff into your app | | Agents | Permissioned API access from the same manifest — no scraping or screen automation | | Operators | Shell credentials, action tiers, and usage from the configured Duct dashboard |


Documentation

| Resource | Description | | --- | --- | | Developer docs (SITE_URL/docs) | Quickstart, CLI, frameworks, agents, threat model | | AI integration prompt (SITE_URL/docs/integration-prompt) | Full DUCT_CONFIG_PROMPT.md — copy into Cursor, Claude Code, Codex, or any agentic IDE | | TOKEN_SPEC.md | Token prefixes, claims, TTLs, and cross-language verify snippets | | Changelog (SITE_URL/changelog) | Platform release notes (includes SDK) |


AI-assisted integration

Duct ships a single integration prompt (DUCT_CONFIG_PROMPT.md) for greenfield setup or auditing an existing duct.config.ts. Paste it into your coding assistant with the product repo open; the agent generates or reviews manifest fields, the four wiring points, env vars, and a ship checklist.

Get the prompt: open SITE_URL/docs/integration-prompt on your configured deployment. The page is expandable and copy-ready, with platform URLs resolved for that environment.

Typical flow:

  1. Run duct init or duct init --manual for a first draft.
  2. Paste DUCT_CONFIG_PROMPT.md from the docs page to audit wiring and permissions.
  3. duct push, embed <DuctShell>, smoke-test in the dashboard playground.

Install

npm install @duct-sdk/sdk
# or run without installing:
npx @duct-sdk/sdk <command>

Global CLI (optional): npm i -g @duct-sdk/sdkduct <command>.

Node 22+: if the CLI exits with ERR_REQUIRE_ESM, use
node --experimental-require-module $(npx --no which duct) <command> or install globally.


Quickstart

1. Create a shell in the Duct dashboard and copy your API key.

2. Log in:

npx @duct-sdk/sdk login

3. Generate a manifest:

npx @duct-sdk/sdk init --manual    # instant template (recommended first run)
npx @duct-sdk/sdk init             # AI-assisted scan when your API is stable
npx @duct-sdk/sdk init --api-spec openapi.yaml

4. Push:

npx @duct-sdk/sdk push

5. Embed (Next.js App Router example):

import { DuctShell } from '@duct-sdk/sdk/next';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <DuctShell
          shellId={process.env.NEXT_PUBLIC_DUCT_SHELL_ID!}
          shellHost={process.env.NEXT_PUBLIC_DUCT_SHELL_HOST}
          onTokenRequest={async () => {
            const res = await fetch('/api/duct/token', {
              method: 'POST',
              credentials: 'include',
            });
            return (await res.json()).token ?? '';
          }}
          preset="tall"
          position="bottom-right"
          theme="system"
        />
      </body>
    </html>
  );
}

Four wiring points

Duct does not replace your API. You add four integration points in your codebase:

| # | What | Where | | --- | ----------------- | ----------------------------------------------------------------- | | 1 | Token minting | POST /api/duct/tokengenerateDuctToken | | 2 | API auth | Existing middleware also accepts verifyDuctToken delegated JWTs | | 3 | Deeplink receiver | POST /api/duct/receiveverifyDeeplinkToken | | 4 | Widget embed | <DuctShell> in root layout with onTokenRequest |

duct.config.ts declares routes, actions, deeplinks, and agent permissions. duct push uploads it; your business logic stays unchanged.


Import guide

Use the subpath that matches your runtime. The root export pulls React adapters and will crash plain Node servers.

| Import | Use when | | ------------------------- | ------------------------------------------------------------------- | | @duct-sdk/sdk/server | Any Node / Edge backend — tokens, config, introspect. No React. | | @duct-sdk/sdk/next | Next.js App Router (React) | | @duct-sdk/sdk/react | React without Next | | @duct-sdk/sdk/vite | Vite + Express (React) | | @duct-sdk/sdk/remix | Remix (React) | | @duct-sdk/sdk/sveltekit | SvelteKit | | @duct-sdk/sdk | React SSR frontends only — not Express/Fastify APIs |

// Server route (Express, Next.js route handler, Remix loader, …)
import { generateDuctToken, verifyDuctToken } from '@duct-sdk/sdk/server';

CLI

| Command | Description | | ------------------------------------ | ---------------------------------------- | | duct login | Authenticate with your Duct API key | | duct init | AI-assisted scan → config + shell files | | duct init --manual | Template without LLM | | duct init --update | Re-scan files changed since last push | | duct init --api-spec <path> | Manifest from OpenAPI / Swagger | | duct push | Upload duct.config.ts to Duct | | duct pull <hash> | Restore a manifest version from history | | duct promote --from <id> --to <id> | Copy manifest between environment shells | | duct scan | Drift between live API and manifest | | duct checkup | Env config and service connectivity |


Frameworks

| Framework | Import | Client env vars | | ------------------------ | ------------------------- | ---------------------------------------------------------- | | Next.js (App Router) | @duct-sdk/sdk/next | NEXT_PUBLIC_DUCT_SHELL_ID, NEXT_PUBLIC_DUCT_SHELL_HOST | | Vite | @duct-sdk/sdk/vite | VITE_DUCT_SHELL_ID, VITE_DUCT_SHELL_HOST | | Remix | @duct-sdk/sdk/remix | VITE_DUCT_SHELL_ID, VITE_DUCT_SHELL_HOST | | SvelteKit | @duct-sdk/sdk/sveltekit | PUBLIC_DUCT_SHELL_ID, PUBLIC_DUCT_SHELL_HOST | | React (generic) | @duct-sdk/sdk/react | framework-specific | | Express / Fastify / Node | @duct-sdk/sdk/server | — (server only) |

Vite + Express

import express from 'express';
import { generateDuctToken, verifyDuctToken } from '@duct-sdk/sdk/server';

router.post('/api/duct/token', express.json(), async (req, res) => {
  if (!req.user) return res.status(401).json({ error: 'unauthenticated' });
  const { token } = await generateDuctToken({
    secretKey: process.env.DUCT_SECRET_KEY!,
    shellId: process.env.DUCT_SHELL_ID!,
    userSession: { id: req.user.id, email: req.user.email },
    expirySeconds: 300,
  });
  res.json({ token });
});

Keep secrets in server .env only (DUCT_SECRET_KEY, DUCT_SHELL_ID). Client bundles use public VITE_* shell ID / host vars.


Deeplinks & replay protection

Declare deeplinks only for routes you have inventoried in routes[]. The receiver must verify signed tokens server-side — never trust raw query params.

Deeplink JWTs include a jti claim. Pass a replayStore to verifyDeeplinkToken so each token is single-use:

import {
  verifyDeeplinkToken,
  createDevReplayStore,
  RedisReplayStore,
} from '@duct-sdk/sdk/server';

const replayStore = createDevReplayStore(); // dev / single instance
// const replayStore = new RedisReplayStore(redisClient, 'duct:jti:'); // production

const result = await verifyDeeplinkToken(token, {
  secretKey: process.env.DUCT_SECRET_KEY!,
  expectedShellId: ductConfig.shellId,
  replayStore,
});

Details: TOKEN_SPEC.md.


Webhooks

Webhook URLs and signing secrets are configured in the dashboard → Shell → Settings → Webhooks, not in duct.config.ts. Your endpoint verifies X-Duct-Signature (HMAC-SHA256). Webhooks are optional for chat and actions.


Security

  • Keep DUCT_SECRET_KEY server-side — never in NEXT_PUBLIC_*, VITE_*, or client bundles
  • Default mutations to agentAccessible: false and sideEffects: true where appropriate
  • Rotate keys in the dashboard if credentials are exposed
  • Review agent-accessible actions before production — use the integration prompt at SITE_URL/docs/integration-prompt

Support

  • Docs: SITE_URL/docs on your configured deployment
  • npm: @duct-sdk/sdk