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

@jvaarala/vm-buketti

v0.2.0

Published

TypeScript client for the Finnish state budget open data API (budjetti.vm.fi)

Downloads

304

Readme

vm-buketti

TypeScript client for the Finnish state budget open data API at budjetti.vm.fi.

Turns the XML-based API into a lazy-loading tree you can navigate by awaiting properties — no manual XML parsing, no upfront fetches.

Install

npm install @jvaarala/vm-buketti

Usage

import { createVmBuketti } from '@jvaarala/vm-buketti';

// Node 18+ (direct fetch — no proxy needed):
const service = createVmBuketti();

// Browser (requires a CORS proxy):
const service = createVmBuketti({ proxyUrl: '/proxy' });

Merged view (recommended starting point)

getMergedKanta fetches one or more publications, merges their nodes by numero, sums amounts, and returns a fully materialised tree with an O(1) index.

const tree = await service.getMergedKanta({
  year: 2025,
  teos: ['tae', 'ltae1'],          // combine original + first supplementary budget
  kanta: 'eduskunnanKirjelma',
});

// Typed spending/income access with pre-computed amounts
tree.Paaluokka[0].amount;          // sum of maararaha across all specified teos
tree.Paaluokka[0].comparison;      // sum of aiemmin-budjetoitu*
tree.Paaluokka[0].Menoluku[0].Menomomentti[0].amount;

// O(1) lookup by composite key
tree.get('23.10.21');              // spending:  paaluokka.menoluku.menomomentti
tree.get('T11.01.01');             // revenue:   T prefix for income branch

// Unified interface — both branches have identical shape (BudgetNode)
tree.branches.menot.nodes;         // BudgetNode[] (Paaluokka level)
tree.branches.tulot.nodes;         // BudgetNode[] (Osasto level)
tree.branches.menot.get('23.10');  // BudgetNode | undefined

Navigate to a single kanta

const lk = await service.kanta({ year: 2025, teos: 'tae', kanta: 'eduskunnanKirjelma' });
const pkList = await lk.Paaluokka;   // LazyPaaluokka[]
const menot  = await pkList[0].Menoluku;

Raw lazy tree

const juuri  = service.getJuuri();
const vuodet = await juuri.Vuosi;                     // all budget years
const teos   = vuodet[0].Teos[0];                     // first publication (e.g. tae)
const kanta  = teos.Kanta[0];                         // budget version
const pkList = await kanta.Paaluokka;                 // expense main classes (lazy fetch)
const menot  = await pkList[0].Menoluku;              // chapters within first main class

Data is fetched on demand. Accessing a property for the first time fires the corresponding XML request; repeated accesses return the cached Promise. All methods on the same service instance share a fetch cache.

API

createVmBuketti(options?)

Returns a VmBuketti instance.

| Option | Type | Description | |--------|------|-------------| | proxyUrl | string | Prefix for CORS proxy requests, e.g. '/proxy'. Appends ?url=<encoded>. | | fetchXml | (url: string) => Promise<string> | Custom fetch function. Takes precedence over proxyUrl. | | onError | (error: Error, url: string) => void | Called when a sub-link fetch fails. Defaults to silent (partial data returned). |

service.getMergedKanta(query): Promise<MergedKanta>

Fetches one or more teos publications, merges their nodes by numero, and returns a MergedKanta.

| Field | Type | Description | |-------|------|-------------| | year | number | Budget year, e.g. 2025. | | teos | TeosType \| TeosType[] | One or more publications: 'tae', 'ltae1''ltae5'. | | kanta | KantaType | Version: 'eduskunnanKirjelma', 'hallituksenEsitys', 'valtiovarainministerionKanta'. |

MergedKanta has:

  • Paaluokka: MergedPaaluokka[] — spending branch, typed, with amount and comparison at every level.
  • Osasto: MergedOsasto[] — revenue branch.
  • branches: { menot: BudgetBranch; tulot: BudgetBranch } — unified interface with nodes and get(key).
  • get(key): BudgetNode | undefined — O(1) lookup across both branches. Menot keys: '23', '23.10', '23.10.21'. Tulot keys: 'T11', 'T11.01', 'T11.01.01'.

service.kanta(query): Promise<LazyKanta>

Navigates to a single LazyKanta without resolving or merging its children.

| Field | Type | |-------|------| | year | number | | teos | TeosType | | kanta | KantaType |

service.getJuuri(): Juuri

Returns the raw lazy-proxy root. Fetches are deferred until properties are accessed.

Budget hierarchy

Juuri
└── Vuosi[]           (year)
    └── Teos[]        (publication: tae, ltae1–ltae7)
        └── Kanta[]   (version: hallituksenEsitys, eduskunnanKirjelma, …)
            ├── Paaluokka[]   → Menoluku[]   → Menomomentti[]   (expenses)
            └── Osasto[]      → Tuloluku[]   → Tulomomentti[]   (revenues)

TypeScript types

All types mirror the XSD schema from budjetti.vm.fi. Lazy nodes (fetched on demand) use Lazy* prefixed types with Promise<T[]> children. The high-level merge API adds Merged* types with pre-computed amount/comparison fields. numero is typed string | number — numeric XML attributes (e.g. numero="01") are cast to JS numbers at parse time, so comparisons should use === against a number rather than a string.

import type {
  // Raw schema types
  LazyVuosi, LazyKanta, Menoluku,
  // High-level query types
  KantaQuery, MergedKantaQuery, KantaType, TeosType,
  // Merged node types (spending)
  MergedPaaluokka, MergedMenoluku, MergedMenomomentti,
  // Merged node types (revenue)
  MergedOsasto, MergedTuloluku, MergedTulomomentti,
  // Unified branch types
  MergedKanta, BudgetBranch, BudgetNode,
} from '@jvaarala/vm-buketti';

Enumerated attributes (e.g. teostyyppi, momenttityyppi) include a | (string & {}) fallback so that values the XSD hasn't yet listed — such as ltae6/ltae7 in live data — are accepted without TypeScript errors while known values still benefit from autocomplete.

Regenerating types

If the upstream XSD changes, regenerate src/schema.ts:

npm run gen-schema

The generated file must not be edited by hand.

Requirements

  • Node 18+ or any modern browser (uses fetch and DOMParser)
  • No runtime dependencies

Data license

The budget data accessed through this library is published by the Finnish Ministry of Finance as part of the open government data programme. Budget proposals have been available in machine-readable XML format since 2014 (government proposals from 2014, Ministry of Finance drafts from 2016). Parliamentary letters are also published in machine-readable form.

The data is licensed under the Creative Commons Attribution 4.0 International license (CC BY 4.0): http://creativecommons.org/licenses/by/4.0/

When using data retrieved via this library, you must credit the Ministry of Finance of Finland as the data source.

This library itself (the wrapper code) is MIT-licensed.