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,108 @@
# @suaveplan/api-secrets-vault — SecretsLike adapter backed by @suaveplan/vault. The vault is passed in unlocked; the adapter never sees the master key. Per-plugin allow-list enforcement, vault `secret.updated` → host bus `secret.changed` forwarding, OTel `api.secrets.reads_total{backend="vault"}`, idempotent dispose. Real vault instance, no mocks.
Stage-8 `SecretsLike` adapter backed by `@suaveplan/vault`. The vault is
passed in already unlocked by the host's startup sequence; the adapter
never sees the master key. Per-plugin allow-list enforcement, vault
`secret.updated` → host event-bus `secret.changed` forwarding, OTel
`api.secrets.reads_total{backend="vault"}` counter, idempotent dispose.
Real vault instance, no mocks.
<!-- begin:auto-docs -->
## Documentation tree
- [adapter](./src/adapter/adapter.md) — Stage-8 concrete `SecretsLike` implementation backed by a `VaultSecretsBackend` (real `@suaveplan/vault.Vault` via `fro…
- [adapter](./src/adapter/adapter.md) — Stage-8 concrete `SecretsLike` implementation backed by a `VaultSecretsBackend` (real `@suaveplan/vault.Vault` via `fro…
- [allowlist](./src/allowlist/allowlist.md) — Compiled per-plugin allow-list of secret names. The vault-backed adapter calls `assertAllowed` BEFORE consulting the ba…
- [allowlist](./src/allowlist/allowlist.md) — Compiled per-plugin allow-list of secret names. The vault-backed adapter calls `assertAllowed` BEFORE consulting the ba…
- [error-codes](./src/error-codes/error-codes.md) — Frozen registry of `SECRETS_VAULT.*` error codes thrown by the vault-backed `SecretsLike` adapter and its watcher / all…
- [error-codes](./src/error-codes/error-codes.md) — Frozen registry of `SECRETS_VAULT.*` error codes thrown by the vault-backed `SecretsLike` adapter and its watcher / all…
- [from-vault](./src/from-vault/from-vault.md) — Bridge a live `@suaveplan/vault.Vault` instance to the structural `VaultSecretsBackend` the adapter consumes. The bridg…
- [from-vault](./src/from-vault/from-vault.md) — Bridge a live `@suaveplan/vault.Vault` instance to the structural `VaultSecretsBackend` the adapter consumes. The bridg…
- [otel](./src/otel/instruments.md) — OpenTelemetry instrument bundle for the vault-backed secrets adapter. Owns the three counters the package emits and a l…
- [instruments](./src/otel/instruments.md) — OpenTelemetry instrument bundle for the vault-backed secrets adapter. Owns the three counters the package emits and a l…
- [types](./src/types/types.md) — Structural type contracts the vault-backed secrets adapter consumes. Decoupling the adapter from the concrete `@suavepl…
- [types](./src/types/types.md) — Structural type contracts the vault-backed secrets adapter consumes. Decoupling the adapter from the concrete `@suavepl…
- [watcher](./src/watcher/watcher.md) — Live subscription that bridges the vault's `secret.updated` events onto the host event bus as `secret.changed`. Plugins…
- [watcher](./src/watcher/watcher.md) — Live subscription that bridges the vault's `secret.updated` events onto the host event bus as `secret.changed`. Plugins…
<!-- end:auto-docs -->
## Modules
- `./adapter` — `createVaultSecretsAdapter({ vault, allowlist })`
factory. Returns a `VaultSecretsAdapter` (extends `SecretsLike`)
enforcing the per-plugin allow-list BEFORE every read, raising
`SECRETS_VAULT.VAULT_LOCKED` on a locked vault without plaintext
fallback, wrapping unexpected backend throws as
`SECRETS_VAULT.VAULT_UNAVAILABLE`, emitting
`api.secrets.reads_total{backend="vault"}` on success.
- `./allowlist` — `createAllowlist({ names })`. Zod-validated factory
returning a frozen `Allowlist` (`isAllowed`, `assertAllowed`,
`names`). Compiled into an O(1) `Set` for the hot read path.
Shared between the adapter and the watcher.
- `./watcher` — `createSecretsVaultWatcher({ vault, allowlist, bus })`.
Subscribes once to the vault's `secret.updated` channel, forwards
allow-listed updates onto the host bus as `secret.changed` carrying
ONLY `{ name }` (value is never broadcast). Idempotent `dispose()`
with an in-listener disposed-flag guard that survives lazy backend
unsubscribes.
- `./error-codes` — `SECRETS_VAULT_CODES` registry: `NOT_FOUND`,
`NOT_ALLOWED`, `VAULT_LOCKED`, `VAULT_UNAVAILABLE`, `WRITE_FAILED`,
`INVALID_OPTIONS`. `SecretsVaultError` subclass with stable
`error.name === "SecretsVaultError"`.
- `./otel` — `getSecretsVaultInstruments()` / `resetSecretsVaultInstruments()`.
Counters: `api.secrets.reads_total{backend}`,
`api.secrets.writes_total{op}`,
`api.secrets.watcher_emits_total`.
- `./types` — `VaultSecretsBackend`, `VaultSecretListener`,
`VaultUnsubscribe`, `SecretChangedPayload`. Structural surface the
adapter consumes — decoupled from `@suaveplan/vault.Vault` so tests
can wire deterministic backends.
- `./from-vault` — `fromVault(vault)` bridges a live
`@suaveplan/vault.Vault` instance to the structural backend.
Secrets are stored as items with `category === "secret"` and a
single concealed field `"value"` so the underlying field-encryption
layer covers them at rest. In-bridge `secret.updated` fan-out fires
on every mutation that goes through the bridge.
## Quickstart
```ts
import {
createSecretsVaultWatcher,
createVaultSecretsAdapter,
fromVault,
} from "@suaveplan/api-secrets-vault";
import { EventBus } from "@suaveplan/events";
import { Vault } from "@suaveplan/vault";
const vault = Vault.open(vaultConfig);
await vault.unlock(password, secretKey);
const backend = fromVault(vault);
const adapter = createVaultSecretsAdapter({
vault: backend,
allowlist: ["STRIPE_SECRET_KEY", "JWT_SIGNING_KEY"],
});
const stripeKey = await adapter.require("STRIPE_SECRET_KEY");
const hostBus = new EventBus<{ "secret.changed": { name: string } }>();
const watcher = createSecretsVaultWatcher({
vault: backend,
allowlist: adapter.allowlist,
bus: hostBus,
});
hostBus.on("secret.changed", (p) => {
console.log(`refresh ${p.name}`);
});
```
## Conformance
Passes `runSecretsConformance` from `@suaveplan/api-secrets/testing` —
see `src/adapter/adapter.spec-conformance.test.ts`. The
`tests/integration.test.ts` suite drives a real
`@suaveplan/vault.Vault` end-to-end with Argon2id parameters set to
the minimum viable values so the lifecycle fits inside vitest's 60s
timeout. No mocks.