Initial Commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# `collision-detector` — install-time auth-path collision check
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`collision-detector` is the install-time guard that prevents a plugin from
|
||||
accidentally squatting on the auth-provider's owned path prefix. It walks
|
||||
every plugin route, segment-aligns its path against the provider's
|
||||
`pathPrefix`, and emits `AUTH_PROVIDER.PATH_COLLISION` entries for every
|
||||
overlap that is not on the plugin's `publicRoutes` allowlist or marked
|
||||
`isPublic` on the per-route descriptor. Returning a report instead of
|
||||
throwing keeps callers in control of how to surface aggregated failures —
|
||||
typically the host turns a non-empty report into a single error listing
|
||||
every offender.
|
||||
|
||||
## Features
|
||||
|
||||
- Segment-aware containment — `/auth` matches `/auth` and `/auth/login` but
|
||||
NOT `/authoritative`.
|
||||
- Configurable prefix — a deployment that mounts the provider under
|
||||
`/myauth` shifts the collision domain accordingly.
|
||||
- Per-route `isPublic` opt-out for plugin routes that augment the auth
|
||||
surface (e.g. a custom `/auth/healthz`).
|
||||
- Plugin-level `publicRoutes` allowlist — identical effect, declared once
|
||||
per plugin manifest.
|
||||
- Aggregating reporter — every offender is returned in one frozen report.
|
||||
- Trailing-slash normalisation — `/auth` and `/auth/` are treated as equal.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { detectAuthPathCollisions } from "@suaveplan/api-auth-provider/collision-detector";
|
||||
|
||||
const report = detectAuthPathCollisions({ provider, plugins });
|
||||
if (report.hasCollisions) {
|
||||
throw new Error(`Auth-path collisions: ${report.entries.length}`);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Aggregating a problem-detail response across every offender:
|
||||
|
||||
```ts
|
||||
import {
|
||||
detectAuthPathCollisions,
|
||||
type CollisionReportEntry,
|
||||
} from "@suaveplan/api-auth-provider/collision-detector";
|
||||
|
||||
const report = detectAuthPathCollisions({ provider, plugins });
|
||||
if (report.hasCollisions) {
|
||||
const offenders = report.entries.map(
|
||||
(e: CollisionReportEntry) => ({ plugin: e.details.plugin, path: e.details.path })
|
||||
);
|
||||
return new Response(
|
||||
JSON.stringify({ type: "auth-collision", offenders }),
|
||||
{ status: 409 }
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `function detectAuthPathCollisions(input: DetectCollisionsInput): CollisionReport`
|
||||
- `function isInsidePrefix(routePath: string, prefix: string): boolean`
|
||||
- `function normalisePrefix(prefix: string): string`
|
||||
- `interface DetectCollisionsInput { provider; plugins }`
|
||||
- `interface PluginDescriptor { name; routes; publicRoutes? }`
|
||||
- `interface PluginRouteDescriptor { path; method?; isPublic? }`
|
||||
- `interface CollisionReport { entries; hasCollisions }`
|
||||
- `interface CollisionReportEntry { code; message; details }`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The detector returns a non-throwing report so the host can decide whether a
|
||||
collision is fatal or merely loggable — empirically a deployment running an
|
||||
older plugin against a newer provider needs the choice. Segment-aware
|
||||
matching is essential: a naïve `startsWith` would falsely flag
|
||||
`/authoritative` (or worse, `/auth-cache`) when the provider owns `/auth`.
|
||||
The root prefix `"/"` is short-circuited to "owns nothing" so a deployment
|
||||
that mistakenly configures the auth provider at the root does not blow up
|
||||
the whole route table; the path-prefix validator catches that mis-configuration
|
||||
at construction time. Two opt-out paths (per-route `isPublic` and plugin
|
||||
`publicRoutes`) coexist because manifests historically use one or the other
|
||||
and supporting both keeps migration tractable.
|
||||
Reference in New Issue
Block a user