Skip to main content

Consumer Projection

A Consumer Projection is the generated boundary between Ninka's compiled authorization artifacts and application code.

Ninka writes canonical artifacts under ninka/out/. Those files are useful for verification, inspection, reproducibility, and tooling, but application code should not have to understand the artifact directory, bundle bindings, or entrypoint layout.

Instead, Ninka generates one application-facing source file that carries the policy references, input contracts, execution bundle, and verification metadata the runtime needs.

For TypeScript, the default location is normally:

src/generated/ninka.ts

For .NET, the output file is named explicitly:

npx ninka-authz build --out-csharp Generated/Ninka.g.cs

The projection is not a second authorization implementation. It is generated source that transports the result of compilation into the application.

What it contains

A Consumer Projection contains, in language-appropriate form:

  • generated policy references;
  • each policy's generated input contract;
  • the execution bundle used by those policies;
  • the manifest/build metadata the runtime needs to verify that bundle;
  • the tegata_hash carried by each generated policy reference.

It does not contain a second copy of the authorization rules as application control flow. In TypeScript, for example, the generated module imports the Ninka runtime; the runtime decodes, verifies, instantiates, and evaluates the embedded WASM.

Why the projection exists

Without the projection, application code would have to understand details such as:

  • where artifacts are stored;
  • which manifest belongs to which policy;
  • which execution bundle contains that policy;
  • which entrypoint the policy uses;
  • how a policy id is bound to its generated input type.

Those are compiler/runtime concerns. The application-facing contract is deliberately smaller:

compiled authorization

Consumer Projection

Ninka runtime

application decision

The application still decides where the Ninka instance lives, when authorization is called, how concrete input is constructed, and how the returned decision is enforced. Ninka does not generate or own the application's composition root.

Generated source that the application can track

A Consumer Projection is generated source and is normally tracked with the application source that imports it.

That makes changes to the authorization contract visible in code review, and it allows ninka-authz verify to regenerate the projection at the resolved path and require byte identity with the file on disk.

This does not make the projection part of ninka/out/. The two outputs have different purposes:

OutputPrimary reader
ninka/out/verify, Authorization Reference, tooling, and optional directory-based runtime loading
Consumer Projectionapplication code and the Ninka runtime it imports

Whether a repository tracks raw artifacts such as WASM is a separate Git policy; see Generated Files.

Runtime binding

A generated policy reference carries both the exact policy id and the tegataHash of the specification revision that produced it.

Before evaluating that reference, the runtime checks the hash against the manifest in the loaded bundle. A projection generated from one policy revision therefore cannot silently evaluate another revision. A mismatch is an integrity error, not an allow/deny decision.

One application-facing API

For TypeScript, the generated module exports:

createNinka
policies

Application code selects a policy from policies by a name derived from its id — hyphens removed, camelCase. The reference itself still carries the exact, untransformed id, and it fixes that policy's input type for check().

The .NET projection provides the equivalent policy reference and input contract while carrying the same compiled execution material into the application. The syntax differs by language; the boundary is the same.

See Runtime API, .NET Runtime API, and Authorization Compiler.