Flake attributes

The flake outputs the api entrypoint (./api#...) exposes. This page is generated from the entrypoint itself every time the docs are built, so it always reflects the current outputs. Descriptions come from each attribute's meta.description.

Two kinds of attribute

The generated lists at the end of this page are api/'s own leaf outputs: api-http-stack, swagger-ui, openapi, the python tests, and so on. They are not the whole of ./api#.

Alongside them the entrypoint carries a deploy family: a full set of <group>-<effect>-<machine> attributes that provision the hosting-provider machines with api/ registered as an application. This is the api-only composition, for a downstream that wants the API service without a front-end. It is exposed at the flake's top level -- the same packages/apps/ devShells/nixosConfigurations outputs core exposes, so ./api# mirrors ./core#:

nix run './api#apps.<group>-<effect>-<machine>'

How the two sets combine:

  • apps, nixosConfigurations and deploymentAttributeNames come verbatim from the rendered deploy family.
  • packages and devShells are deploy.<x> // <api's own>, so api/'s leaf attributes win. The deploy names are all group- and effect-prefixed (dev-tf-*, hosting-provider-*, operator-*, ...), so they sit alongside the flat leaf names without collision; the single overlap is devShells.default, which stays the api devShell.

The names follow core's grammar

api/ does not invent attribute names: they follow core's <group>-<effect>-<machine>[-<verb>] grammar exactly, described at https://core.pages.git.fediversity.eu/flake-attributes.html. The derivations differ, because this family is rendered from a group set that has api/ folded in, but the naming, the all/combined aggregate targets and the verbs are the same. They are not enumerated here: the family is on the order of a thousand attributes, and core's page documents the pattern rather than the list. For the flat enumeration:

nix eval --json ./api#deploymentAttributeNames

How it is built (and how to extend it)

api/ maintains no deployment topology of its own. It reuses core's pure render combinator: core ships a frontend-free base group (abundos, the hosting-provider machines with no front-end registered), and api/ folds its own components.api registration and the api machine onto that base, then re-renders:

core = import ../core { inherit system sources pkgs; };
composedGroups =
  core.lib.foldGroupExtensions
    (core.lib.foldGroupComponents core.lib.baseGroups {
      hosting-provider = [ component ];  # api's components.api fragment
    })
    {
      hosting-provider = {
        machines.published.api = core.lib.components.hosting-provider.machine "api";
        deployRunners = [ "api" ];
        sourcePinnedApps = [ "api" ];
      };
    };
deploy = core.lib.render { inherit system sources groups = composedGroups; };

foldGroupExtensions hands the data to the group, which derives its zone and mail records again from the merged machines.

core is downward-only (it never names a front-end leaf), so this fold happens in the leaf, by name. A downstream that wants to extend the model further -- registering another application, or adding a group -- has two routes:

  • Fold onto the frontend-free base (core.lib.baseGroups) with its own application fragment, and call the SAME core.lib.render on the result. This is the api-independent path -- the downstream names only core.

  • Extend api's pre-extended group. api/ exposes its composed group set as api.lib.composedGroups (base + api's application), so a downstream that wants api/ registered too folds only its OWN application and machine onto that, rather than naming api's application again:

    composedGroups =
      core.lib.foldGroupExtensions
        (core.lib.foldGroupComponents api.lib.composedGroups {
          hosting-provider = [ component ];  # only the downstream's own fragment
        })
        { hosting-provider.machines.published.my-app = core.lib.components.hosting-provider.machine "my-app"; };

    foldGroupComponents appends, so chaining [api] (here) then [downstream] yields the same [...base, api, downstream] merge order -- hence the same deploy -- as one fold of [api, downstream].

Either way: no fork of core, no intermediate leaf to reach around. A front-end leaf is such a consumer and takes the second route: it folds its own component, and sets the front-end options of the api component (frontendBaseUrl, authzCallbackPath) in a components.api.module definition.

Packages

  • api-http-stack
  • asyncapi-docs: Rendered HTML documentation for the Fediversity AsyncAPI specification
  • asyncapi-spec
  • asyncapi-validate: Validates the generated Fediversity AsyncAPI specification
  • centrifugo-dev
  • db-diagram
  • default
  • dev-authz-token
  • docs: Generate static site docs of nix options
  • docs-with-diagram
  • openapi
  • openapi-validate
  • swagger-ui
  • terraform-backend-dev
  • windmill-dev

Checks

  • api-asyncapi-validate: Validates the generated Fediversity AsyncAPI specification
  • api-db-diagram: Render the entity-relationship diagram of the API's sqlite state store.
  • api-deploy-env-apex: Assert the api node bakes the fleet's apex into an operator deploy's env, so core's cross-group names resolve there, serves the curation and the credentials its own contracts resolve to, reads the addresses document of the hosting provider and not its full state, names no front-end, runs no Centrifugo and keeps the {host} placeholder on its AsyncAPI page, verifies the audit chain in the store of the service, sends its audit lines on an audit path that only its credential opens and only it reads the credential of, serves its documentation pages, and states the tester apex in no file of its own.
  • api-docs: Generate static site docs of nix options
  • api-http: Exercise the API's HTTP RPC endpoints end to end.
  • api-migration-kv: Assert the api writes the state pointers of a migration import to the KV mount, prefix and path that the operator deployer policy grants and the operator graph reads, and the domain claims to the path that the operator graph reads.
  • api-openapi-validate: Validate the generated OpenAPI specification.
  • api-pinned-schema: Assert a pinEffected build serves the effect's settings at the schema root, with the rename that moves a stored value there.
  • api-python-tests: Run the API's Python unit tests.
  • api-schema-parity: Assert the baked schema/application schemas/renames equal core's provider-configuration-schema/provider-application-schemas/configuration-renames outputs (what a pinned module_source builds).
  • api-state-migrations: NixOS test of the guard on the version of the state store of the api: a fresh installation records the number of the last Alembic revision without a dump, an upgrade dumps the database through the backup command of the streamingBackup contract and keeps only that dump, a downgrade is refused with exit status 78 while the api stays stopped and the data stays, and the audit verification waits for the guard.
  • apps-api: Deploy services through the API and verify the result.
  • asyncapi-docs: Rendered HTML documentation for the Fediversity AsyncAPI specification
  • treefmt: Check that the project tree is formatted