@nurix/apollo
v0.6.0
Published
The apollo CLI — bootstrap NuStack services into a repo via the Apollo discovery plane.
Readme
@nurix/apollo — the apollo CLI
The consumer-side installer for the Apollo discovery plane. It implements the build-time integration flow of the consumer journey: exchange your application key for service-scoped credentials, write them into a managed .env block, install the service's npm package, and record the consumes edge in your apollo.service.json (the application's bill of materials).
Interactive UX is built on @clack/prompts.
Install
Published to npm with public access — no npm account or token required to run it. That's deliberate: apollo is the on-ramp to the stack, so it must run before you have any credentials.
npx @nurix/apollo@latest --help # one-shot, no auth
npm install -g @nurix/apollo # or install the `apollo` binary globallyThe CLI ships no secrets — the tarball is just compiled JS + the bundled schema. Access to the restricted @nurix/* service packages (what apollo add installs) is granted at runtime: after you sign in (apollo login, the 24h device-trust flow), the CLI mints a narrow, per-device registry-proxy token and writes it into your user-level ~/.npmrc (a chmod 600, delimited apollo:managed block that never touches your own npm config). The real npm token never lands on your machine — your token only works against Apollo's own registry proxy. From then on apollo add <service> can pull restricted packages with no manual npm login. Opt out with NUSTACK_NPM_AUTH=off (you then provide npm auth yourself).
Commands (implemented)
apollo # bootstrap: validate the stored APOLLO_APP_KEY,
# run the login flow if it's missing/rejected,
# then finish with init's manifest scaffold
apollo login [--no-open] # browser SSO via 24h device trust: approve once at
# /device (Google SSO / OTP); re-logins within the
# window need no browser. Issues APOLLO_APP_KEY +
# APOLLO_APP_ID into the managed block.
apollo logout # local sign-out: drop APOLLO_APP_KEY from the
# managed block + sever device trust (next login
# needs browser approval); the key stays valid
# server-side until revoked in the console
apollo init # login (or paste a key), gitignore .env,
# scaffold apollo.service.json
apollo add <service> # the installer (see flow below)
apollo add # same, picking the service from the catalogue
apollo list # one line per catalogue service
apollo sync # re-project ALL credentials issued to this
# application into the managed block (server wins;
# stale entries removed)
apollo describe <svc> [--json] # full catalogue entry, pretty or raw
apollo validate [manifest] [--schema <pathOrUrl>]
# JSON Schema validation (apollo.dev/v1, draft-07;
# schema bundled into dist/ at build time)
apollo graph [--mermaid] # consumes-graph: ascii edges or mermaid `graph LR`
apollo doctor # key validity + per-credential health probes +
# manifest conformance + deprecated-consumes warnings
apollo open <svc> [--env <name>] # open endpoint (default production) or repo URLGlobal options: --apollo-url <url> (defaults to $APOLLO_URL, then the hosted instance https://apollo.nustack.tech) — the default means you never need to pass the URL; override only for a non-hosted Apollo.
apollo init
- Prompts for your
APOLLO_APP_KEY(created with your application in the Apollo console) and validates it against Apollo — no key, no install. - Writes it into the Apollo-managed block of
.env(+ a placeholder in.env.example) and makes sure.envis gitignored. - Offers to scaffold
apollo.service.jsonif the repo has none.
apollo add <service> — the installer
- Reads
APOLLO_APP_KEYfrom the managed block (or the environment); fails loudly with remediation if missing. - Fetches the catalogue and resolves the service (interactive select when no name is passed).
POST /api/v1/keys/exchange→{ endpoint, serviceKey }— idempotent per (application × service), so re-running is safe.- Writes
<SERVICE>_ENDPOINT+<SERVICE>_KEYinto the managed.envblock, placeholders into.env.example. - Installs the service's npm package when it ships one (package manager detected from the repo's lockfile).
- Appends the
consumesedge toapollo.service.json(offers a scaffold if the manifest is missing). - Best-effort health probe against the issued endpoint (never blocks).
The managed .env block
The CLI owns only the delimited block — everything outside it is yours and is never touched:
MY_OWN_SECRET=untouched
# >>> apollo:managed — do not edit by hand; the apollo CLI rewrites this block >>>
APOLLO_APP_KEY=018f… # opaque app id (UUID), no fixed prefix
EMAIL_ENDPOINT=https://…
EMAIL_KEY=apollo_svc_…
# <<< apollo:managed <<<Inside the block the server is the source of truth (manual edits get overwritten); outside it, nothing is ever rewritten.
Development
pnpm --filter @nurix/apollo build # tsc → dist/ (+ schema copy)
pnpm --filter @nurix/apollo typecheck
node packages/cli/dist/index.js --help # run from the repo rootESM, Node ≥ 22, strict TypeScript. bin is dist/index.js (apollo). Releases ship via .github/workflows/publish-cli-to-npm.yml — merges to dev touching packages/cli/** auto-publish a patch; dispatch the workflow for minor/major.
Current limitations
- The hosted catalogue is empty until the registry read path lands (consumer-journey.md R3) —
list/describe/graph/opendegrade with a clear message;apollo add <name>still works for services seeded into the KV catalogue, since the exchange resolves endpoints server-side. apollo syncneedsGET /api/v1/keys/credentials(journey R7) — the route is in the worker code; it goes live with the next worker deploy.- Exchange still returns
{endpoint, serviceKey}together; once it slims to credential-only with Apollo-served definitions (journey §9.2–§9.3), the client picks the endpoint up from the definition instead (src/lib/apollo_client.tsis the seam).
