Files
suaveplan/openspec/changes/api-plugin-foundation/proposal.md
2026-05-27 23:29:53 +01:00

14 KiB

API Plugin Foundation

Package: @suaveplan/api-* (umbrella across the foundation family — see Stage breakdown below) Status: PROPOSED Type: new-package (umbrella)

Why

Genesis currently has no API host. packages/api/ contains only api-schemas (Zod request/response shapes) and sitemap (XML utility). Every plugin we ship next — billing, users, search, files, vault-API, drive-API, network-API, auth-API — needs the same scaffolding: lifecycle, routes, multi-tenancy, hot reload, observability, error contracts. Building that scaffolding once, at enterprise quality, is what unblocks every subsequent plugin.

This umbrella change captures the foundation as a single coherent design. The full design lives at docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md (committed under the brainstorming flow, reviewed by spec-document-reviewer, approved by the user with explicit "no MVP scoping — enterprise grade only" direction). This proposal is the OpenSpec rollup that the per-package child changes hang off.

What changes

Eight implementation stages, each landing a coherent slice. Every stage's packages are independent OpenSpec changes — proposals + tasks + spec deltas live under openspec/changes/api-<package-name>/. This umbrella tracks the rollup state.

Stage 1 — Contracts

Zero-runtime, types-only packages plus the Zod schemas + abstract interfaces every downstream package builds against. Stage gates: nothing in Stages 2-8 starts until all Stage-1 packages are merged.

Change ID Package Role
api-types @suaveplan/api-types Every cross-package interface (Principal, TenantId, PluginContext, RequestContext, Router contract, CapabilityMap, Manifest types, …). Zero runtime, zero deps.
api-manifest @suaveplan/api-manifest Zod schema for plugin.json, validators, dep-graph resolver, capability resolver.
api-router @suaveplan/api-router Abstract Router / Middleware / Request / Response types; composition (prefix mounting, middleware chains, blue-green slot management interfaces).
api-graphql @suaveplan/api-graphql Abstract Registry / Resolver / LoaderFactory; federation contract.
api-ws @suaveplan/api-ws Abstract WebSocket engine: ConnectionRegistry, SubscriptionBus, broker contract.
api-sse @suaveplan/api-sse Abstract SSE engine; Last-Event-Id resume contract.
api-auth @suaveplan/api-auth Session-resolver abstract: Request → Principal | null.
api-auth-provider @suaveplan/api-auth-provider Auth-provider abstract: account lifecycle routes (login/register/oauth/verify-email).
api-secrets @suaveplan/api-secrets Abstract Secrets contract.
api-tenant-provider @suaveplan/api-tenant-provider Abstract "list tenants" contract.
api-loader @suaveplan/api-loader Module resolver interface + RollbackJournal interface (impls in Stage 2).
api-lifecycle @suaveplan/api-lifecycle Lifecycle FSM definition (states + transitions, no concrete plugin yet).

Stage 2 — Host orchestration core

Change ID Package Role
api-host @suaveplan/api-host CapabilityRegistry, definePlugin, lifecycle driver, hot-reload primitive (blue-green + RollbackJournal), plugin ledger, admin API, error boundary, OTel scaffolding.

The host metadata DB schema (tables suaveplan_plugin_ledger, suaveplan_rollback_journal, suaveplan_saga_instances, suaveplan_saga_steps, suaveplan_2pc_transactions) ships with api-host's migrations.

Stage 3 — Worker isolation infrastructure

Change ID Package Role
api-worker-rpc @suaveplan/api-worker-rpc MessagePort protocol; correlation; AbortSignal forwarding; streaming; error reconstruction; backpressure.
api-worker-host @suaveplan/api-worker-host Worker-side runtime hosting one plugin; accepts capability proxies.
api-router-worker-bridge @suaveplan/api-router-worker-bridge Request/response marshalling main↔worker.
api-db-worker-proxy @suaveplan/api-db-worker-proxy Worker-side proxy → main-process DB adapter.
api-events-worker-proxy @suaveplan/api-events-worker-proxy Worker-side proxy → main-process @suaveplan/events bus.
api-secrets-worker-proxy @suaveplan/api-secrets-worker-proxy Worker-side proxy → main-process secrets adapter.
api-jobs-worker-proxy @suaveplan/api-jobs-worker-proxy Worker-side proxy → main-process job scheduler.
api-logger-worker-proxy @suaveplan/api-logger-worker-proxy Worker-side proxy → main-process logger.

Conformance gate: every Stage-4 capability MUST pass its conformance suite under both direct and worker-proxy surfaces before Stage 4 can be marked complete.

Stage 4 — Base adapters (both isolation surfaces)

Change ID Package Role
api-router-hono @suaveplan/api-router-hono Hono router adapter.
api-auth-jwt @suaveplan/api-auth-jwt Session resolver via @suaveplan/jws against JWKS/static key.
api-auth-anonymous @suaveplan/api-auth-anonymous Always returns null principal.
api-auth-bearer-static @suaveplan/api-auth-bearer-static Service-to-service static-token resolver.
api-tenant-resolver-jwt @suaveplan/api-tenant-resolver-jwt Reads ctx.principal.tenantId.
api-secrets-env @suaveplan/api-secrets-env process.env / Bun.env source.
api-db-adapter @suaveplan/api-db-adapter Bridge from @suaveplan/db → plugin DatabaseLike (Postgres/SQLite/Surreal).
api-tenant-provider-memory @suaveplan/api-tenant-provider-memory In-memory reference + test impl.

Stage 5 — Testing kit + conformance suites

Change ID Package Role
api-router-in-memory @suaveplan/api-router-in-memory In-memory router for tests.
api-auth-static-principal @suaveplan/api-auth-static-principal Test auth adapter — supplies a fixed Principal.
api-db-sqlite-memory @suaveplan/api-db-sqlite-memory In-memory SQLite DB adapter for tests.
api-events-in-memory @suaveplan/api-events-in-memory In-memory wrapper over @suaveplan/events for tests.
api-ws-broker-in-memory @suaveplan/api-ws-broker-in-memory In-memory broker for single-host + tests.
api-host-testing-kit @suaveplan/api-host/testing (subpath) createTestHost + await using lifecycle; not a separate package, ships as a subpath of api-host populated in this stage. Tracked here for sequencing.

Conformance suites under ./testing subpaths on every abstract package: runRouterConformance, runAuthSessionConformance, runTenantResolverConformance, runDbAdapterConformance, runSecretsConformance, runEventsBusConformance, runJobsConformance, runGraphqlEngineConformance, runWsEngineConformance, runSseEngineConformance, runSagaParticipantConformance, run2pcParticipantConformance.

Stage 6 — Distributed transactions + Better-Auth

Change ID Package Role
api-saga @suaveplan/api-saga Saga orchestrator; manifest-declared workflows; compensable steps; persisted state.
api-2pc @suaveplan/api-2pc Two-phase commit coordinator (Postgres PREPARE TRANSACTION).
api-auth-better-auth @suaveplan/api-auth-better-auth Better-Auth wraps both auth.session and auth.provider; owns its own DB connection.

Stage 7 — GraphQL + WebSocket / SSE engines

Change ID Package Role
api-graphql-yoga @suaveplan/api-graphql-yoga GraphQL Yoga engine adapter (default).
api-graphql-apollo @suaveplan/api-graphql-apollo Apollo engine adapter.
api-graphql-ui-graphiql @suaveplan/api-graphql-ui-graphiql GraphiQL UI at /graphql/ui (default).
api-graphql-ui-altair @suaveplan/api-graphql-ui-altair Altair UI alternative.
api-ws-bun @suaveplan/api-ws-bun Bun.serve WebSocket engine.
api-ws-broker-redis @suaveplan/api-ws-broker-redis Cross-host broadcast via Redis pub/sub.
api-sse-bun @suaveplan/api-sse-bun Bun.serve SSE engine.

Stage 8 — Sandboxing + cross-cutting middleware + authoring helpers

Change ID Package Role
api-sandbox-permissions @suaveplan/api-sandbox-permissions Permission model (fs/fetch allowlist, CPU/memory/wall-clock budgets).
api-sandbox-vm @suaveplan/api-sandbox-vm vm.Context based sandbox for non-WASM.
api-sandbox-wasm @suaveplan/api-sandbox-wasm WASM/WASI target host.
api-rbac @suaveplan/api-rbac Scope + rule-based authz; reuses @suaveplan/rules.
api-rate-limit @suaveplan/api-rate-limit Per-tenant / per-principal / per-IP token bucket.
api-openapi @suaveplan/api-openapi Emission from manifest + route schemas; via @asteasolutions/zod-to-openapi.
api-openapi-ui-scalar @suaveplan/api-openapi-ui-scalar Default /docs UI.
api-openapi-ui-swagger @suaveplan/api-openapi-ui-swagger Swagger UI alternative.
api-openapi-ui-redoc @suaveplan/api-openapi-ui-redoc ReDoc alternative.
api-audit-stdout @suaveplan/api-audit-stdout Default audit sink (containers redirect).
api-audit-file @suaveplan/api-audit-file File-rotating audit sink.
api-auth-rolled @suaveplan/api-auth-rolled Reference rolled-our-own provider via @suaveplan/crypto-rsa + webauthn + otp + srp + hibp + password-strength + password-generator.
api-secrets-bun @suaveplan/api-secrets-bun Bun.secrets (OS keystore).
api-secrets-vault @suaveplan/api-secrets-vault @suaveplan/vault source.
api-tenant-resolver-header @suaveplan/api-tenant-resolver-header Header-based tenant resolver.
api-tenant-resolver-subdomain @suaveplan/api-tenant-resolver-subdomain Subdomain tenant resolver.
api-plugin-example @suaveplan/api-plugin-example Reference plugin exercising every capability under every isolation tier. Load-bearing integration test.
create-suaveplan-plugin create-suaveplan-plugin Scaffold via @suaveplan/installer.

Out of scope

These are explicit non-goals — captured in the design doc Section 14 and repeated here so per-package changes don't re-litigate them:

  • Multi-region active-active host coordination — cross-region consistency of the plugin ledger / saga state / 2PC coordinator is a separate design. Foundation assumes one host per region.
  • Plugin marketplace / discovery service — foundation supports third-party plugins via npm; a curated marketplace + signing infra is its own product.
  • Built-in feature-flag system — @suaveplan/feature-flags already exists; plugins use it via the standard dep.
  • Reversible migrations — forward-only is the model. Plugin authors can write reversible if they want; host doesn't enforce.

Source mapping

This is a genesis-original family. No ../suaveplan/enterprise/<pkg>.md source. The single source of design intent is docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md (commits 1445b41e, e2051e07, 41419bae, 1eb2569f).

Per-package proposals link back to this design doc by section reference (e.g. "implements §5 Capability injection"). No package re-derives the design intent — each one specs ONLY its own surface and references the umbrella for cross-cutting concerns.

Verification approach

This umbrella has no test files of its own — verification is delegated to per-package changes. The umbrella tracks stage-level acceptance:

  • Stage 1 complete WHEN every Stage-1 child change is archived AND bun openspec validate passes for every spec delta.
  • Stage 2 complete WHEN Stage 1 ✓ AND api-host is archived AND boots empty (bun examples/api-host-empty.ts returns 200 on /internal/livez).
  • Stage 3 complete WHEN Stage 2 ✓ AND api-worker-rpc conformance suite passes against a trivial proxy capability under both direct and worker surfaces.
  • Stage 4 complete WHEN Stage 3 ✓ AND every Stage-4 adapter passes its conformance suite under both surfaces.
  • Stage 5 complete WHEN Stage 4 ✓ AND createTestHost boots api-plugin-example's skeleton against the in-memory adapter set with 100% conformance pass.
  • Stage 6 complete WHEN Stage 5 ✓ AND a multi-step saga in api-plugin-example runs end-to-end including a compensation path, AND api-2pc commits + aborts an integration scenario against real Postgres.
  • Stage 7 complete WHEN Stage 6 ✓ AND api-plugin-example mounts a federated GraphQL schema across two plugins AND publishes a tenant-scoped WebSocket broadcast.
  • Stage 8 complete WHEN Stage 7 ✓ AND api-plugin-example deploys cleanly under every isolation tier including sandboxed with WASM, AND create-suaveplan-plugin <name> scaffolds a working package whose tests pass first time.

Foundation complete when Stage 8 ✓ AND the reference plugin's full integration test (Section 13.5 of the design doc) is green in CI.

Migration impact

  • packages/api/api-schemas and packages/api/sitemap keep working as pure libraries during the foundation roll-out. After Stage 8 ships, each can optionally migrate to live as a plugin if it wants lifecycle hooks; if not, they stay as pure libs consumed by plugins.
  • No other monorepo package depends on the foundation today — the foundation is additive.
  • The host metadata DB introduces a new SQLite file at ./suaveplan-host.db by default. Production deployments will need a host-config decision (SQLite vs Postgres vs Surreal) but no existing data is touched.