Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
<!-- markdownlint-disable MD024 -->
# Capability Spec Delta: api-openapi (api-openapi)
**Package**: `@suaveplan/api-openapi`
**Status**: PROPOSED
> Every requirement below carries a `**Verified by:**` line at authoring time.
## ADDED Requirements
### Requirement: OpenAPI 3.1 document emitted from Zod schemas
The package SHALL emit an OpenAPI 3.1 document from every plugin's manifest plus every registered route's Zod schemas (request body / params / query / response). Conversion uses `@asteasolutions/zod-to-openapi`.
#### Scenario: full document covers every plugin
- WHEN two plugins are registered each with two routes
- THEN `emitter.getJson()` returns an OpenAPI 3.1 document with paths for all four routes
**Verified by:** `src/emitter/emitter.test.ts::"emits a 3.1 document covering every registered route"`
---
### Requirement: Namespacing rules are deterministic
The package SHALL set tags to each plugin's `displayName`, prefix component schemas with `<pluginName>.<TypeName>`, and set `operationId` to `<pluginName>.<method>.<routePath>`. operationIds MUST be unique across the merged document; collisions raise `OPENAPI_OPERATION_ID_COLLISION`.
#### Scenario: operationId is deterministic
- WHEN a billing plugin declares `GET /invoices/:id`
- THEN the emitted operationId is `billing.get./invoices/{id}`
#### Scenario: operationId collision raises error
- WHEN two plugins register routes that produce identical operationIds
- THEN emission raises `OPENAPI_OPERATION_ID_COLLISION`
**Verified by:** `src/namespacing/namespacing.test.ts::"operationId is deterministic"` AND `src/namespacing/namespacing.test.ts::"collision raises OPENAPI_OPERATION_ID_COLLISION"`
---
### Requirement: Security schemes inherit from the active auth adapter
The package SHALL read the active auth adapter's `securitySchemes` contribution and attach the default scheme to every route except those listed in any plugin's `publicRoutes`.
#### Scenario: public route has no security
- WHEN a route is listed in `publicRoutes`
- THEN the emitted operation has `security: []`
#### Scenario: non-public route inherits default scheme
- WHEN a route is not on `publicRoutes`
- THEN the emitted operation lists the auth adapter's default scheme
**Verified by:** `src/emitter/emitter.test.ts::"public route emits empty security"` AND `src/emitter/emitter.test.ts::"non-public route inherits adapter scheme"`
---
### Requirement: Endpoints serve json, yaml, and per-plugin filtered views
The package SHALL expose `GET /openapi.json`, `GET /openapi.yaml`, `GET /docs`, and `GET /docs/{plugin}` handlers. The filtered view MUST return only operations owned by the named plugin; an unknown plugin name raises `OPENAPI_UNKNOWN_PLUGIN_IN_FILTER` (HTTP 404).
#### Scenario: yaml endpoint returns yaml content-type
- WHEN a client requests `GET /openapi.yaml`
- THEN response Content-Type is `application/yaml` AND the body parses as YAML
#### Scenario: filtered view excludes other plugins
- WHEN `GET /docs/billing` is requested in a host with billing + users plugins
- THEN the response document contains billing routes only AND no users routes
**Verified by:** `src/endpoints/endpoints.test.ts::"yaml endpoint returns application/yaml"` AND `src/endpoints/endpoints.test.ts::"filtered view excludes other plugins"`
---
### Requirement: Missing schema is handled per strictness setting
The package SHALL read `host.openapi.strictness`. When `"warn"`, missing request/response schemas log a warning AND emit with `description: "schema-missing"`. When `"refuse-install"`, missing schemas raise `OPENAPI_MISSING_SCHEMA` BEFORE the plugin reaches `installed`.
#### Scenario: warn mode emits with placeholder
- WHEN a route has no response schema AND strictness is `"warn"`
- THEN emission succeeds AND the warning counter `api.openapi.missing_schema_total{plugin, route}` increments
#### Scenario: refuse-install raises
- WHEN strictness is `"refuse-install"`
- THEN emission raises `OPENAPI_MISSING_SCHEMA`
**Verified by:** `src/emitter/emitter.spec-conformance.test.ts::"warn mode emits placeholder and increments warning counter"` AND `src/emitter/emitter.spec-conformance.test.ts::"refuse-install raises OPENAPI_MISSING_SCHEMA"`