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

@godoo-dev/stateman

v0.2.0

Published

Declarative Odoo resource planning, explicit recovery, apply and fresh drift for TypeScript

Readme

godoo-stateman

Compose desired Odoo configuration in TypeScript, review a deterministic plan, apply it with explicit recovery storage, and check fresh drift. The package @godoo-dev/stateman targets Node 24+ and Odoo 18. The v0.1.0 release was published on 25 October 2026; its release record reports verified npm bytes and installed API/CLI consumers. This is historical release evidence, not a fresh registry or application acceptance check.

The current acceptance target is installed API/CLI behavior against sanitized disposable Odoo 18. Native checks below distinguish offline simulation, installed artifacts and disposable integration. Application migration, custom addons, business workflows and deployed-instance acceptance remain with each application owner.

Install and develop

npm ci --ignore-scripts
npm run typecheck
npm test
npm run build
npm pack --pack-destination /absolute/path/to/artifacts

Install that tarball in a separate Node 24 ESM project:

npm install /absolute/path/to/artifacts/godoo-dev-stateman-0.2.0.tgz

The 0.2.0 candidate adopts published client 0.8.0 and introspection 0.2.4 in both runtime ranges and the resolved lock. Testcontainers is an optional application test supplier, not a Stateman dependency. The addon-inspection seam requires a structural adapter from the selected supplier. No sibling source import is required. Public npm distribution retains LGPL-3.0-only, source attribution and corresponding TypeScript source in the archive. See release preparation.

For the complete local delivery, install the supplied client, introspection, Stateman and testcontainers tarballs as direct file: dependencies. Retain the provided package lock and verify npm ls --all. For candidate qualification, prevent registry ranges from introducing nested older clients:

{
  "overrides": {
    "@godoo-dev/client": "$@godoo-dev/client",
    "@godoo-dev/introspection": "$@godoo-dev/introspection"
  }
}

Use the delivery's exact artifact manifest and fresh-install recipe. Candidate versions and hashes identify tested bytes; they do not claim registry publication.

Author and inspect offline

Only load trusted modules: TS/ESM and imported helpers execute with ordinary Node filesystem, process and network privileges. The loader is not a sandbox. It collects exported resources and arrays without calling exported helper functions.

import { children, resource } from '@godoo-dev/stateman';

export const project = resource('project.project', 'example.project', {
  name: 'Example',
  type_ids: children('project.task.type', 'project_ids', [
    resource('project.task.type', 'ready', { name: 'Ready', sequence: 1 }),
    resource('project.task.type', 'done', { name: 'Done', sequence: 2 }),
  ]),
});
npx stateman load resources/project.ts
npx stateman inspect resources

Both print offline inspection JSON without a connection. loadResources(path) is the API equivalent; inspectResources(definitions) renders in-memory definitions. Discovery supports .ts, .mts, .js and .mjs, skips hidden/build/vendor folders, and visits files and exports in sorted order. Re-exports of the same object are deduplicated within each evaluation. Separate definitions claiming the same XML ID fail. Local child IDs become example.project.ready; qualified IDs stay intact. Shared references to the same declared child retain that canonical identity.

md, mdFile, html and withCss retain the predecessor content behavior. mdFile strips leading YAML frontmatter unless stripFrontmatter: false. Relative content paths use the input directory or --content-root; use module-relative absolute paths for content in nested modules. Rendering is not HTML sanitization. translated supports scalar string fields through contextual writes and fresh language reads. Plans restore affected defaults after translation writes, using the caller's base context; choose it explicitly (for example { lang: false }). See translation write ordering. Separate language records are ordinary resources. Python assembly is an ordinary helper producing a string; Stateman never executes that Python. Computed fields and MIS Builder use the same resource graph and plan/apply/drift, including explicit multi-company report scope. HTML fields use bounded Odoo storage comparison, including translations; equivalentHtml exposes the same rules for read assertions. Authored strings, text whitespace and exact stale-plan observations remain intact. See HTML storage convergence for its limits.

Plan, apply and inspect fresh drift

A StateConnection deliberately binds a client to its current URL/database/user. It supplies identity() and read-only serverInfo(), plus inspectAddons() when addon requirements are requested. createConnection can wrap an already authenticated direct OdooClient; pass that client's URL explicitly. It never authenticates or changes safety settings. A connection module owns its own credential/authentication procedure; Stateman does not choose an environment or load credential files.

import {
  apply, createConnection, drift, openRecoveryJournal, plan,
} from '@godoo-dev/stateman';

// client has already been explicitly selected and authenticated by your application.
const connection = createConnection(client, { url: selectedUrl });
const journal = await openRecoveryJournal('/absolute/private/path/recovery.json');
try {
  const reviewed = await plan('./resources', connection, { recovery: journal.receipts });
  // Review or save this concrete plan before requesting writes.
  const result = await apply(reviewed, connection, { journal });
  if (!result.ok) throw new Error('Inspect result.results, result.recovery and result.drift');
  const fresh = await drift('./resources', connection, { recovery: journal.receipts });
  console.log(fresh.converged);
} finally {
  await journal.close();
}

The example assumes an existing private directory and an explicitly selected client; it is not a live deployment instruction. See the API guide for adoption, prerequisites, ownership and recovery details.

The CLI consumes the same API. connection.ts must export a StateConnection as default or connection. Keep it outside a directory being scanned for resources. options.json contains PlanOptions, such as required addons and selected XML IDs.

npx stateman plan resources --connection connection.ts --journal recovery.json --options options.json --out reviewed.json
npx stateman apply reviewed.json --connection connection.ts --journal recovery.json
npx stateman drift resources --connection connection.ts --journal recovery.json

plan exits 0 when it produces a plan. drift exits 0 for convergence or 2 for changes. Errors and incomplete/failed apply exit 1. Apply reads the saved rendered input, not newly evaluated authoring files, and rejects changes to its digest, connection or observed state before writes. Changed source requires a new plan. Journal changes also require re-planning with --journal. Initial validation is not a transaction or a concurrent-writer lock. Keep an environment under one operator.

Policies that affect writes

  • _ref: lookup(model, criteria) explicitly permits adoption/configuration. Zero matches default to an error; pass fourth-argument { onMissing: 'create' } to permit creation. Field lookups always require exactly one visible match.
  • ref('example.other') refers to another managed resource. A fourth-argument { dependsOn: ['example.action'] } declares opaque dependencies such as Python env.ref() calls. Stateman does not infer Python dependencies. A selection includes managed closure; missing definitions or unsupported cycles fail before writes.
  • Nested M2O, declared child/inverse, same-model, list and recursive JSON references resolve to committed IDs. X2many lists are additive. Opt into owned M2M membership with exact([...]); its visibility audit requires an explicit complete authorized-company context. Reviewed unlinks remove only those relations.
  • Odoo Reference fields such as ir.ui.menu.action use the same ref() syntax and resolve to model,id, including targets created in the same apply. See Reference fields for validation and clearing.
  • companyValues([{ company: lookup('res.company', { name: 'Company A' }), value }]) manages effective values of a company-dependent field on one resource identity. Omitted companies stay unmanaged. See the scoped-value contracts.
  • Legacy removeUnmanaged is ignored with a diagnostic; model-wide orphan policies are rejected. Enumerate M2M unlink IDs, or record removals plus an exact ownership allowlist. Other XML-ID aliases protect a record from archive/delete. Adoption and relation membership do not grant destructive ownership.
  • Models and desired fields are checked read-only. Access-denied metadata is unknown, not absent. Required addons need the generic inspection adapter and a complete installed dependency report. Plans install nothing and call no server action.
  • Managed crons are created inactive. Relevant existing active crons pause during changes, and activation follows successful mutations and a fresh readiness plan.
  • Apply returns committed/failed/skipped results and re-reads actual state even after partial failure. ok requires a fresh empty plan. There is no whole-run rollback.

Recovery and supported scope

Retain the recovery journal across runs and crashes. Before create, apply saves a pending receipt; after the returned record ID, it saves record-created before writing the XML ID; after identity registration it saves complete. The file helper uses an exclusive lock, atomic replacement and filesystem synchronization. A stale lock needs investigation. Other stores must make save durable before resolving.

Pass retained receipts into the next plan. A known created ID is adopted rather than created again. A pending receipt without an ID blocks automatic retry: inspect the uncertain RPC outcome, supply the verified ID or deliberately retire the receipt only after establishing that no record was created. Losing/omitting the journal forfeits this protection. A save failure stops further writes and returns the known receipt so it can be retained manually. Whole-run RPC rollback is not available.

The selected replacement for legacy snapshot helpers is bounded rendered offline fixtures and explicit seeding. createFixture, serializeFixture and parseFixture preserve symbolic desired state; seedFixture uses the same plan/apply/recovery engine and returns fresh target bindings. The CLI's --fixture flag accepts bounded JSON for load/inspect/plan/drift. Broad live clone/export/import is outside this path.

Explicit addon stages use planModules/applyModules with the published client lifecycle API. Review the addon preview, apply only the selected install/upgrade requests, invalidate introspection and make a fresh resource plan. Record planning does not install addons. Testcontainers remains independent: call Stateman seeding after the chosen disposable environment is ready.

Source and product direction

The DSL, offline loader/content and useful engine ideas derive from Marc Fargas's odoo-state-manager. The resource scheduler, policies and recovery replace unsafe predecessor behavior. See NOTICE.md, LICENSE and COPYING; corresponding TypeScript source ships in the tarball. Python source/tests/packaging are preserved as an incomplete prior implementation; see the Python reference. This is not a commitment to maintain parallel implementations.

The developer API guide describes the local core. The product contract and direction belong to this repository. The organization README provides optional family orientation; ordinary use requires no online profile fetch. Source, offline tests, package publication, disposable Odoo verification and consumer acceptance are distinct evidence.

Required checks

npm run check checks all TypeScript source/tests, runs maintained regressions and builds. Create a fresh external directory, set GODOO_ARTIFACT_DIR to it, then run npm run check:package followed by npm run check:odoo18. The package caller retains the exact tarball/manifest and verifies it in an isolated consumer; the Docker caller consumes those same bytes with owned Odoo18/Postgres15 resources, synthetic base-addon records and cron scheduling disabled. It records observed version/image identity and confirms all five owned resources are absent at cleanup.

For an unreleased supplier trial, the GODOO_SUPPLIER_MANIFEST option selects a sealed TS candidate manifest for both package and Odoo callers. They verify all three tarball hashes, install them directly with both dependency overrides and retain their source/artifact identities separately from the registry baseline. This is installed qualification, not publication.

The optional19 check requires explicit GODOO_ENABLE_ODOO19=1 and retained18 proof for the exact same candidate. It is not part of ordinary18 qualification. The CI required aggregate fails if mandatory checks are skipped/cancelled/failed. Remote protection and hosted execution remain separate evidence. Python publication and docs deployment workflows are retired. npm publication is an explicit manual operation; see release preparation and the concrete verifier for proof, isolation, installed supplier qualification and coverage limits.