Files
2026-06-09 21:06:27 +01:00
..
2026-06-09 21:06:27 +01:00

@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."

Documentation tree

  • error-codes — The reference plugin owns a small set of stable error codes that the integration suite asserts are surfaced through the…
    • error-codes — The reference plugin owns a small set of stable error codes that the integration suite asserts are surfaced through the…
  • events — The reference plugin both publishes and subscribes to events. This module exposes the topic names and the Zod payload s…
    • events — The reference plugin both publishes and subscribes to events. This module exposes the topic names and the Zod payload s…
  • instruments — The reference plugin declares three OTel instruments that mirror the telemetry.metrics[] block in plugin.json. The…
    • instruments — The reference plugin declares three OTel instruments that mirror the telemetry.metrics[] block in plugin.json. The…
  • plugin — The reference plugin's definePlugin invocation lives in its own module so the manifest, the integration test, and any…
    • plugin — The reference plugin's definePlugin invocation lives in its own module so the manifest, the integration test, and any…
  • routes — The route table is the heart of the reference plugin. Every route demonstrates one piece of the §6 11-step request pipe…
    • routes — The route table is the heart of the reference plugin. Every route demonstrates one piece of the §6 11-step request pipe…
  • schemas — Every route in the reference plugin is wired against a Zod schema so the §6 input-validation step always has a contract…
    • schemas — Every route in the reference plugin is wired against a Zod schema so the §6 input-validation step always has a contract…

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

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

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:

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.