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

@voyantjs/finance

v0.86.0

Published

Finance module for Voyant. Invoices, payments, credit notes, supplier payments, and finance notes.

Readme

@voyantjs/finance

Finance module for Voyant. Invoices, payments, credit notes, supplier payments, and finance notes.

Install

pnpm add @voyantjs/finance

Usage

import { financeModule } from "@voyantjs/finance"
import { createApp } from "@voyantjs/hono"

const app = createApp({
  modules: [financeModule],
  // ...
})

Entities

  • Invoices + Invoice lines (inv, inli)
  • Payments (pay)
  • Credit notes + Credit note lines (crn, cnli)
  • Supplier payments (spay)
  • Finance notes (fnot)
  • Invoice number series (invs)
  • Invoice templates (invt)
  • Invoice renditions (invr)
  • Tax regimes (txrg)
  • Invoice external refs (iner)

Invoice Rendition Events

Use financeService.bindInvoiceRendition(db, invoiceId, artifact, { eventBus }) when a rendered invoice artifact has already been stored and should be bound to the invoice as the ready rendition. The helper creates the invoice_renditions row with status: "ready" inside a transaction, optionally marks previous renditions of the same format as stale when replaceExisting is true, and then emits invoice.rendered after the transaction commits.

invoice.rendered is an internal service event. Subscribers receive metadata only:

  • invoiceId
  • invoiceStatus
  • invoiceType
  • renditionId
  • format
  • storageKey
  • contentType
  • byteSize
  • contentHash

The event does not include rendered document bodies or signed download URLs. Subscriber failures do not roll back the rendition write; use a durable job or workflow when a downstream reaction needs retries.

Customer-Safe Document Lookup

Public finance routes include booking-scoped document lookup for customer portal and checkout surfaces:

  • GET /v1/public/finance/bookings/:bookingId/documents
  • GET /v1/public/finance/bookings/:bookingId/documents/by-reference?reference=...
  • GET /v1/public/finance/documents/by-reference?reference=...

Booking-scoped routes require a checkout capability for the requested booking. The by-reference variant resolves invoice numbers and payment reference numbers only inside that booking, so a valid capability for one booking cannot retrieve documents from another booking.

Booking Tax Preview

Booking creation UIs can show the same tax line that booking finalization will persist by mounting the booking-tax extension:

import { createBookingTaxHonoExtension } from "@voyantjs/finance/booking-tax"

createApp({
  extensions: [
    createBookingTaxHonoExtension({
      resolveBookingTaxSettings: async (db) => {
        const settings = await getTaxSettings(db)
        return {
          taxPriceMode: settings?.taxPriceMode ?? "inclusive",
          taxPolicyProfileId: settings?.taxPolicyProfileId ?? null,
        }
      },
    }),
  ],
})

The settings callback is the storage seam. A template can read a singleton settings table, KV, environment configuration, or any other deployment-owned store, while @voyantjs/finance owns the tax policy rule walker, tax-regime lookup, product tax-class fallback, and inclusive/exclusive math.

Templates that already mount custom routes can call mountBookingTaxRoutes(...) from the same entrypoint instead of using the Hono extension.

Mounting this route registers:

  • GET /v1/admin/bookings/tax-settings
  • PATCH /v1/admin/bookings/tax-settings when updateBookingTaxSettings is supplied
  • POST /v1/admin/bookings/tax-preview

The preview endpoint is consumed by @voyantjs/bookings-react tax-preview hooks. Consumers that use the booking-create dialog without mounting the route will silently lose tax rows in the dialog summary because the client treats a missing preview as "no tax to show".

Server-side booking-finalize code can use the same helpers directly:

import {
  computeBookingItemTaxLine,
  loadProductTaxFacts,
  resolveBookingSellTaxRate,
} from "@voyantjs/finance/booking-tax"

Invoice FX Settings

Invoice issuing can enrich invoice.issued events with operator accounting currency, FX rate, FX commission, and effective provider rate. Configure the finance module with invoiceFxSettings or resolveInvoiceFxSettings, plus an exchange-rate resolver:

import {
  createFinanceHonoModule,
  createVoyantDataFxExchangeRateResolver,
} from "@voyantjs/finance"

createFinanceHonoModule({
  invoiceFxSettings: {
    baseCurrency: "RON",
    fxCommissionBps: 200,
    fxCommissionInvoiceMention: "2% comision curs risc valutar",
  },
  resolveInvoiceExchangeRate: createVoyantDataFxExchangeRateResolver({
    apiKey: process.env.VOYANT_DATA_API_KEY!,
  }),
})

The default data resolver uses @voyantjs/data-sdk to call the Voyant Data FX pair route /data/fx/v1/fx/pair/{invoiceCurrency}/{baseCurrency}. SDK responses can add provenance metadata such as source, quotedAt, and validUntil; invoice-issued events expose those as fxRateSource, fxRateQuotedAt, and fxRateValidUntil. If the invoice currency matches the operator base currency, no FX fields are emitted.

The same resolver also backs GET /v1/finance/invoice-fx-rate, which lets operator UI surfaces auto-fill cross-currency payment rates without exposing the Voyant Cloud API key to the browser.

Exports

| Entry | Description | | --- | --- | | . | Module export | | ./invoice-fx | Invoice FX settings, route helpers, and data FX resolver | | ./schema | Drizzle tables | | ./validation | Zod schemas | | ./booking-tax | Booking sell-side tax policy helpers and route mounting | | ./routes | Hono routes |

License

Apache-2.0