5.5 KiB
Capability Spec Delta: api-auth-provider (api-auth-provider)
Package: @suaveplan/api-auth-provider
Status: PROPOSED
Every requirement carries a
**Verified by:**line.
ADDED Requirements
Requirement: AuthProviderAdapter contract
The package SHALL export AuthProviderAdapter interface: pathPrefix: string (default /auth), routes(router: Router, ctx: PluginContext): void to register provider routes, lifecycle: { install, start, stop, uninstall } hooks matching the generic plugin lifecycle. The adapter MUST be generic over Caps extends CapabilityMap.
Scenario: every documented field present
- WHEN
expectTypeOf<AuthProviderAdapter>()is checked - THEN
pathPrefix,routes, and the four lifecycle hooks are declared
Verified by: src/provider/provider.spec-conformance.test.ts::"AuthProviderAdapter declares pathPrefix routes lifecycle"
Requirement: import z from "zod" everywhere
Every Zod import MUST use the default form.
Scenario: no named import of z
- WHEN the test greps
import zfrom"zod" - THEN zero matches
Verified by: tests/zod-import-form.test.ts::"every src file uses default-import z"
Requirement: Canonical provider route surface
The package SHALL export PROVIDER_ROUTE_SURFACE listing the canonical paths a provider OWNS (relative to pathPrefix): /register, /login, /logout, /refresh, /oauth/:provider/start, /oauth/:provider/callback, /verify-email/:token, /forgot-password, /reset-password. Providers MAY implement a subset; the host does not require every path.
Scenario: surface enumerates the documented paths
- WHEN the test inspects
PROVIDER_ROUTE_SURFACE - THEN every documented path is listed
Verified by: src/route-surface/route-surface.test.ts::"canonical surface lists every documented path"
Requirement: Path-ownership registry
The package SHALL export PathOwnership — a runtime registry. register(provider) claims provider.pathPrefix. A second register(provider2) with a different provider MUST throw AUTH_PROVIDER.MULTIPLE_PROVIDERS_REGISTERED. Re-registering the SAME provider instance MUST be a no-op (idempotent).
Scenario: double registration with different provider rejected
- WHEN provider A is registered AND provider B is registered
- THEN the second call throws
AUTH_PROVIDER.MULTIPLE_PROVIDERS_REGISTERED
Scenario: re-registering same provider is idempotent
- WHEN provider A is registered twice
- THEN the second call returns without throwing
Verified by: src/path-ownership/path-ownership.test.ts::"double registration rejected" AND src/path-ownership/path-ownership.test.ts::"re-registering same provider is idempotent"
Requirement: Collision detector
The package SHALL export detectAuthPathCollisions({ provider, plugins }): CollisionReport. A plugin route whose prefix overlaps with provider.pathPrefix AND is not in publicRoutes MUST be reported with code AUTH_PROVIDER.PATH_COLLISION AND details.plugin AND details.path. Plugin routes outside the auth prefix MUST NOT be reported.
Scenario: overlap reported
- WHEN provider owns
/authAND plugin declares route/auth/custom - THEN the report includes
{ code: "AUTH_PROVIDER.PATH_COLLISION", details: { plugin: ..., path: "/auth/custom" } }
Scenario: non-overlap not reported
- WHEN provider owns
/authAND plugin declares route/billing/invoices - THEN the report is empty
Scenario: configurable prefix shifts collision domain
- WHEN provider's
pathPrefix === "/myauth"AND plugin declares route/auth/x - THEN the report is empty AND a plugin route
/myauth/xwould be reported
Verified by: src/collision-detector/collision-detector.test.ts::"overlap with auth prefix reported" AND src/collision-detector/collision-detector.test.ts::"non-overlap not reported" AND src/collision-detector/collision-detector.test.ts::"configurable prefix shifts collision domain"
Requirement: CapabilityId augmentation contributes "auth.provider"
The package SHALL augment the CapabilityId union to include "auth.provider".
Scenario: auth.provider assignable to CapabilityId
- WHEN
expectTypeOf<"auth.provider">().toMatchTypeOf<CapabilityId>()is checked - THEN the assertion passes
Verified by: src/capability-id/capability-id.spec-conformance.test.ts::"auth.provider is a valid CapabilityId after augmentation"
Requirement: Error codes registry frozen
The package SHALL export AUTH_PROVIDER_CODES containing exactly: PATH_COLLISION, MULTIPLE_PROVIDERS_REGISTERED, PROVIDER_LIFECYCLE_FAILED, OAUTH_CALLBACK_INVALID_STATE.
Scenario: every code reachable
- WHEN the test enumerates
AUTH_PROVIDER_CODES - THEN every code has a production throw site
Verified by: src/error-codes/error-codes.spec-conformance.test.ts::"every AUTH_PROVIDER_CODES entry thrown by production path"
Requirement: Conformance harness for providers
The package SHALL export runAuthProviderConformance({ factory, label }). Every concrete provider in Stages 6/8 MUST pass it.
Scenario: harness covers path ownership, route surface, lifecycle, collision
- WHEN the harness runs against a stub provider
- THEN test categories exist for each documented behavior
Verified by: src/testing/conformance.test.ts::"harness covers path ownership, route surface, lifecycle, collision"