Skip to content

Nara v3.4.0 — Types catch wrong code. Nara catches wrong access.

Latest

Choose a tag to compare

@MasRama MasRama released this 10 Oct 05:51
· 2 commits to main since this release

Nara v3.4.0: Types catch wrong code. Nara catches wrong access.

v3.3 made Feature evolution provable. v3.4 turns the same idea on access: who can reach every route and hear every event is declared once, as data, and tested from what the application actually composes. It also makes Auth an official Feature, so applications evolve it instead of forking it.

Access, declared and proven

  • Every /api route declares its access. Guards record what they enforce (signedIn, allow, publicRoute). The server refuses to start while a route declares none, and names it. The authorization matrix is generated from Hono's route table, so a new route is tested against anonymous callers, members, permission holders, administrators, and temporary passwords without editing the test.
  • Each access rule is stated once. An AccessRule ({ permission } or ADMINISTRATOR) lives in the Feature contract, and the same value serves server routes, the browser host, route meta.requiresAccess, and the matrix.
  • Every live topic declares its audience. liveTopic(name, { rule, affected }). publish only accepts declared topics, so a publisher can name who was affected but can never widen the audience. The stream checks the rule at every publication, so a revoked grant stops events at once. A realtime matrix proves each topic reaches exactly the people it names.
  • Features declare their own permissions, route policies, refusal codes, activity, and table upkeep. Permissions are written at startup. Sensitive routes and body budgets sit next to app.route. Every code a route answers with is in its contract, and the typed client rejects any other. Each action shown in the Activity feed has a label, and maintenance tasks run on their interval.
  • Concurrent editing. Users and roles carry a revision. A stale save gets 409 STALE_REVISION with the current record, and the form merges three ways instead of overwriting. Open forms show who else is editing.

Official Features you evolve, not fork

  • One copy. An official Feature is its src/features/<name>, marked by a .nara/ folder and shipped from there. The official-features/ folder is gone. Tests that need the whole reference app live in the Feature's tests/app/ and are not shipped.
  • Auth is official. npm run nara -- evolve auth brings later fixes into your application. The choices that used to force a fork are now made where you compose it:
    • createAuthRoutes(activity, { registration: false | { role: 'customer' } }) closes self-registration or gives every new account a role.
    • declareRoles([{ slug, name, permissions }]) creates the roles your application needs at startup and never edits one that exists.
    • Your own sign-in pages can be built on createAuthClient and useAuthSession alone.
    • See docs/auth.md.
  • Activity is official, and the application decides which Features report to it through createActivityRecorder.
  • Users' host is a contract. It states duplicate-email outcomes, administrator roles, and revisions, and describeUsersHost is a conformance suite any provider can run.
  • The first administrator is created through Auth (ensureAdministrator), and tests create accounts through src/app/tests/personas.ts, never by writing Auth's tables.

Upgrade notes

A v3.3 application is not upgraded in place. Start new products from this release. These changes affect code written for v3.3:

  • The interface translation system is removed. Interface text is English and lives in each page's template. The UI shows refusals by message and branches on code.
  • The server refuses to start while an /api route has no signedIn, allow, or publicRoute.
  • Request bodies and query strings are validated by jsonInput/queryInput before state checks, so an invalid body answers 422 where it could previously answer 404, 409, or 403.
  • Permissions are declared by Features and written at startup. Auth's permission seeds are gone.
  • createEventStream takes allows(listener, rule). publish only accepts topics declared with liveTopic.
  • The Users host changed shape. It takes access rules plus allows instead of canManageUsers/canAssignRoles/canResetPasswords, administrators() replaces usersWithRole, and createAccount/updateAccount return duplicate-email as an outcome.
  • Users and roles have a revision. Updates send the revision they were based on.
  • audit is removed from the official catalog. The catalog is auth, health, users, activity.
  • src/shared/logging joins the guaranteed substrate official Features may import.
  • Database changes ship as forward-only Feature migrations. Run npm run migrate (or npm run setup).

The npm package @nara-web/cli is staged at packages/nara and has not been published to the registry yet.