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/assets

v0.5.0

Published

Fixed-asset register + valuation engine on @classytic/mongokit — acquisition, multi-book depreciation (6 methods, half-year/mid-period conventions), IAS 16 revaluation, IAS 36 impairment, IAS 8 estimate changes, market/appraisal value history, disposal wi

Readme

@classytic/assets

Fixed-asset register + valuation engine on @classytic/mongokit.

Acquisition → multi-book depreciation → valuation → disposal, covering the full spectrum from personal net-worth tracking (market value of a property, gold, a vehicle) to IFRS-grade business accounting (IAS 16 revaluation, IAS 36 impairment, IAS 8 estimate changes) — with pure integer-minor-unit calculators that are audit-clean (schedule sums match the depreciable basis to the cent, no floating-point drift).

  • Mongokit repositories ARE the domain layer. Inherited CRUD / pagination / aggregation; claim() FSM transitions; claimVersion() on every carrying-amount write; arc createAdapter wiring for free.
  • Six depreciation methods — straight-line, declining balance, double-declining, sum-of-years-digits, units-of-production, manual — plus first-period conventions (half-year rule, mid-month proration).
  • Dual books. accounting drives asset totals + the GL bridge; tax (or any host-defined book) is a pure projection with its own method / life / rate.
  • Valuation layer. Append-only value history (market, insurance, tax-assessed, liquidation) with appraiser + evidence refs; currentValue() resolves book or market value at any point in time; revaluation / impairment / estimate changes rebase unposted periods prospectively — posted history is immutable.
  • Optional ledger bridge (LedgerPort, rule-23 host adapter) with deterministic idempotency keys — the non-atomic post sequence converges on crash-retry instead of double-posting.
  • Arc-standard events: 15 events, Zod catalog on ./events, P8 outbox dispatch, §P8.1 unit-of-work with post-commit flush.

Install

npm install @classytic/assets

Peers: @classytic/mongokit >=3.19, @classytic/repo-core >=0.8, @classytic/primitives >=0.11, mongoose >=9.4, zod >=4.

Quick start

import { createAssets, ensureAssetsReady } from '@classytic/assets';

const assets = await createAssets({
  connection: mongoose.connection,
  bridges: { ledger: myLedgerBridge },   // optional — runs open-loop without
  eventTransport: arcTransport,          // optional — in-process bus fallback
  // tenant: true,                       // opt-in; default = company-wide register
});
await ensureAssetsReady(assets);

const ctx = { actorId: 'user-1' };
const asset = await assets.repositories.asset.acquire({
  assetNumber: 'VEH-0001',
  name: 'Delivery Van',
  category: 'vehicle',
  cost: { amount: 2_000_000, currency: 'USD' },        // $20,000.00 in cents
  salvageValue: { amount: 200_000, currency: 'USD' },
  depreciation: { method: 'straight_line', periods: 60 },
}, ctx);
const id = String(asset._id);

await assets.repositories.asset.activate(id, ctx);
await assets.services.depreciation.generate(id, { firstPeriodFraction: 0.5 }, ctx);
await assets.services.depreciation.postPeriod(id, 0, {}, ctx);

// Tax book — DDB over 5 periods, projection-only:
await assets.services.depreciation.generate(id, {
  book: 'tax', methodOverride: 'double_declining', periodsOverride: 5,
}, ctx);

// Valuation — personal/insurance tracking and accounting events:
await assets.repositories.valuation!.record(id, {
  kind: 'market', value: { amount: 2_400_000, currency: 'USD' },
  appraiser: 'ACME Appraisals',
}, ctx);
await assets.services.valuation!.impair(id, {
  recoverableAmount: { amount: 1_200_000, currency: 'USD' },
}, ctx);
const { value } = await assets.services.valuation!.currentValue(id, { kind: 'market' }, ctx);

// Disposal with realized gain/loss + GL derecognition:
const { gainLoss } = await assets.repositories.asset.dispose(id, {
  proceeds: { amount: 1_000_000, currency: 'USD' },
}, ctx);

Domain verbs

| Surface | Verbs | |---|---| | repositories.asset | acquire, activate, dispose, retire, writeOff, transfer, loadAsset (tag OR ObjectId) + inherited CRUD | | services.depreciation | generate (per book, conventions, overrides), postPeriod, rebase | | repositories.valuation | record (market/insurance/tax_assessed/liquidation), latest + inherited CRUD | | services.valuation | revalue (IAS 16), impair / reverseImpairment (IAS 36), changeEstimate (IAS 8), currentValue | | engine | withTransaction (P8.1 UoW), syncIndexes, ensureAssetsReady |

Carrying-amount model

bookValue = grossCarryingAmount − accumulatedDepreciation − accumulatedImpairment
  • Revaluation (elimination approach): gross ← fair value, accumulated depreciation and impairment reset to 0, cumulative revaluationSurplus tracked on the asset. Unposted periods rebase over the new base.
  • Impairment: gross unchanged, accumulatedImpairment grows, book value drops to the recoverable amount; reversals are capped at the accumulated loss.
  • Posted history is immutable — every prospective change (estimate, revaluation, impairment) re-projects only scheduled rows; posted rows and the GL never rewrite.

Ledger bridge (host-side, rule 23)

Implement LedgerPort.postEntry and honor idempotencyKey as a dedupe key (return the existing entryRef). Kinds: depreciation, disposal (plus revaluation / impairment if your GL maps them — the domain events carry before/after/surplus for that decision). Reference adapter: be-prod/src/resources/assets/asset.adapters.ts.

Arc wiring

defineResource({
  name: 'asset',
  adapter: createAdapter(assets.models.FixedAsset, assets.repositories.asset),
  actions: {
    activate: { handler: (id, body, req) => assets.repositories.asset.activate(id, req.scope, body?.placedInServiceAt) },
    dispose:  { handler: (id, body, req) => assets.repositories.asset.dispose(id, body, req.scope) },
    // …retire / writeOff / revalue / impair follow the same shape
  },
});

Register events: for (const def of assetsEventDefinitions) registry.register(def); (import from @classytic/assets/events). Zod route schemas live on @classytic/assets/schemas.

Tests

npm test — 64 tests: pure-calculator unit suites (audit-clean invariants), convention proration, event-catalog no-drift, and mongodb-memory-server (replica set) integration: full lifecycle, valuation scenarios, dual books, tenant probe, ghost-event/unit-of-work.

Trademark

Code is MIT-licensed. "Classytic"/"arc" names + logos are trademarks of Classytic LLC — see TRADEMARK.md.