Docs
/

@leumas/api-kit

The express boilerplate every Leumas router was writing for itself — async wrapping, HTTP-status errors, the admin/ownership predicates, the optional-guard and PassNode-meter seams, pagination and...

@leumas/api-kit

The express boilerplate every Leumas router was writing for itself. No domain logic, no express import — it sits under both halves of the routes/controllers split.

// a router
import { wrap, optionalGuard, meter } from '@leumas/api-kit';

const auth = optionalGuard(requireAuth);
const aiGuard = meter(passnode, 'feature:graphs.ai');

router.post('/:id/statements', wrap(async (req, res) => {
  const { texts, text, source, aiMeta } = req.body || {};
  res.json(await ctl.addStatements({ id: req.params.id, texts, text, source, aiMeta }, { user: req.user }));
}));
// a controller — no req, no res, callable from an action or a workflow node
import { httpError, requireOwned } from '@leumas/api-kit';

async function addStatements({ id, texts }, { user }) {
  const doc = await requireOwned((i) => conn.getById('reasoning_graphs', i), { user, id, kind: 'graph' });
  if (doc.kind === 'imported') throw httpError(400, 'imported graphs have no statements');
  ...
}

What each export replaces

ExportWas
wrap(fn)29 copies of const wrap = (fn) => …, in three incompatible bodies
httpError(status, msg, extra?) / assertHttp~50 hand-written Object.assign(new Error(m), { status }), plus two private copies of this helper
isAdmin(user)8 module-level definitions + 6 inlinings of req.user?.isAdmin === true
owns(row, ownerId)own() in products/leumas-api/src/app.jsunowned rows are shared
requireOwned(load, { user, id, kind })the 6 ownGraph/ownScene/ownMap/ownStation/ownItem/ownOutfit helpers — unowned rows belong to nobody; throws instead of writing the response
optionalGuard(g)14 copies of `requireAuth \\((req,res,next) => next())`
meter(passnode, feature)12 copies of the passnode?.guard ? … : next block
ownerStore(conn, coll) / ownerStores(conn)collStore() in app.js
paginate(query, opts)promoted from router-kit/src/social-lib.js

owns and requireOwned disagree about an unowned row on purpose — see the comment at the top of src/access.js. Merging them is a security change, not a cleanup.

Rules

  • Controllers may not import express and may not mention req/res. Enforced by

pnpm check:controllers.

  • The route table and its ordering may not drift. Enforced by pnpm check:routes against

ops/infra/baselines/api-routes.json.

  • There is no error class. instanceof across a pnpm workspace is a trap and nothing needs one —

every consumer reads .status, which errlog.finalHandler() already does.

What it exports

30 exports: 1 components, 0 hooks, 29 helpers. Import from @leumas/api-kit.

DEFAULT_CONCURRENCYassertHttpassertHttpasStringcopyNamehttpErrorhttpErrorisAdminisAdminmapPoolmetermeteroptionalGuardoptionalGuardoptionalMeteroptionalMeterownerStoreownerStoreownerStoresownerStoresownsownspaginatepaginateparseBoolrequireOwnedrequireOwnedslugifywrapwrap
Source shared/packages/api-kit/README.md (no-git)markdownjson
Generated from the Leumas repository. Every page cites the file it came from.leumas.techllms.txt