Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
# @suaveplan/api-plugin-example - Reference plugin for the @suaveplan/api-host plugin system. Exercises every contract surface reachable through createTestHost: definePlugin spec, REST routes (public, RBAC-gated, Zod-validated, streaming, idempotent, rate-limited, schema-violation), custom PLUGIN.EXAMPLE.* error codes mapped to HTTP statuses, manifest-declared OTel instruments (counter + histogram + gauge), seeded secrets, tenant-scoped DB, event publish + subscribe handlers. Ships its own integration suite that runs end-to-end against api-host/testing.createTestHost so any host-side change that breaks the plugin contract fails in one place.
Reference plugin for the `@suaveplan/api-host` plugin system. The
package is a load-bearing integration target, not a tutorial: every
contract surface the host exposes through `createTestHost` is wired
through one route or one hook here, and the package's own integration
test runs that surface end-to-end. When a host-side change breaks the
plugin contract, this test fails in one place against the in-memory
stack.
The plugin doubles as the canonical onboarding doc. When a plugin
author asks "how do I use capability X?", the answer is "look at how
`api-plugin-example` uses it."
<!-- begin:auto-docs -->
## Documentation tree
- [error-codes](./src/error-codes/error-codes.md) — The reference plugin owns a small set of stable error codes that the integration suite asserts are surfaced through the…
- [error-codes](./src/error-codes/error-codes.md) — The reference plugin owns a small set of stable error codes that the integration suite asserts are surfaced through the…
- [events](./src/events/events.md) — The reference plugin both publishes and subscribes to events. This module exposes the topic names and the Zod payload s…
- [events](./src/events/events.md) — The reference plugin both publishes and subscribes to events. This module exposes the topic names and the Zod payload s…
- [instruments](./src/instruments/instruments.md) — The reference plugin declares three OTel instruments that mirror the `telemetry.metrics[]` block in `plugin.json`. The…
- [instruments](./src/instruments/instruments.md) — The reference plugin declares three OTel instruments that mirror the `telemetry.metrics[]` block in `plugin.json`. The…
- [plugin](./src/plugin/plugin.md) — The reference plugin's `definePlugin` invocation lives in its own module so the manifest, the integration test, and any…
- [plugin](./src/plugin/plugin.md) — The reference plugin's `definePlugin` invocation lives in its own module so the manifest, the integration test, and any…
- [routes](./src/routes/routes.md) — The route table is the heart of the reference plugin. Every route demonstrates one piece of the §6 11-step request pipe…
- [routes](./src/routes/routes.md) — The route table is the heart of the reference plugin. Every route demonstrates one piece of the §6 11-step request pipe…
- [schemas](./src/schemas/schemas.md) — Every route in the reference plugin is wired against a Zod schema so the §6 input-validation step always has a contract…
- [schemas](./src/schemas/schemas.md) — Every route in the reference plugin is wired against a Zod schema so the §6 input-validation step always has a contract…
<!-- end:auto-docs -->
## Capability map (scope, against `createTestHost`)
| Capability | Surface in this package |
| --------------------------- | -------------------------------------------------------------------------- |
| `definePlugin` lifecycle | `src/plugin/plugin.ts` — install / start / stop / uninstall / health all wired |
| REST — public | `GET /example/public/ping`, `GET /example/health` |
| REST — RBAC-gated | `GET /example/invoices`, `GET /example/invoices/:id`, `POST /example/invoices` |
| REST — Zod-validated body | `POST /example/invoices` against `CreateInvoiceRequest` |
| REST — idempotent flag | `POST /example/invoices` (declared in `plugin.json` — host gate) |
| REST — rate-limited | `GET /example/rate-limited` (declared in `plugin.json` — host gate) |
| REST — streaming | `GET /example/stream/large-report` (chunked NDJSON) |
| REST — custom error codes | `PLUGIN.EXAMPLE.{SUBSCRIPTION_INACTIVE, INVOICE_NOT_FOUND, INVALID_INVOICE_STATE}` mapped in `errors.statusMap` |
| REST — response validation | `GET /_/test/fail-response?failResponse=1` (intentional schema violation) |
| Event publish | `example.invoice.created` on every `POST /example/invoices` happy path |
| Event subscribe | `users.user.deleted` via `makeUserDeletedHandler` |
| Secrets | `EXAMPLE_STRIPE_KEY`, `EXAMPLE_HMAC_SIGNING_KEY`, `EXAMPLE_WEBHOOK_TOKEN` |
| Tenant resolution | Seeded `tenant-int` reached via `X-Tenant-Id` |
| OTel instruments | `example.invoices_finalised_total`, `example.stripe.call_duration_ms`, `example.outstanding_invoice_count` |
## Capability map (declared in `plugin.json` for future Stages)
These surfaces are present in `plugin.json` because the design doc
§13.5 reference plugin SHALL declare every top-level manifest key.
The runtime implementations land alongside the host substrates as
those substrates ship in subsequent changes.
| Capability | Declared in `plugin.json` | Host substrate status |
| --------------------------- | ------------------------------------------------------------------ | ------------------------------------ |
| GraphQL types + subscription | `graphql.queries` / `mutations` / `subscriptions` | `@suaveplan/api-graphql-yoga` lands later |
| WebSocket fan-out (multi-host) | `websockets[]` with topic mapping | `@suaveplan/api-ws-bun` + broker shipped; cross-host federation later |
| SSE with `Last-Event-Id` | `sse[]` with `resume: "last-event-id"` | `@suaveplan/api-sse-bun` shipped; resume wiring later |
| Saga (3-step) + 2PC | `sagas[]` + `twoPhaseCommit` | `@suaveplan/api-saga` + `api-2pc` orchestrators land later |
| Migrations (v1 → v2) | `database.schemaVersion: 2` + `migrationsDir` | `@suaveplan/api-migrations` rollback driver lands later |
| Sandboxed (vm + wasm) | Future: rebuild against `api-sandbox-vm` / `api-sandbox-wasm` | Both shipped; isolation wiring through `createHost` lands later |
| Per-tenant cron + queued jobs | `jobs.cron[]` (incl. `perTenant`) + `jobs.queued[]` | `@suaveplan/job-scheduler` already lives universal; host bridge later |
## Running
```bash
bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-plugin-example
```
The integration suite at
`tests/integration/full-flow.integration.test.ts` runs against
`createTestHost` with the seeded principal, tenants, and secrets — no
external services required.
## Files
```text
plugin.json # Manifest declaring every top-level key
src/index.ts # Package barrel
src/plugin/plugin.ts # Frozen definePlugin record
src/routes/routes.ts # REST surface (10 routes)
src/schemas/schemas.ts # Zod request / response schemas
src/events/events.ts # Topic constants + handler factories
src/error-codes/error-codes.ts # PLUGIN.EXAMPLE.* registry + status map
src/instruments/instruments.ts # OTel counter + histogram + gauge-as-counter
tests/integration/full-flow.integration.test.ts
# End-to-end against createTestHost
tests/setup/polyfills.ts # In-memory MeterProvider install
```
## Verification
The acceptance gate runs:
```bash
bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-plugin-example
```
100% Istanbul coverage is enforced; the manifest `errors.statusMap`
is verified end-to-end against the runtime by the integration suite.