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

@ekwo-ai/transaction-journal

v0.13.0

Published

Reads a transaction journal saved as CSV — each transaction a run of rows under one date, type and number, closed by its total — with the list of accounts exported beside it, into plain objects in TypeScript: amounts as decimal strings, and what does not

Readme

@ekwo-ai/transaction-journal

Reads a transaction journal saved as CSV — the report a ledger prints of every transaction it posted, one after the other, each line of a transaction on a row of its own — into plain objects, in TypeScript, with no dependencies. Beside it, the list of accounts, exported the same way.

import { readTransactionJournal } from '@ekwo-ai/transaction-journal';

const books = readTransactionJournal([journal, accountList], { dateOrder: 'mdy' });

books.entries;    // [{ journal: 'Invoice', number: '1001', date: '2025-01-15', lines: […] }, …]
books.accounts;   // [{ code: '1200', name: 'Accounts Receivable (A/R)', type: 'Accounts receivable (A/R)' }, …]
books.violations; // a transaction that does not balance, a line that belongs to none

The files

The journal (required). Such a ledger exports its reports as a spreadsheet, not as CSV: open it and save it as CSV. A report is laid out for a person, and nothing on a line names the transaction it belongs to, so it is read in order:

  • the header is the first row that names a Date, an Account (or an Account #), a Debit and a Credit — the title rows above it are passed over, and so is an empty first column;
  • a row with an account and a date starts a transaction — unless it repeats the date, the Transaction Type and the Num of the transaction just before it, which a layout that prints them on every line does;
  • a row with an account and no date continues the transaction above;
  • a row with no account ends it: the total of a transaction, a blank row, the total of the report, the footer.

Optional columns: Transaction Type (kept as the journal of the entry), Num (its number and reference), Name — or Customer full name, Vendor, Supplier, Employee where the report shows those instead — and Memo/Description.

  • An account is identified by its number, Account #, where the report has the column — tick it among the report's columns before exporting — and otherwise by the name the list of accounts gives a number to, or by its name alone.
  • A date written in digits — 03/04/2026 — is read in the order the caller names (dateOrder: 'dmy' | 'mdy' | 'ymd') and refused without one: the order follows the region of the company, and the file does not say it. A date in ISO or with its month in letters (Jan 15, 2025) needs none.
  • An amount is read as a spreadsheet displays it. In a comma-separated file the decimal mark is a point and a comma only groups thousands, three digits at a time (1,234.50). In a file separated by a semicolon or a tab the decimal mark is the one mark the number carries, and thousands are grouped by a space only. A negative is a minus or brackets. A currency symbol, or anything else, is refused.

The list of accounts (optional): Account (or Full name), Type, and Account # where it has one; the rest is ignored. The type is kept in the list's words.

What it returns

The shape declared in src/types.ts, which is, field for field, the shape every reader of an accounting export in this repository declares for itself. A report says no currency: it prints the company's and does not name it, and no amount in another currency is read. Amounts are decimal strings, never negative. What does not add up comes back in violations; what is not a journal is thrown as a BooksFileError with a code.

It knows no chart of accounts: in Ekwo OS the correspondence is made by ekwo import transaction-journal <files…> --date-order mdy.

Sources

This reader was written against the Journal report of QuickBooks Online, read on 24 September 2026 from its help centre:

ekwo import quickbooks-online <files…> is the same as ekwo import transaction-journal.

What those pages do not state — the exact text of the title and total rows, whether a line repeats the date of its transaction — is why the reader finds the header by its columns, and a transaction by the order of its rows under either layout, rather than by position. The fixtures under test/fixtures/ are written by hand from those pages and hold no real data.

MIT.