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

@fabric-harness/channels

v0.24.0

Published

Event-ingress channels (Slack, GitHub, …) for TechFabric Harness agents.

Readme

@fabric-harness/channels

Event-ingress channels for TechFabric Harness — turn platform webhooks (Slack, GitHub, …) into agent dispatches. The core Channel seam lives in @fabric-harness/sdk; this package provides the 17 vendor adapters behind subpath exports so vendor code stays out of core.

Handlers are written against the Web Request/Response API and crypto.subtle, so the same channel runs on Node and Cloudflare.

Maintained subpaths cover Slack, GitHub, Discord, Teams, Telegram, Twilio, WhatsApp, Google Chat, Linear, Notion, Stripe, Zendesk, Intercom, Shopify, Messenger, Resend, and Salesforce Marketing Cloud. Run fh add channel <name> to install a versioned recipe. Import channelCompatibility from @fabric-harness/channels/compatibility for supported provider APIs and the deprecation contract.

Slack

// .fabricharness/channels/slack.ts
import { createSlackChannel } from '@fabric-harness/channels/slack';

export const channel = createSlackChannel({
  signingSecret: process.env.SLACK_SIGNING_SECRET!,
  agent: 'assistant', // dispatch app mentions / threaded messages here
});

The events handler verifies the v0 HMAC signature, answers the URL-verification challenge, and dispatches app_mention / threaded message events to the agent keyed by the Slack thread — with the Slack event_id as the dedupe key (exactly-once), the team as tenantId, and the user as the acting actor (which powers on-behalf-of governance).

Outbound, bind the reply tool to the thread at agent init:

import { replyInSlackThread } from '@fabric-harness/channels/slack';

export default createAgent(({ id }) => {
  const thread = channel.parseConversationKey(id);
  return { tools: [replyInSlackThread(thread, { botToken: process.env.SLACK_BOT_TOKEN! })] };
});

Buzz (preview)

Buzz is a self-hostable Nostr-based workspace where humans and agents share channels. Unlike webhook vendors, Buzz pushes over a NIP-01 WebSocket, so ingress uses the buzz-tail transport shim: it holds a NIP-42-authenticated subscription and forwards events to the channel's /events route inside a timestamped X-Fabric-Signature: v1= HMAC envelope (same route a future Buzz workflow call_webhook egress can target). The handler additionally verifies each inner event's Schnorr signature, so the acting actor is the cryptographically proven author pubkey. Requires nostr-tools (declared dependency; the only non-Fetch/WebCrypto adapter, hence status: preview + sdk: nostr-tools in the compatibility contract).

// .fabricharness/channels/buzz.ts
import { buzzPublicKey, createBuzzChannel } from '@fabric-harness/channels/buzz';
import { buzzState } from '../state/buzz.js';

const channels = ['gtm-pipeline'];

export const channel = createBuzzChannel({
  agent: 'assistant',
  sharedSecret: process.env.BUZZ_ENVELOPE_SECRET!,
  selfPubkey: buzzPublicKey(process.env.BUZZ_PRIVATE_KEY!),
  community: 'acme',
  channels,
  decisionReceiptStore: buzzState.deliveryStore,
  onLifecycleEvent(notice) {
    // Content-free evidence only: edits/deletions never enter model context.
    console.info(JSON.stringify({ integration: 'buzz', ...notice }));
  },
});
// tail process (Node >= 22), co-deployed with the app
import { startBuzzTail } from '@fabric-harness/channels/buzz-tail';
import { buzzState } from '../state/buzz.js';

const channels = ['gtm-pipeline'];

startBuzzTail({
  relayUrl: process.env.BUZZ_RELAY_URL!,
  secretKey: process.env.BUZZ_PRIVATE_KEY!,
  community: 'acme', // must equal the channel's server-owned community
  channels, // same server-owned channel allowlist used by createBuzzChannel
  forwardUrl: 'https://app/channels/buzz/events',
  sharedSecret: process.env.BUZZ_ENVELOPE_SECRET!,
  cursorStore: buzzState.cursorStore,
  deadLetterStore: buzzState.deadLetterStore,
  onOperationalEvent(event) {
    // Content-free backfill, delivery, auth, reconnect, and shutdown evidence.
    console.info(JSON.stringify({ integration: 'buzz', ...event }));
  },
});

For PostgreSQL or Databricks Lakebase, inject the application's existing pg.Pool into the dependency-free structural client boundary. One scoped state object supplies all three production stores:

import { createPostgresBuzzPersistence } from '@fabric-harness/channels/buzz-postgres';
import { Pool } from 'pg';

export const buzzState = createPostgresBuzzPersistence({
  client: new Pool({ connectionString: process.env.DATABASE_URL }),
  consumerId: 'gtm-primary', // stable and unique per deployed consumer
});

createPostgresBuzzPersistence() initializes isolated cursor, dead-letter, and decision-card-delivery tables. Pass initialize: false when migrations own DDL and call ensurePostgresBuzzTables() from the migration boundary instead. The same contract works with Lakebase clients that implement the structural query() method; no Databricks or PostgreSQL dependency is loaded by the core channel adapter.

inspectPostgresBuzzHealth() is the read-only certification surface for one consumer. It returns only cursor lag/age, unresolved dead-letter depth, and prepared/published card counts; it never selects event, dead-letter, or decision-card payloads.

The default tail filter also observes stock Buzz message edits and event/channel deletions. createBuzzChannel() never dispatches these lifecycle events to an agent: its optional onLifecycleEvent sink receives a content-free notice with event ids, kind, author, scope, and decisionEffect: "none". Deleting a reaction therefore cannot reverse an immutable decision already committed by Platform. BUZZ_PROTOCOL_SUPPORT exposes this policy for capability discovery; direct messages, media, voice, and free-form edit approval remain unsupported.

The tail is a durable consumer, not a best-effort reconnect loop: it persists a cursor (advanced only after a 2xx forward or durably recorded dead-letter), pages a complete bounded POST /query snapshot backward and forwards it oldest-first on every (re)start, forwards in order with retry classification (408/429/5xx/network retry with bounded backoff; other 4xx go to deadLetterStore for reconciliation), answers NIP-42 challenges including OK acknowledgement and CLOSED re-subscription, enforces NIP-11 limits, and propagates cancellation and per-request timeouts. It fails closed when the cursor, backfill, or dead-letter store is unavailable. Use reconcileBuzzDeadLetters() from a bounded scheduled worker to replay unresolved records through the ordinary verified/governed ingress path. The channel route derives the tenant from its own community option (server-owned configuration) and refuses envelopes claiming any other community with 403 — the tenant is never taken from the event or envelope.

onOperationalEvent emits content-free backfill counts, forwarding outcomes, authentication renewals, reconnect attempts, and shutdown evidence. Sink failures are reported through onError without interrupting durable consumption. Applications generated by Buzz recipe v3 wire both operational and lifecycle events. Operators can preview and replay one bounded PostgreSQL/Lakebase dead-letter batch through the normal signed ingress route with:

fh buzz reconcile --dry-run --limit 100
fh buzz reconcile --limit 100 --json

Records are acknowledged only after a 2xx ingress response. Reports contain counts and the consumer id, never stored event content.

Outbound tools: postInBuzzChannel, replyInBuzzThread, addBuzzReaction. The tail also enforces NIP-11 at connect (requiredNips, default [1, 42]) and refuses relays that do not advertise them; probeBuzzRelay is exported for standalone detection.

Decisions are deterministic and model-free (@fabric-harness/channels/buzz-decisions, plan D14): postBuzzDecisionCard renders the canonical card from request data (never agent prose), signs it, and persists the exact immutable event plus its card receipt before relay I/O. A retry reuses the same Nostr event id, queries that id after an ambiguous response, and only then marks publication. The receipt binds (community, channel, cardEventId) to (approvalRequestId, requestVersion, parametersHash, options, expiry). The createBuzzDecisionBridge resolves a signed reaction through the receipt store and a fixed emoji table (👍/✅/+ → approve, 👎/❌/- → reject) into exactly one decision candidate carrying the attested Nostr identity and source-event proof; unmapped emoji surface for audit, free-form replies resolve to edit proposals that require structured confirmation, and everything else is ordinary conversation. The bridge performs zero authorization and signals nothing — the vertical's governed decision action owns binding resolution, capability, validation, and the decision transaction. Stock Buzz Desktop emits NIP-25 reactions with an e target and no h channel tag. To support that shape, give createBuzzChannel the same durable receipt store used by postBuzzDecisionCard plus an explicit channels allowlist. The route derives the channel only when the reaction has one target and exactly one receipt matches it inside that allowlist. Missing, malformed, cross-channel, and ambiguous matches are ignored; receipt-store failures fail the forward so the durable tail retries. Receipt correlation only recovers transport scope: the normal governed identity, membership, expiry, request-version, parameter-hash, and compare-and-swap checks remain mandatory downstream.

Migration from channels 0.18.x: postBuzzDecisionCard() now requires deliveryStore: BuzzDecisionCardDeliveryStore instead of a write-only receiptStore. The route still consumes its lookup-only decisionReceiptStore; in production both must be views over the same durable store (buzzState.deliveryStore). This closes the post-succeeded/receipt-write-failed split-brain window. Vendored kind constants are guarded by scripts/sync-buzz-kinds.mjs against a Buzz checkout's buzz-core/src/kind.rs.

See docs/channels-design.md.