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

@classytic/fin-io

v0.6.1

Published

Financial data interchange — parse and emit OFX, CAMT.053, MT940, CSV, IIF, Xero, Plaid into one canonical shape. Ledger-agnostic, ESM-first, tree-shakable, streaming-capable.

Readme

@classytic/fin-io

Parse and emit OFX / CAMT.053 / MT940 / CSV / IIF, plus live REST clients for QuickBooks Online, Xero, and Plaid — all normalized into one canonical shape.

Tree-shakable subpath exports. ESM-first. Zero runtime deps outside what each subpath needs.

Install

npm install @classytic/fin-io

Optional peers (per subpath): @classytic/mongokit, @classytic/primitives, @classytic/revenue.

Quickstart

import { parseOfx } from '@classytic/fin-io/formats/ofx';

const result = parseOfx(buffer);
if (result.ok) {
  for (const stmt of result.data) console.log(stmt.account.iban, stmt.transactions.length);
}

Subpaths

| Import | What you get | |---|---| | @classytic/fin-io | Canonical types + Money/date helpers | | @classytic/fin-io/core | HttpTransport, TokenStore, FinIoError, write primitives | | @classytic/fin-io/formats/{ofx,camt053,mt940,csv,iif} | File parsers (pure, no network) | | @classytic/fin-io/providers/quickbooks | QBO OAuth + REST + CDC + reports.trialBalance() + writes | | @classytic/fin-io/providers/xero | Xero OAuth + REST + reports.trialBalance() + writes | | @classytic/fin-io/providers/plaid | Plaid Link + /transactions/sync + webhook parser | | @classytic/fin-io/providers/plaid/auth | /auth/get — ACH/EFT/BACS/IBAN numbers | | @classytic/fin-io/providers/plaid/balance | Real-time /accounts/balance/get + validatePayment | | @classytic/fin-io/providers/plaid/identity | /identity/get + /identity/match | | @classytic/fin-io/providers/plaid/processor | Stripe / Dwolla / Galileo processor tokens | | @classytic/fin-io/providers/plaid/webhook-verify | ES256 JWT verifier (zero-dep) | | @classytic/fin-io/adapters/mongokit | Optional mongokit upsert helper |

Plaid — agent integration guide

fin-io's Plaid layer is curated, not a full SDK. Pick the right subpath for the job; use Plaid's official SDK alongside it for products we don't ship.

Pick the right subpath

| You want to… | Use | Notes | |---|---|---| | Ingest a bank feed | providers/plaid | linkToken.create + transactions.sync + parsePlaidTransactions | | Show / authorize against real balance | providers/plaid/balance | NEVER use cached /accounts/get for payment decisions | | KYC owner-match for ACH | providers/plaid/identity | summarize returns a per-account pass/fail verdict | | Hand ACH to Stripe / Dwolla / etc. | providers/plaid/processor | No raw routing/account in your system | | Originate ACH yourself | providers/plaid/auth | Accepts the PCI/NACHA burden | | Verify webhook | providers/plaid/webhook-verify | JWT + body hash + staleness, all in Node node:crypto |

Minimal flow

import { createPlaidClient, PLAID_PRODUCTS } from '@classytic/fin-io/providers/plaid';

const plaid = createPlaidClient({
  clientId: process.env.PLAID_CLIENT_ID!,
  secret: process.env.PLAID_SANDBOX_SECRET!,
  env: 'sandbox',
  store: myTokenStore,           // production: real DB-backed TokenStore
  checkpointStore: mySyncStore,  // production: real DB-backed SyncCheckpointStore
});

// 1. Mint a Link token for the FE.
const { link_token } = await plaid.linkToken.create({
  user: { clientUserId: userId },
  clientName: 'My App',
  products: [PLAID_PRODUCTS.transactions],
  countryCodes: ['US'],
  transactions: { daysRequested: 180 }, // optional; set at Link, not at sync
});

// 2. FE opens Link, returns public_token. BE exchanges + persists:
const { access_token, item_id } = await plaid.publicToken.exchange(publicToken);
await plaid.savePlaidItem(`${orgId}:plaid:${item_id}`, access_token, item_id);

// 3. Sync transactions; commit cursor atomically with your delta writes.
await plaid.transactions.sync({
  storeKey: `${orgId}:plaid:${item_id}`,
  async onComplete({ result, saveCheckpoint }) {
    await db.tx(async () => {
      await applyDeltas(result);
      await saveCheckpoint(); // skip to replay next time (safe default)
    });
  },
});

// 4. (Optional) Surface connection health on the FE.
const { item, status } = await plaid.item.get({ storeKey: `${orgId}:plaid:${item_id}` });
if (item.consent_expiration_time) warnUserBefore(item.consent_expiration_time);
// `item.error` is non-null when the Item needs attention (ITEM_LOGIN_REQUIRED, etc.)
// → mint an update-mode Link token with `linkToken.create({ user, accessToken })`.

// 5. (Optional) "Sync now" button — wire to `transactions.refresh`. Add-on product.
await plaid.transactions.refresh({ storeKey: `${orgId}:plaid:${item_id}` });
// Returns a request_id; deltas arrive via webhook + the next `transactions.sync`.

Constants

Plaid-shaped constants are mirrored from Plaid's official OpenAPI spec (plaid/plaid-openapi, 2020-09-14.yml) and re-exported from the Plaid root:

import {
  PLAID_PRODUCTS, PLAID_COUNTRY_CODES, PLAID_LANGUAGES,
  PLAID_ACCOUNT_TYPES, PLAID_ACCOUNT_SUBTYPES,
  PLAID_SANDBOX_INSTITUTIONS, PLAID_ERROR_CODES,
  PLAID_TRANSACTIONS_UPDATE_STATUS,
} from '@classytic/fin-io/providers/plaid';
import { PLAID_PROCESSORS } from '@classytic/fin-io/providers/plaid/processor';

Each Plaid call sends Plaid-Version: 2020-09-14. Override per-client via apiVersion. Local constant source: _constants.ts. Official spec: https://github.com/plaid/plaid-openapi/blob/master/2020-09-14.yml.

Sharp edges

  • validatePayment fails closed: depository-only, currency must match, available balance required (opt in to current fallback). All flagged via reason on the response.
  • item.remove({ storeKey }) deletes BOTH the token AND the sync checkpoint — never reuse a cursor across re-linked Items.
  • onComplete({ saveCheckpoint }) is the ONLY hook. Don't call saveCheckpoint? The cursor stays put and next sync replays. Crash-safe by default.
  • linkToken.create exactly one of: products (initial) / accessToken (update) / transfer.authorizationId (Transfer action). Anything else → ValidationError before the network call.

Plaid product coverage

| Product | Status | |---|---| | Link, /transactions/sync, /transactions/refresh, Accounts, Item lifecycle (item.get / item.remove) | ✅ providers/plaid | | Auth, Balance, Identity, Processor tokens, Webhook verify | ✅ own subpath each | | Transfer (/transfer/*) | ⏳ planned providers/plaid/transfer | | Payment Initiation (/payment_initiation/*) | ⏳ planned providers/plaid/payment-initiation | | Investments / Liabilities / Income | ❌ use Plaid's official SDK |

/transactions/get is intentionally not surfaced — Plaid has deprecated it in favor of /transactions/sync. New consumers use transactions.sync({ storeKey, onComplete }); cutover from a legacy ingest uses transactions.bootstrapCursorAtNow to skip historical replay.

QBO / Xero write capabilities

Both expose client.write.<entity>.{create, update, delete, dryRun, batch} for canonical migrations, plus raw.{create, update} for vendor-shaped escape hatches. dryRun({ mode: 'local' }) validates without network; mode: 'server' round-trips a throw-away record. Pass idempotencyKey for retry-safe writes.

What it does NOT do

  • No double-entry / accounting logic → @classytic/ledger
  • No tax computation → packages/tax/
  • No payment file generation (PAIN.001, NACHA) → future @classytic/payments-io
  • No PDF / OCR
  • No generic upsert() — pass create / update after resolving provider IDs

See CHANGELOG.md for releases.