updated skills

This commit is contained in:
2026-06-09 21:06:27 +01:00
parent db1ce43ee1
commit 427a5bd919
1283 changed files with 24684 additions and 2313 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,411 +0,0 @@
# sp-stack Full-Stack Library Composer Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add an `sp-stack` skill that turns a whole-app description into a complete `@suaveplan/*` library set, wiring, and starter code — and relocate the `docs/` tree into the plugin that owns it.
**Architecture:** Approach C (hybrid). A curated capability manifest (`capabilities.md`) covers the common app capabilities with turnkey, code-minimal picks; the existing `sp` docs-traversal is the long-tail fallback. Both skills live in `document-navigator` and share the relocated `docs/` tree, referenced via `${CLAUDE_PLUGIN_ROOT}/docs/`.
**Tech Stack:** Claude Code plugin skills (Markdown + YAML frontmatter). No build step, no test runner — verification is path-resolution and content checks via `grep` / `test -f`.
**Spec:** `docs/superpowers/specs/2026-05-29-sp-stack-composer-design.md`
---
## Chunk 1: Relocate docs/ and rewrite path references
### Task 1: Move the docs tree into the plugin
**Files:**
- Move: `docs/` (excluding `docs/superpowers/`) → `plugins/document-navigator/docs/`
> Note: `docs/superpowers/` holds these specs/plans and must STAY at the repo root.
> Only the package-mirror categories move.
- [ ] **Step 1: Snapshot the pre-move reference set (verification baseline)**
Run:
```bash
grep -rIl --exclude-dir=.git -e "suaveplan-skills/docs" -e "\.\./docs/" -e " docs/" \
plugins GUIDELINES.md .claude-plugin
```
Expected: `plugins/document-navigator/skills/sp/SKILL.md` and `GUIDELINES.md` only. (These are rewritten in Tasks 2 and 4. If any OTHER file appears, stop and reassess — it is an unplanned reference into the docs tree.)
- [ ] **Step 2: Confirm what is under docs/ root**
Run: `ls docs/`
Expected: the 18 package categories (`api-stack`, `commerce`, `communication`, `devtools`, `foundation`, `gaming`, `geospatial`, …) plus the root files `README.md` and `_intro.md`, and the `superpowers/` directory. The `git mv` loop in Step 3 moves everything except `superpowers/` (so `README.md` and `_intro.md` move too).
- [ ] **Step 3: Move every category (not superpowers/) with git mv**
Run:
```bash
mkdir -p plugins/document-navigator/docs
for entry in docs/*; do
base="$(basename "$entry")"
[ "$base" = "superpowers" ] && continue
git mv "$entry" "plugins/document-navigator/docs/$base"
done
```
- [ ] **Step 4: Verify the move landed and superpowers/ stayed**
Run:
```bash
test -f plugins/document-navigator/docs/README.md && echo "DOCS-OK"
test -f plugins/document-navigator/docs/api-stack/api/api-plugin-payment/README.md && echo "SEED-OK"
test -d docs/superpowers && echo "SPECS-STAYED"
test ! -e docs/api-stack && echo "ROOT-CLEAN"
```
Expected: `DOCS-OK`, `SEED-OK`, `SPECS-STAYED`, `ROOT-CLEAN` all print.
- [ ] **Step 5: Commit**
```bash
git add -A
git commit -m "Move docs/ package mirror into document-navigator plugin"
```
---
### Task 2: Rewrite docs path references in sp/SKILL.md
**Files:**
- Modify: `plugins/document-navigator/skills/sp/SKILL.md`
The current file hard-codes `.claude/plugins/suaveplan-skills/docs/` in the Architecture table, File Structure block, and the two `grep` Patterns examples. Replace every occurrence with the portable `${CLAUDE_PLUGIN_ROOT}/docs/`.
- [ ] **Step 1: Write the failing check**
Run: `grep -c "suaveplan-skills/docs" plugins/document-navigator/skills/sp/SKILL.md`
Expected (before fix): a non-zero count (the stale paths still present).
- [ ] **Step 2: Replace the docs-tree row in the Architecture table**
Change:
```
| Docs tree | `.claude/plugins/suaveplan-skills/docs/` (`.md`-only mirror of `packages/`, maintained externally) |
```
to:
```
| Docs tree | `${CLAUDE_PLUGIN_ROOT}/docs/` (`.md`-only mirror of `packages/`, maintained externally) |
```
- [ ] **Step 3: Replace the File Structure block**
Change the fenced block that begins `.claude/plugins/suaveplan-skills/` so its root is `${CLAUDE_PLUGIN_ROOT}/` and the tree reads:
```
${CLAUDE_PLUGIN_ROOT}/
docs/ # mirrored .md tree (maintained externally)
<category>/
README.md
<subcategory>/
README.md
<package>/
README.md
src/
<module>.md
skills/sp/
SKILL.md # this file
```
- [ ] **Step 4: Replace the two grep Patterns examples**
Change:
```bash
grep -ri "sms" .claude/plugins/suaveplan-skills/docs/*/README.md
grep -ri "twilio" .claude/plugins/suaveplan-skills/docs/
```
to:
```bash
grep -ri "sms" ${CLAUDE_PLUGIN_ROOT}/docs/*/README.md
grep -ri "twilio" ${CLAUDE_PLUGIN_ROOT}/docs/
```
- [ ] **Step 5: Run the check to verify it passes**
Run:
```bash
grep -c "suaveplan-skills/docs" plugins/document-navigator/skills/sp/SKILL.md
grep -c "CLAUDE_PLUGIN_ROOT" plugins/document-navigator/skills/sp/SKILL.md
```
Expected: first command prints `0`; second prints a non-zero count.
- [ ] **Step 6: Commit**
```bash
git add plugins/document-navigator/skills/sp/SKILL.md
git commit -m "Point sp skill at \${CLAUDE_PLUGIN_ROOT}/docs"
```
---
### Task 3: Update the docs path in GUIDELINES.md
**Files:**
- Modify: `GUIDELINES.md` (§7.2, the `docs/` tree description, ~line 148)
- [ ] **Step 1: Locate the stale reference**
Run: `grep -n "suaveplan-skills/docs" GUIDELINES.md`
Expected: one hit in §7.2.
- [ ] **Step 2: Rewrite it to the new repo location**
Change `.claude/plugins/suaveplan-skills/docs/<category>/<subcategory>/<pkg>/` to `plugins/document-navigator/docs/<category>/<subcategory>/<pkg>/`.
- [ ] **Step 3: Verify**
Run: `grep -c "suaveplan-skills/docs" GUIDELINES.md`
Expected: `0`.
- [ ] **Step 4: Commit**
```bash
git add GUIDELINES.md
git commit -m "Update docs tree path in GUIDELINES §7.2"
```
---
## Chunk 2: The sp-stack skill and capability manifest
### Task 4: Author the capability manifest
**Files:**
- Create: `plugins/document-navigator/skills/sp-stack/capabilities.md`
Each row maps a capability to its turnkey `primary` pick, supporting packages, the
`example_doc` path (relative to `docs/`), and external prerequisites. All `example_doc`
paths below were verified to exist under the relocated tree.
- [ ] **Step 1: Create capabilities.md with the v1 seed (15–20 capabilities)**
```markdown
# Capability Manifest
Curated map of common app capabilities to turnkey `@suaveplan/*` packages. The
`sp-stack` skill consults this first; capabilities not listed fall back to the
`sp` docs-traversal. `example_doc` paths are relative to `${CLAUDE_PLUGIN_ROOT}/docs/`.
| capability | layer | primary | supporting | example_doc | external |
|---|---|---|---|---|---|
| api-host | backend | @suaveplan/api | — | api-stack/api/api/README.md | — |
| auth | backend | @suaveplan/api-plugin-auth | @suaveplan/api-auth-better-auth | api-stack/api/api-plugin-auth/README.md | Better-Auth config |
| multi-tenancy | backend | @suaveplan/api-plugin-tenant | @suaveplan/api-tenant | api-stack/api/api-plugin-tenant/README.md | — |
| payments | backend | @suaveplan/api-plugin-payment | @suaveplan/payment | api-stack/api/api-plugin-payment/README.md | Stripe/Adyen/PayPal account + secret key |
| email-campaigns | backend | @suaveplan/campaigns | @suaveplan/suppression, @suaveplan/delivery-tracking | communication/emails/campaigns/README.md | — |
| transactional-email | backend | @suaveplan/emailer | @suaveplan/email-templates | communication/emails/emailer/README.md | SMTP creds or Gmail REST token |
| file-upload | backend | @suaveplan/api-plugin-file-upload | — | api-stack/api/api-plugin-file-upload/README.md | storage backend |
| search | backend | @suaveplan/api-plugin-search | — | api-stack/api/api-plugin-search/README.md | — |
| realtime-sse | backend | @suaveplan/api-plugin-sse | @suaveplan/api-sse-bun | api-stack/api/api-plugin-sse/README.md | — |
| rate-limiting | backend | @suaveplan/api-plugin-rate-limit | @suaveplan/rate-limiter | api-stack/api/api-plugin-rate-limit/README.md | — |
| notifications | backend | @suaveplan/api-plugin-notifications | @suaveplan/notification-channel | api-stack/api/api-plugin-notifications/README.md | APNs key (push) |
| webhooks | backend | @suaveplan/api-plugin-webhook | @suaveplan/webhook-client | api-stack/api/api-plugin-webhook/README.md | — |
| booking | backend | @suaveplan/booking | — | commerce/booking/booking/README.md | — |
| validation | foundation | @suaveplan/validation | — | foundation/data/validation/README.md | — |
| pwa | frontend | @suaveplan/pwa | — | foundation/data/pwa/README.md | — |
| client-data-hooks | frontend | @suaveplan/react-packer | @suaveplan/packer-browser | foundation/data/react-packer/README.md | React 19 |
| cli | devtools | @suaveplan/cli | — | devtools/tooling/cli/README.md | — |
| testing | devtools | @suaveplan/test-vite | — | devtools/tooling/test-vite/README.md | — |
```
(`booking` doc path is verified present at `commerce/booking/booking/README.md`.)
- [ ] **Step 2: Verify every example_doc path resolves**
Filter to data rows by **content**, not line number (the preamble makes line offsets
brittle): keep only lines starting with `|`, drop the header row (the `capability`
column is `$2` because the leading `|` makes `$1` empty) and the `|---|` separator
(`$6` is only dashes/spaces).
Run:
```bash
cd plugins/document-navigator
awk -F'|' '/^\|/ && $2 !~ /capability/ && $6 !~ /^[- ]*$/ {gsub(/ /,"",$6); print $6}' \
skills/sp-stack/capabilities.md \
| grep -v '^$' | grep -v '^—$' \
| while read p; do [ -f "docs/$p" ] && echo OK || echo "MISSING $p"; done \
| sort | uniq -c
cd -
```
Expected: a single line `18 OK`; no `MISSING` lines. (A `MISSING <path>` line means that
manifest row points at a doc that does not exist — fix the path before continuing.)
- [ ] **Step 3: Commit**
```bash
git add plugins/document-navigator/skills/sp-stack/capabilities.md
git commit -m "Add sp-stack capability manifest (v1 seed)"
```
---
### Task 5: Author the sp-stack SKILL.md
**Files:**
- Create: `plugins/document-navigator/skills/sp-stack/SKILL.md`
- [ ] **Step 1: Create SKILL.md**
````markdown
---
name: sp-stack
description: Describe a whole website, service, or app and get the complete @suaveplan/* library set, host wiring, and starter code — selected to minimise the code you write.
---
# Stack Composer for Suaveplan
Turn a natural-language description of an entire website, service, or app into the full
set of `@suaveplan/*` packages needed across all layers, plus the wiring and starter
code to compose them. Selection always prefers the highest-level turnkey package so the
user writes as little code as possible.
This skill is the whole-app counterpart to `sp` (which finds a library for a single
stated need). Use `sp-stack` when the input describes a product; use `sp` for "which
library does X" or "how do I use Y".
## Inputs
A product description, e.g. *"a multi-tenant SaaS with email campaigns, Stripe billing,
and a booking calendar"*.
## Sources
| Source | Path |
|--------|------|
| Capability manifest | `${CLAUDE_PLUGIN_ROOT}/skills/sp-stack/capabilities.md` |
| Docs tree (fallback + examples) | `${CLAUDE_PLUGIN_ROOT}/docs/` |
## Flow
1. **Decompose.** Parse the description into a list of capabilities and infer the
app-type (service / website / app / game). Map each capability to the manifest
vocabulary (auth, multi-tenancy, payments, email-campaigns, file-upload, search,
realtime-sse, rate-limiting, notifications, webhooks, booking, validation, pwa,
client-data-hooks, cli, testing, …).
2. **Resolve each capability.**
- **Manifest hit** → take `primary` + `supporting`; open its `example_doc` under
`${CLAUDE_PLUGIN_ROOT}/docs/` and read the quick-start block verbatim.
- **Manifest miss** → fall back to the `sp` docs-traversal: root README →
`<category>/README.md` → `<subcategory>/README.md` → package README, ranking
turnkey `api-plugin-*` / engine packages above low-level primitives.
3. **Assemble.** Dedupe packages, order by dependency (turnkey plugins first), group by
`layer` (backend / frontend / foundation / devtools).
4. **Read examples.** Pull the quick-start code verbatim from each chosen package's
docs. Never fabricate import paths.
5. **Emit** the output below.
## Output
- **Bill of materials** — grouped by layer, one-line reason per package.
- **Install** — a single `bun add @suaveplan/… …`.
- **Wiring** — the `createHost({ plugins: [...] })` composition (see
`docs/api-stack/api/api/README.md` for the host entry point).
- **Starter code** — stitched from the verbatim docs examples.
- **Gaps & prerequisites** — capabilities with no `@suaveplan` package (the user writes
custom code or brings a third-party lib) and required external services (API keys,
datastores) drawn from each manifest row's `external` column.
## Constraints
- Only reference packages that exist under `${CLAUDE_PLUGIN_ROOT}/docs/`. Never invent
package names.
- Use exact `@suaveplan/<name>` identifiers.
- Extract code examples verbatim from `.md` files; do not fabricate import paths.
- Prefer the turnkey package for a capability (the manifest's `primary`) over
hand-assembling low-level primitives.
- Be honest about gaps — do not imply coverage that the catalog does not provide.
## Checklist
1. Description decomposed into capabilities + app-type.
2. Each capability resolved via manifest, or via docs-traversal fallback when absent.
3. Packages deduped, dependency-ordered, grouped by layer.
4. Code examples pulled verbatim from the docs tree, not invented.
5. Gaps and external prerequisites stated explicitly.
````
- [ ] **Step 2: Verify frontmatter and source paths**
Run:
```bash
f=plugins/document-navigator/skills/sp-stack/SKILL.md
grep -q "^name: sp-stack$" "$f" && echo "NAME-OK"
grep -q "^description: " "$f" && echo "DESC-OK"
grep -q "CLAUDE_PLUGIN_ROOT}/skills/sp-stack/capabilities.md" "$f" && echo "MANIFEST-REF-OK"
test -f plugins/document-navigator/skills/sp-stack/capabilities.md && echo "MANIFEST-EXISTS"
```
Expected: `NAME-OK`, `DESC-OK`, `MANIFEST-REF-OK`, `MANIFEST-EXISTS` all print.
- [ ] **Step 3: Commit**
```bash
git add plugins/document-navigator/skills/sp-stack/SKILL.md
git commit -m "Add sp-stack composer skill"
```
---
### Task 6: Narrow the sp skill description
**Files:**
- Modify: `plugins/document-navigator/skills/sp/SKILL.md` (frontmatter `description`)
So Claude reliably routes single-need lookups to `sp` and whole-app requests to
`sp-stack`, sharpen `sp`'s description to the single-capability role.
- [ ] **Step 1: Replace the description line**
Change:
```
description: Navigate the 500+ @suaveplan/* packages to find libraries matching a stated development need. Extracts code examples from the mirrored docs tree.
```
to:
```
description: Find the @suaveplan/* package for a single stated need ("which library does X", "how do I use Y") and extract its code examples from the docs tree. For whole-app stacks, use sp-stack.
```
- [ ] **Step 2: Verify the two descriptions are distinct and cross-referenced**
Run:
```bash
grep "^description:" plugins/document-navigator/skills/sp/SKILL.md
grep "^description:" plugins/document-navigator/skills/sp-stack/SKILL.md
grep -q "sp-stack" plugins/document-navigator/skills/sp/SKILL.md && echo "CROSSREF-OK"
```
Expected: two clearly different description lines print; `CROSSREF-OK` prints.
- [ ] **Step 3: Commit**
```bash
git add plugins/document-navigator/skills/sp/SKILL.md
git commit -m "Narrow sp skill description to single-need lookups"
```
---
## Final verification
- [ ] **Step 1: End-to-end path + structure check**
Run:
```bash
test -f plugins/document-navigator/docs/README.md && echo "DOCS-MOVED"
test -f plugins/document-navigator/skills/sp/SKILL.md && echo "SP-OK"
test -f plugins/document-navigator/skills/sp-stack/SKILL.md && echo "SPSTACK-OK"
test -f plugins/document-navigator/skills/sp-stack/capabilities.md && echo "MANIFEST-OK"
grep -rc "suaveplan-skills/docs" plugins GUIDELINES.md | grep -v ':0' || echo "NO-STALE-PATHS"
```
Expected: `DOCS-MOVED`, `SP-OK`, `SPSTACK-OK`, `MANIFEST-OK`, `NO-STALE-PATHS` all print.
- [ ] **Step 2: Manual smoke test (human or driving agent)**
In a session with the plugin loaded, give `sp-stack` the prompt *"a multi-tenant SaaS
with email campaigns, Stripe billing, and a booking calendar"* and confirm the output
contains: a layered BOM, a `bun add` line, a `createHost` wiring block, starter code,
and a gaps/prerequisites section naming the Stripe key.

View File

@@ -1,149 +0,0 @@
# sp-stack — Full-Stack Library Composer
**Date:** 2026-05-29
**Status:** Approved (design)
**Plugin:** `document-navigator`
## Problem
The marketplace exposes two ways into the 472-package `@suaveplan/*` catalog:
- `library-navigator` — 383 self-contained `sp-<package>` skills, one per library.
- `document-navigator/skills/sp` — greps the mirrored `docs/` tree to match a single
stated need to a package and pull verbatim code examples.
Neither answers the question a user actually starts with: *"I want to build a
multi-tenant SaaS with email campaigns, Stripe billing, and a booking calendar —
which libraries do I need, and how do they fit together?"* Answering that today
means many manual `sp` lookups and hand-assembling the result.
We need a skill that takes a whole-app description and returns the complete library
set, the wiring, and starter code — selected to **minimise the code the user writes**
(prefer a turnkey `api-plugin-payment` over hand-assembling `payment` + `retry` +
`webhook-client`).
## Goals
- Map a natural-language app description to the full set of `@suaveplan/*` packages
needed, across all 18 categories (backend, frontend, foundation, devtools).
- Always prefer the highest-level turnkey package for each capability.
- Emit a bill of materials, install command, host wiring, and starter code stitched
from **verbatim** docs examples — never fabricated imports.
- Surface gaps honestly: capabilities with no `@suaveplan` package, and external
prerequisites (API keys, datastores).
## Non-Goals
- No automated or batch generation of per-library skills (GUIDELINES.md §1 stands;
the capability manifest is a separate hand-curated artifact).
- No runtime/scaffolding tool — the skill emits code as text, it does not write a
project to disk.
- No change to the 383 `library-navigator` skills.
## Decisions
1. **Approach C (hybrid).** A curated capability manifest covers the common 80% with
precise, code-minimal picks; the existing `sp` docs-traversal is the fallback for
the long tail. This is the only approach that both guarantees the "prefer turnkey"
behavior and cannot silently miss a library.
2. **Housed in `document-navigator`**, sharing the relocated `docs/` tree. The composer
is a docs-navigation concern, so co-locating it avoids duplicating 32 MB or relying
on cross-plugin paths (which Claude Code has no mechanism for).
3. **`docs/` moves under the plugin** so the plugin is self-contained and portable
regardless of distribution.
## Architecture
### File layout
```
plugins/document-navigator/
.claude-plugin/plugin.json
docs/ # moved from repo root (32 MB, ~6k .md)
skills/
sp/SKILL.md # existing — description narrowed (see below)
sp-stack/
SKILL.md # new composer skill
capabilities.md # curated capability manifest
```
### docs/ relocation
`docs/` moves from the repo root to `plugins/document-navigator/docs/`. Every `docs/`
reference in `sp/SKILL.md` is rewritten from the hard-coded
`.claude/plugins/suaveplan-skills/docs/` path to `${CLAUDE_PLUGIN_ROOT}/docs/`.
A repo-root path that only resolves when the entire marketplace is cloned together is
replaced by a plugin-relative path that resolves however the plugin is installed.
**Pre-move verification (planning step):** before relocating ~6k files, grep the repo
for any other reference to the root `docs/` path — the 383 `library-navigator` skills,
`marketplace.json`, and any build/lint scripts — and confirm none break. Relative links
*inside* `docs/` (e.g. `./<category>/README.md`) survive a wholesale move; references
*into* `docs/` from outside do not.
### Capability manifest (`capabilities.md`)
A small, hand-curated table — the heart of Approach C. One row per common capability:
| Field | Purpose |
|---|---|
| `capability` | e.g. `payments`, `multi-tenancy`, `email-campaigns`, `file-upload` |
| `layer` | `backend` / `frontend` / `foundation` / `devtools` — drives grouping |
| `primary` | the turnkey package, the minimise-code pick (`@suaveplan/api-plugin-payment`) |
| `supporting` | deps it pulls in / commonly paired packages |
| `example_doc` | path into `docs/` where the verbatim quick-start lives |
| `external` | non-suaveplan prerequisites (Stripe keys, SurrealDB, SMTP) |
The manifest is the only place the "prefer turnkey over low-level primitives" rule is
encoded, so selection is deterministic rather than re-derived per request.
**v1 seed scope:** ship ~15–20 of the most common app capabilities (auth, multi-tenancy,
payments, email-campaigns, transactional-email, file-upload, search, realtime/SSE,
rate-limiting, notifications, webhooks, validation, PWA, client data hooks, CLI, testing).
This bounds the manifest work; everything outside it degrades to the docs-traversal
fallback, not a wrong answer. Each seed row should be anchored against a real example
phrasing so the `capability` vocabulary maps to how users actually describe needs.
## Composer flow
1. Parse the app description into a capability list plus an inferred app-type.
2. For each capability:
- **Manifest hit** → take `primary` + `supporting`, read its `example_doc` verbatim.
- **Manifest miss** → fall back to the `sp` docs-traversal (root → category →
subcategory → package) to locate candidates.
3. Dedupe packages, order by dependency (turnkey plugins first), group by `layer`.
4. Read the verbatim quick-start blocks from the docs tree.
5. Emit the output.
## Output shape
- **Bill of materials** grouped by layer, with a one-line reason per package.
- **Install command** — a single `bun add …`.
- **Wiring** — the `createHost({ plugins: [...] })` composition.
- **Starter code** — stitched from the verbatim docs examples.
- **Gaps & prerequisites** — capabilities with no `@suaveplan` package (write custom
or bring third-party) and required external services.
## Coexistence with `sp`
Two skills, differentiated sharply by description so Claude selects the right one:
- **`sp`** — narrowed to *"find the library for a single stated need / how do I use X."*
- **`sp-stack`** — *"Describe a whole website/service/app; get the complete library set,
wiring, and starter code."*
## Constraints inherited from existing skills
- Only reference packages that exist under the docs tree; never invent package names.
- Use exact `@suaveplan/<name>` identifiers.
- Extract code examples verbatim; never fabricate import paths.
## Risks
- **Manifest drift.** New packages need manual addition. Mitigation: the docs-traversal
fallback keeps the long tail reachable, so a missing manifest row degrades to the
current `sp` behavior rather than a wrong answer.
- **Two code paths.** Manifest + fallback. Both are simple, and the fallback is the
existing, already-exercised traversal.
```

View File

@@ -357,9 +357,9 @@ Game controllers, entity-component systems, and game-server logic.
| Package | Description |
|---|---|
| [`@suaveplan/controller`](./gaming/games/controller/README.md) | Universal input controller foundation. Ships the unified `ControllerInput` shape (37 normalised fields in `[0, 255]`), `BaseController` abstract base with inje… |
| [`@suaveplan/ecs`](./gaming/games/ecs/README.md) | Archetype-based Entity Component System with `Uint32`-backed bitset queries, phase-ordered system scheduling, entity-ID recycling, Zod-validated component sche… |
| [`@suaveplan/game-server`](./gaming/games/game-server/README.md) | Universal game-server framework. Migrated from `@suaveplan/game-server` on the reference branch `claude/review-game-engine-arch-Kaykr` (main repo `packages/uni… |
| [`@suaveplan/controller`](./gaming/gaming/controller/README.md) | Universal input controller foundation. Ships the unified `ControllerInput` shape (37 normalised fields in `[0, 255]`), `BaseController` abstract base with inje… |
| [`@suaveplan/ecs`](./gaming/gaming/ecs/README.md) | Archetype-based Entity Component System with `Uint32`-backed bitset queries, phase-ordered system scheduling, entity-ID recycling, Zod-validated component sche… |
| [`@suaveplan/game-server`](./gaming/gaming/game-server/README.md) | Universal game-server framework. Migrated from `@suaveplan/game-server` on the reference branch `claude/review-game-engine-arch-Kaykr` (main repo `packages/uni… |
### `geospatial`

View File

@@ -106,4 +106,3 @@ Every adapter implementing a writer participant MUST run
`tests/conformance/run-2pc-participant.test.ts` file. The harness
pins prepare / commit / rollback semantics and the idempotency
contract.

View File

@@ -82,4 +82,3 @@ await sink.dispose();
## Tier
Server-tier — depends on `node:fs/promises`.

View File

@@ -76,4 +76,3 @@ queue wait exceeds the bound the record is dropped, the
`api.audit.dropped_total{sink,reason}` counter increments, and
(subject to a once-per-`warnThrottleMs` throttle) a single warning is
logged. Drops are NEVER silent.

View File

@@ -7,7 +7,7 @@ _(no submodules)_
## Purpose
This module produces the HMAC-SHA-256 tag attached to every audit
line. Signing operates on a *canonical* byte representation of the
line. Signing operates on a _canonical_ byte representation of the
record (keys serialised in a fixed order, `cause` omitted when
absent) so the same logical record always produces the same MAC under
the same key, regardless of how the source object was constructed.

View File

@@ -11,7 +11,7 @@ writes. The shape is exactly what design doc §12.5 specifies for the
admin / audit pipeline: `ts`, `type`, `principal`, `tenant`,
`request_id`, `trace_id`, `subject`, `outcome`, and a conditional
`cause`. Every write goes through `parseAuditRecord(...)` so a
malformed record raises `AUDIT_STDOUT.INVALID_RECORD` *before* a line
malformed record raises `AUDIT_STDOUT.INVALID_RECORD` _before_ a line
is written — log pipelines downstream never see a half-finished
record.

View File

@@ -32,7 +32,7 @@ rejected synchronously without consuming the slot.
- Boundary Zod validation — `AUDIT_STDOUT.INVALID_RECORD` on a bad
record.
- Bounded queue — `AUDIT_STDOUT.QUEUE_FULL` on timeout, drop counter
+ throttled warning.
- throttled warning.
- HMAC-SHA-256 over canonical bytes appended as `_hmac` field.
- `dispose()` drains the in-flight write and rejects subsequent
writes as `closed` drops.

View File

@@ -57,4 +57,3 @@ The resolver passes `runAuthSessionConformance` (null-only mode) from
`AUTH_ANON.INVALID_OPTIONS` — thrown only when the factory is handed a
non-object or unknown-key options bag. No per-request error paths exist by
design.

View File

@@ -152,4 +152,3 @@ Both surfaces pass `runAuthSessionConformance` from
`@suaveplan/api-auth`. Spec-conformance tests live alongside the source
under `src/factory/*.spec-conformance.test.ts` and
`src/proxy/*.spec-conformance.test.ts`.

View File

@@ -169,4 +169,3 @@ createBetterAuthSession createBetterAuthProvider
▼ ▼
Principal auth.handler(rewrittenRequest)
```

View File

@@ -41,7 +41,7 @@ provider, not this package.
`JWT_BEARER_SCHEME` and `createJwtBearerSecurityScheme(name)` for
OpenAPI emission.
- [`./error-codes`](src/error-codes/error-codes.md) — `AUTH_JWT_*` codes
+ `AuthJwtError` class.
- `AuthJwtError` class.
- [`./options`](src/options/options.md) — Zod-validated options
boundary.
@@ -132,4 +132,3 @@ returns a non-Principal value.
## License
MIT — see the repository.

View File

@@ -65,4 +65,3 @@ package.
## Stage / status
Concrete providers ship in Stages 6 / 8.

View File

@@ -4,6 +4,7 @@ Stage-8.12 rolled session-token resolver for `@suaveplan/api`. Issues
RS256-signed JWTs with rotating `kid` slots, verifies tokens through the
rotator's active + retired-non-revoked key set, projects DB rows onto
the `@suaveplan/api-types` `Principal` contract, and contributes cookie
+ bearer OpenAPI security schemes.
This milestone ships the **session-resolver half** of the eventual dual
@@ -14,20 +15,20 @@ a successor change `api-auth-rolled-provider`.
<!-- begin:auto-docs -->
## Documentation tree
- [composition](./src/composition/composition.md) — Top-level factory `createRolledAuthAdapter` that wires the four sub-modules (`token-rotator`, `session`, `principal-pro…
- [composition](./src/composition/composition.md) — Top-level factory `createRolledAuthAdapter` that wires the four sub-modules (`token-rotator`, `session`, `principal-pro…
- [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry for `@suaveplan/api-auth-rolled`. Every code is namespaced under `AUTH_ROLLED.*` so cross-pa…
- [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry for `@suaveplan/api-auth-rolled`. Every code is namespaced under `AUTH_ROLLED.*` so cross-pa…
- [options](./src/options/options.md) — Defines the configuration shape accepted by `createRolledAuthAdapter` and the Zod schema that validates it. Operators w…
- [options](./src/options/options.md) — Defines the configuration shape accepted by `createRolledAuthAdapter` and the Zod schema that validates it. Operators w…
- [principal-projection](./src/principal-projection/principal-projection.md) — Projects the package's internal `UserRow` storage shape onto the abstract `Principal` contract published by `@suaveplan…
- [principal-projection](./src/principal-projection/principal-projection.md) — Projects the package's internal `UserRow` storage shape onto the abstract `Principal` contract published by `@suaveplan…
- [security-schemes](./src/security-schemes/security-schemes.md) — Contributes OpenAPI 3.1 `securitySchemes` entries describing both transports the rolled session resolver accepts — `Aut…
- [security-schemes](./src/security-schemes/security-schemes.md) — Contributes OpenAPI 3.1 `securitySchemes` entries describing both transports the rolled session resolver accepts — `Aut…
- [session](./src/session/session.md) — The rolling-JWT session resolver — the keystone of the rolled auth adapter. Builds a `SessionResolver` (per `@suaveplan…
- [session](./src/session/session.md) — The rolling-JWT session resolver — the keystone of the rolled auth adapter. Builds a `SessionResolver` (per `@suaveplan…
- [token-rotator](./src/token-rotator/token-rotator.md) — Owns the rotating-keyset state for the rolled session-token resolver. The active key signs new JWTs; retired-but-non-re…
- [token-rotator](./src/token-rotator/token-rotator.md) — Owns the rotating-keyset state for the rolled session-token resolver. The active key signs new JWTs; retired-but-non-re…
+ [composition](./src/composition/composition.md) — Top-level factory `createRolledAuthAdapter` that wires the four sub-modules (`token-rotator`, `session`, `principal-pro…
+ [composition](./src/composition/composition.md) — Top-level factory `createRolledAuthAdapter` that wires the four sub-modules (`token-rotator`, `session`, `principal-pro…
+ [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry for `@suaveplan/api-auth-rolled`. Every code is namespaced under `AUTH_ROLLED.*` so cross-pa…
+ [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry for `@suaveplan/api-auth-rolled`. Every code is namespaced under `AUTH_ROLLED.*` so cross-pa…
+ [options](./src/options/options.md) — Defines the configuration shape accepted by `createRolledAuthAdapter` and the Zod schema that validates it. Operators w…
+ [options](./src/options/options.md) — Defines the configuration shape accepted by `createRolledAuthAdapter` and the Zod schema that validates it. Operators w…
+ [principal-projection](./src/principal-projection/principal-projection.md) — Projects the package's internal `UserRow` storage shape onto the abstract `Principal` contract published by `@suaveplan…
+ [principal-projection](./src/principal-projection/principal-projection.md) — Projects the package's internal `UserRow` storage shape onto the abstract `Principal` contract published by `@suaveplan…
+ [security-schemes](./src/security-schemes/security-schemes.md) — Contributes OpenAPI 3.1 `securitySchemes` entries describing both transports the rolled session resolver accepts — `Aut…
+ [security-schemes](./src/security-schemes/security-schemes.md) — Contributes OpenAPI 3.1 `securitySchemes` entries describing both transports the rolled session resolver accepts — `Aut…
+ [session](./src/session/session.md) — The rolling-JWT session resolver — the keystone of the rolled auth adapter. Builds a `SessionResolver` (per `@suaveplan…
+ [session](./src/session/session.md) — The rolling-JWT session resolver — the keystone of the rolled auth adapter. Builds a `SessionResolver` (per `@suaveplan…
+ [token-rotator](./src/token-rotator/token-rotator.md) — Owns the rotating-keyset state for the rolled session-token resolver. The active key signs new JWTs; retired-but-non-re…
+ [token-rotator](./src/token-rotator/token-rotator.md) — Owns the rotating-keyset state for the rolled session-token resolver. The active key signs new JWTs; retired-but-non-re…
<!-- end:auto-docs -->
## Why
@@ -80,4 +81,3 @@ setInterval(async () => {
## License
MIT

View File

@@ -122,4 +122,3 @@ const host = createTestHost({
Until then, callers wire the adapter directly via
`createStaticPrincipalAdapter()` as shown above.

View File

@@ -106,4 +106,3 @@ contract bundle (`api-types`, `api-auth`, `api-tenant-resolver`,
| `@suaveplan/types` | Cross-package contracts (logger, clock, etc.). |
| `tslib` | TypeScript runtime helpers (catalog). |
| `zod` | Boundary validation for security-scheme contributions. |

View File

@@ -125,4 +125,3 @@ a no-op.
factory.
- `DB_ADAPTER.INVALID_OPTIONS` — Zod validation failed; issues attached
to `error.context.issues`.

View File

@@ -26,7 +26,7 @@ The result object exposes:
## Features
- Options are parsed once at factory time; the rest of the API is typed
against the *post-parse* `DbAdapterOptions`.
against the _post-parse_ `DbAdapterOptions`.
- Engine lookup is delegated to `buildEngineAdapter`, so any
declaration-merged engine works automatically.
- Tenant scoping config (`tenantColumn`, `autoInjectInserts`) flows from

View File

@@ -24,7 +24,7 @@ payloads.
- `parseDbAdapterOptions(input)` — convenience wrapper that converts every Zod
failure into a typed `DbAdapterError` with code `INVALID_OPTIONS`. Issues
are surfaced through `error.context.issues`.
- `engine` is `z.string().min(1)` — the *literal value* check happens against
- `engine` is `z.string().min(1)` — the _literal value_ check happens against
the open `DatabaseEngineRegistry` so declaration-merged engines pass.
- `pool` is an optional sub-schema with its own defaults; absent values are
forwarded as `undefined` to the engine layer rather than guessed.

View File

@@ -10,7 +10,7 @@ This module is the load-bearing safety boundary between a plugin route handler
and the underlying admin database surface. Every SELECT/UPDATE/DELETE that the
route handler issues is rewritten in flight to carry a `WHERE tenant_id = ?`
predicate; every INSERT either carries the tenant column or is rejected (or
auto-injected, configurable). The contract is enforced *at the wrapper*, so a
auto-injected, configurable). The contract is enforced _at the wrapper_, so a
route handler literally cannot read another tenant's rows even if the plugin
author is malicious.

View File

@@ -75,4 +75,3 @@ The final merged pragma map is `{ ...DEFAULT_PRAGMAS, ...options.pragmas }`, so
## License
MIT.

View File

@@ -109,4 +109,3 @@ parentPort?.once("message", (boot) => {
- [`src/tenant-scoped/tenant-scoped.md`](./src/tenant-scoped/tenant-scoped.md)
- [`src/error-codes/error-codes.md`](./src/error-codes/error-codes.md)
- [`src/testing/testing.md`](./src/testing/testing.md)

View File

@@ -102,4 +102,3 @@ underlying `z.ZodError` on `cause`.
## License
MIT — Suaveplan Team.

View File

@@ -87,4 +87,3 @@ console.log(result.delivered);
- [`payload-codec`](./src/payload-codec/payload-codec.md)
- [`error-codes`](./src/error-codes/error-codes.md)
- [`testing`](./src/testing/testing.md)

View File

@@ -66,4 +66,3 @@ slimmer dependency closure.
Original. Owned by the `api-stack` super-category.
Passes the abstract conformance harness with the same invariants Yoga
satisfies — see `src/engine/apollo-engine.spec-conformance.test.ts`.

View File

@@ -16,7 +16,7 @@ boundary.
The module also re-exports the unmodified `runGraphqlEngineConformance`
so downstream packages that want to run the harness against a
*different* factory (e.g. a federated subgraph composing Apollo + a
_different_ factory (e.g. a federated subgraph composing Apollo + a
custom transport) keep a single import surface.
## Features

View File

@@ -94,4 +94,3 @@ the `ui` label.
## License
MIT

View File

@@ -104,4 +104,3 @@ bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-graphql-ui
100% statements / branches / functions / lines required on touched
modules (`provider: istanbul`).

View File

@@ -87,4 +87,3 @@ const result = await engine.executeQuery({ query: "{ ping }" }, ctx);
## License
MIT — Suaveplan Team.

View File

@@ -10,6 +10,7 @@ Bridges the `WsBroker` contract from `@suaveplan/api-ws` to GraphQL
`Subscription` resolvers via `AsyncIterable<Payload>`. The Yoga engine
wires `graphql-ws` over the host's already-mounted WebSocket transport;
this module is the per-subscription helper that converts a broker `topic`
+ `tenant` pair into an iterator the engine can consume.
Tenant filtering is enforced at the bridge: only `BrokerEnvelope` items
@@ -20,10 +21,10 @@ within one tick.
## Features
- Returns `AsyncIterable<Payload>` with an explicit `close()` accessor.
- Queues payloads when no consumer is awaiting; resolves immediately when
+ Returns `AsyncIterable<Payload>` with an explicit `close()` accessor.
+ Queues payloads when no consumer is awaiting; resolves immediately when
a consumer is parked.
- Calls `GraphqlYogaError("SUBSCRIPTION_TRANSPORT_UNAVAILABLE")` when the
+ Calls `GraphqlYogaError("SUBSCRIPTION_TRANSPORT_UNAVAILABLE")` when the
host hands a `null` broker, satisfying the design doc §10.4 contract.
## Usage: Basic
@@ -59,7 +60,7 @@ const subscription = {
## API Reference
- `subscribeBrokerTopic(broker, topic, tenant)` — returns
+ `subscribeBrokerTopic(broker, topic, tenant)` — returns
`AsyncIterable<Payload> & { close(): Promise<void> }`.
## Implementation Notes

View File

@@ -78,4 +78,3 @@ Altair packages land .
- `@suaveplan/error` — `defineCodes` + `SuaveplanError` base.
- `zod` — subscription protocol envelope validation.
- `tslib` — TypeScript helper functions.

View File

@@ -115,4 +115,3 @@ bun add @suaveplan/api-host
## License
MIT

View File

@@ -112,7 +112,7 @@ const PIPELINE_STEPS: readonly PipelineStepName[];
## Implementation Notes
The pipeline runs route-match *first* (technically step 2 in §6) so
The pipeline runs route-match _first_ (technically step 2 in §6) so
later step gates (`auth`, `csrf`, `rateLimit`, `idempotent`) can
consult per-route policy. The §6 ordering of "intake → match" is
preserved at the engine adapter; this driver assumes the intake has

View File

@@ -67,4 +67,3 @@ in-repo substitute can be swapped out without changing consumers.
bunx turbo lint typecheck test --filter=@suaveplan/api-jobs-worker-proxy
bunx turbo test:coverage --filter=@suaveplan/api-jobs-worker-proxy
```

View File

@@ -79,4 +79,3 @@ await fsm.transition("startCompleted");
| `LIFECYCLE.MUTEX_HELD` | `assertAcquired` called on a null `tryAcquire` result |
| `LIFECYCLE.RETRY_BUDGET_EXHAUSTED` | start_failed × 3 OR crashed × 3 in window |
| `LIFECYCLE.REINSTALL_REQUIRED_VERSION_DOWNGRADE` | `next.version < prev.version` |

View File

@@ -88,7 +88,7 @@ export type ModuleResolverFactory<M = unknown> = () => ModuleResolver<M>;
## Implementation Notes
`resolve` returns the *evaluated namespace*, not a thenable wrapping it —
`resolve` returns the _evaluated namespace_, not a thenable wrapping it —
the host's lifecycle FSM treats a successful return as a synchronous
"module loaded" signal even though the call itself is async. Concrete
implementations are free to memoise nothing (the cache-bust strategy in

View File

@@ -95,4 +95,3 @@ server.close();
## License
MIT

View File

@@ -33,7 +33,7 @@ proxy).
`WireLogRecord` with defaults.
- `runLoggerProxyConformance(plugin, options?)` — full paired
harness: client + server + captured-output array + control sender
+ `dispose()`.
- `dispose()`.
## Usage: Basic

View File

@@ -108,4 +108,3 @@ Every code is namespaced under `MANIFEST.*` and produced by `defineCodes`. The e
## License
MIT

View File

@@ -123,4 +123,3 @@ import { MIGRATION_CODES } from "@suaveplan/api-migrations/error-codes/error-cod
Server (Bun + Node). Uses `node:crypto` for SHA-256 and `node:fs/promises`
for directory scanning and file reads.

View File

@@ -80,4 +80,3 @@ const res = handler();
## License
MIT

View File

@@ -127,4 +127,3 @@ bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-openapi-ui
100% statements / branches / functions / lines required on touched
modules (`provider: istanbul`).

View File

@@ -78,4 +78,3 @@ for (const name of listBundledAssetNames()) {
- `OPENAPI_UI_SWAGGER.ASSETS_MISSING` — bundled mode requested without `assetBasePath`, or a bundled asset name is not registered.
Both surfaces raise at factory-call time (eager validation), so misconfiguration is caught at boot rather than at first request.

View File

@@ -220,4 +220,3 @@ Server-tier (Hono-typed). Runs in Bun + Node.
## License
MIT

View File

@@ -85,4 +85,3 @@ app.post("/users/:id/delete", async (c) => {
- `auditService` registered with `ctx.registerService("auditService", ...)` and exposed through the typed `ServiceRegistry` slot.
- Hono `ContextVariableMap` augmented with `audit: AuditContext` so handlers fire explicit events without import boilerplate.
- Four OpenTelemetry instruments: `audit.requests_recorded_total{outcome,sampled}`, `audit.requests_excluded_total`, `audit.sink_failures_total`, `audit.middleware_duration_ms`.

View File

@@ -192,4 +192,3 @@ createAuthPlugin({
- `better-auth ^1.4` (resolves to 1.6.x via the catalog).
- `hono`, `@hono/zod-openapi`, `zod` — supplied by the host
application; the plugin imports them directly.

View File

@@ -65,4 +65,3 @@ each ships green on its own:
`bunx turbo lint typecheck test --filter=@suaveplan/api-plugin-campaigns`
plus `bunx turbo test:coverage --filter=@suaveplan/api-plugin-campaigns`
at 100/100/100/100 are required for every chunk to land.

View File

@@ -94,4 +94,3 @@ app.onError((err, c) => respondProblemJson(c, err));
## License
MIT — © Suaveplan Team

View File

@@ -108,4 +108,3 @@ Migration metrics are emitted by `@suaveplan/api-migrations` under its own meter
## Errors
Every failure path raises `DatabaseError` carrying one of eight `DATABASE_*` codes: `CONNECTION_FAILED`, `POOL_EXHAUSTED`, `POOL_CLOSED`, `QUERY_FAILED`, `MIGRATION_FAILED`, `LOCK_CONTENDED`, `TENANT_INVALID`, `INVALID_CONFIG`. See [`error-codes/error-codes.md`](./src/error-codes/error-codes.md).

View File

@@ -193,4 +193,3 @@ table and `context.statusCode` mapping.
application.
- `@suaveplan/api-plugin-auth` — used by `requireAuth()` route gate
when `requireAuthForRoutes: true` (default).

View File

@@ -109,4 +109,3 @@ for the full list. Highlights:
`0.1.0` — feature parity with upstream `@suaveplan/api-plugin-events`
modulo the explicit scope-outs above. 100% line / branch / function /
statement coverage. Real SurrealDB testcontainer integration.

View File

@@ -102,4 +102,3 @@ bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-plugin-exa
100% Istanbul coverage is enforced; the manifest `errors.statusMap`
is verified end-to-end against the runtime by the integration suite.

View File

@@ -86,4 +86,3 @@ DELETE /v1/exports/{id} → { success: true }
## Scope notes
This package ships the upstream §2 functional surface (CSV / JSON / SpreadsheetML XML exporters + in-memory job store + four-route Hono group). The upstream §3–§4 enhancements (streaming exporters, S3-backed blob store, auth/permissions/rate-limit/idempotency middleware, OOXML/ZIP writer, scheduled exports, signed download URLs, Parquet/Markdown formats) are deferred to follow-up changes — they require downstream plugins that have not yet landed .

View File

@@ -55,4 +55,4 @@ const result = new XlsxExporter().export(rows, cols, { sheetName: "WideExport" }
## Implementation Notes
The output is *SpreadsheetML 2006* — a worksheet XML payload, not the ZIP package most consumers think of when they hear "xlsx". This is a deliberate carry-over from the upstream package which chose XML over the `xlsx` npm dependency. The MIME type is set to the OOXML sheet content-type so HTTP consumers can still dispatch by `Content-Type`; the filename suffix is `.xlsx.xml` to signal the format honestly. The sheet name is escaped into the `<worksheet sheetName="…">` attribute even though the bare-worksheet form is not strictly required to carry one — keeping the attribute lets downstream upgrades wrap this document in an OOXML/ZIP package without re-emitting the worksheet. The `columnIndexToLetter` loop uses `Math.floor(n / 26) - 1` so the multi-letter overflow is exactly Excel-compatible: `26 → "AA"`, `51 → "AZ"`, `52 → "BA"`, `676 → "ZA"`, `701 → "ZZ"`, `702 → "AAA"`. The boolean cell uses `1`/`0` (not `true`/`false`) because OOXML requires the integer form.
The output is _SpreadsheetML 2006_ — a worksheet XML payload, not the ZIP package most consumers think of when they hear "xlsx". This is a deliberate carry-over from the upstream package which chose XML over the `xlsx` npm dependency. The MIME type is set to the OOXML sheet content-type so HTTP consumers can still dispatch by `Content-Type`; the filename suffix is `.xlsx.xml` to signal the format honestly. The sheet name is escaped into the `<worksheet sheetName="…">` attribute even though the bare-worksheet form is not strictly required to carry one — keeping the attribute lets downstream upgrades wrap this document in an OOXML/ZIP package without re-emitting the worksheet. The `columnIndexToLetter` loop uses `Math.floor(n / 26) - 1` so the multi-letter overflow is exactly Excel-compatible: `26 → "AA"`, `51 → "AZ"`, `52 → "BA"`, `676 → "ZA"`, `701 → "ZZ"`, `702 → "AAA"`. The boolean cell uses `1`/`0` (not `true`/`false`) because OOXML requires the integer form.

View File

@@ -53,4 +53,4 @@ const inst = getExportInstruments(); // rebinds against the new provider
## Implementation Notes
The bundle is held in a module-scope `let cached: ExportInstruments | undefined` rather than in a class instance, because the function is the only documented entry point and there is no per-plugin state to keep — every plugin instance in a process shares the same meter. Counters use `add(value, attributes?)`; the `outcome` attribute is set by the call site rather than declared on the instrument because OTel attributes are runtime keys, not instrument metadata. The histogram unit is set to `"ms"` (lower-case) per OTel semantic conventions for latency. Resetting between tests is mandatory: meter handles cache internally inside `@opentelemetry/api`, so without `resetExportInstruments()` a test would emit to whichever provider was installed when the *first* `getExportInstruments()` call ran — usually the global default provider, which loses every metric.
The bundle is held in a module-scope `let cached: ExportInstruments | undefined` rather than in a class instance, because the function is the only documented entry point and there is no per-plugin state to keep — every plugin instance in a process shares the same meter. Counters use `add(value, attributes?)`; the `outcome` attribute is set by the call site rather than declared on the instrument because OTel attributes are runtime keys, not instrument metadata. The histogram unit is set to `"ms"` (lower-case) per OTel semantic conventions for latency. Resetting between tests is mandatory: meter handles cache internally inside `@opentelemetry/api`, so without `resetExportInstruments()` a test would emit to whichever provider was installed when the _first_ `getExportInstruments()` call ran — usually the global default provider, which loses every metric.

View File

@@ -56,4 +56,4 @@ const routes = createExportRoutes({
## Implementation Notes
The `runPostExport` helper in `post-handler.ts` owns the bulk of the work — the route definitions stay in this file so that the OpenAPI schema is one click away from the route name. Failure paths set `job.status = "failed"` and persist `job.error` *before* returning, so `GET /:id` immediately afterwards sees the failure record (mirroring upstream behaviour). The `downloadUrl` response is `/${jobId}/download` — the actual streaming endpoint is upstream §3 future work, deferred in this migration. The downstream consumer is expected to combine this `downloadUrl` with the `basePath` themselves (e.g. `${basePath}${downloadUrl}`) — the upstream package made the same choice and the route layer cannot know the full mount path. Every route is also registered against an explicit `createRoute(...)` descriptor so an OpenAPI document generated by `OpenAPIHono.getOpenAPIDocument()` includes the export routes with full Zod-derived schemas.
The `runPostExport` helper in `post-handler.ts` owns the bulk of the work — the route definitions stay in this file so that the OpenAPI schema is one click away from the route name. Failure paths set `job.status = "failed"` and persist `job.error` _before_ returning, so `GET /:id` immediately afterwards sees the failure record (mirroring upstream behaviour). The `downloadUrl` response is `/${jobId}/download` — the actual streaming endpoint is upstream §3 future work, deferred in this migration. The downstream consumer is expected to combine this `downloadUrl` with the `basePath` themselves (e.g. `${basePath}${downloadUrl}`) — the upstream package made the same choice and the route layer cannot know the full mount path. Every route is also registered against an explicit `createRoute(...)` descriptor so an OpenAPI document generated by `OpenAPIHono.getOpenAPIDocument()` includes the export routes with full Zod-derived schemas.

View File

@@ -77,4 +77,4 @@ try {
## Implementation Notes
The two guards run in a specific order: row count is checked *before* the exporter runs so a runaway provider doesn't burn CPU encoding fields the route layer is about to reject. File size is checked *after* encoding because cell-level transforms and XML/JSON overhead can push a "small" row count over the byte cap. The `default:` branch in `getExporter` is reachable only if a caller bypasses the Zod boundary (the schema enumerates `csv|json|xlsx`); the `format as string` cast in the error message is intentional — we want the actual value the caller passed to surface in logs, not the post-narrowing `never`. `provider.fetch` errors are wrapped rather than thrown raw because the route layer needs to distinguish a *bad provider* (502-class) from a *bad request* (400-class), and the `ExportError` code is the contract that drives that branching upstream.
The two guards run in a specific order: row count is checked _before_ the exporter runs so a runaway provider doesn't burn CPU encoding fields the route layer is about to reject. File size is checked _after_ encoding because cell-level transforms and XML/JSON overhead can push a "small" row count over the byte cap. The `default:` branch in `getExporter` is reachable only if a caller bypasses the Zod boundary (the schema enumerates `csv|json|xlsx`); the `format as string` cast in the error message is intentional — we want the actual value the caller passed to surface in logs, not the post-narrowing `never`. `provider.fetch` errors are wrapped rather than thrown raw because the route layer needs to distinguish a _bad provider_ (502-class) from a _bad request_ (400-class), and the `ExportError` code is the contract that drives that branching upstream.

View File

@@ -41,4 +41,4 @@ providers.set("orders", myOrderProvider);
## Implementation Notes
The augmentation pattern is identical to `@suaveplan/api-plugin-database`'s `registry-augmentation.ts` — both files exist purely to add slots to the shared registry interface defined by `@suaveplan/api-plugin/service-registry`. Without this file, every call site would have to cast the `getService("exportProviders")` return value, defeating the type safety that the `ServiceRegistry` interface was designed to provide. The two slots cover the two distinct concerns the plugin owns: the *registry* of data providers (writable by every consumer that wants to expose a resource for export) and the *store* of jobs (mutated by the route layer, observable by anyone tracking export progress). Exposing both is a deliberate departure from upstream, which exposed them via `ctx.registerService(...)` at runtime but never declared the corresponding types.
The augmentation pattern is identical to `@suaveplan/api-plugin-database`'s `registry-augmentation.ts` — both files exist purely to add slots to the shared registry interface defined by `@suaveplan/api-plugin/service-registry`. Without this file, every call site would have to cast the `getService("exportProviders")` return value, defeating the type safety that the `ServiceRegistry` interface was designed to provide. The two slots cover the two distinct concerns the plugin owns: the _registry_ of data providers (writable by every consumer that wants to expose a resource for export) and the _store_ of jobs (mutated by the route layer, observable by anyone tracking export progress). Exposing both is a deliberate departure from upstream, which exposed them via `ctx.registerService(...)` at runtime but never declared the corresponding types.

View File

@@ -97,4 +97,3 @@ await api.start();
- [`schemas/routes/initiate`](./src/schemas/routes/initiate.md) — chunked-init request/response.
- [`schemas/routes/status`](./src/schemas/routes/status.md) — chunk / complete / status / abort schemas.
- [`types/types`](./src/types/types.md) — public data model.

View File

@@ -105,4 +105,3 @@ This package is functional-parity with upstream `@suaveplan/api-plugin-graphql`
## License
MIT.

View File

@@ -138,4 +138,3 @@ upstream import success/failure).
## License
MIT

View File

@@ -106,4 +106,3 @@ const service = new ApnService({ config, transport });
See `src/transport/apn-transport/apn-transport.md` for the full
contract.

View File

@@ -157,4 +157,3 @@ const plugin = createPaymentPlugin({
- [`./src/otel/instruments.md`](./src/otel/instruments.md) — 5 counters + 1 histogram.
- [`./src/error-codes/error-codes.md`](./src/error-codes/error-codes.md) — 15 `PAYMENT_PLUGIN_*` codes.
- [`./src/types/types.md`](./src/types/types.md) — `PaymentPluginOptions` / `PaymentPluginConfig`.

View File

@@ -130,4 +130,3 @@ readiness).
## Status
`0.1.0` — initial ship. Surface is final for the 0.1.x line.

View File

@@ -113,4 +113,3 @@ SurrealDB FTS / Typesense / Meilisearch), tenant scoping, auth gates,
rate limiting, and the enterprise-audit §4 enhancements (vector search,
synonyms, query DSL, saved searches, learning-to-rank) are tracked as
follow-up changes.

View File

@@ -98,4 +98,3 @@ The site plugin ships **zero runtime dependencies** on `@suaveplan/api-plugin-ra
- See [`docs/middleware-integration.md`](./docs/middleware-integration.md) for the canonical end-to-end wiring example and the recommended layering order (audit OUTERMOST → rate-limit MIDDLE → site routes INNERMOST).
- See [`src/integration/middleware-recommendations.md`](./src/integration/middleware-recommendations.md) for the `MIDDLEWARE_RECOMMENDATIONS` constant exposing recommended rate-limit windows and audit categories per route group.
- The pattern is proven by [`src/integration/middleware-composition.integration.test.ts`](./src/integration/middleware-composition.integration.test.ts) — a runnable composition asserting site behaviour, rate-limit headers, and audit event emission.

View File

@@ -106,4 +106,3 @@ This package follows the canonical API-plugin pattern pioneered by `@suaveplan/a
## License
MIT

View File

@@ -118,4 +118,3 @@ const app = defineApp({
## License
MIT

View File

@@ -200,4 +200,3 @@ The plugin emits three counters:
Counters bind lazily to the global `MeterProvider`; tests
re-bind by calling `resetUserInstruments()` after swapping the
provider.

View File

@@ -163,4 +163,3 @@ Operators can:
- [`services/registry-augmentation`](./src/services/registry-augmentation.md)
— typed `ServiceRegistry` slot.
- [`types/types`](./src/types/types.md) — public TS surface.

View File

@@ -118,4 +118,3 @@ Status label values: `delivered`, `exhausted`, `not_found`, `inactive`, `invalid
## License
MIT

View File

@@ -116,4 +116,3 @@ ctx.getService("nope"); // type error — not augmented
- **Topological sort is deterministic** — alphabetical tie-break for equal-in-degree nodes makes boot logs reproducible across runs.
- **No `applyMigrations`** — migrations live in `@suaveplan/api-migrations`. The plugin registry knows nothing about databases.
- **No ALS singletons** (`getCurrentApp`, etc.). Callers thread `ctx` explicitly.

View File

@@ -98,4 +98,3 @@ bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-rate-limit
```
100% statements/branches/functions/lines (Istanbul).

View File

@@ -82,4 +82,3 @@ Reason label values: `"missing-scope" | "rule-deny" | "no-principal"`.
## License
MIT

View File

@@ -59,4 +59,3 @@ await slot.dispose(draining.slotId, { timeoutMs: 1_000 });
## Version
`0.1.0` — initial Stage-4 ship. Graduates to `1.0.0` when the plugin system as a whole is declared production-ready.

View File

@@ -71,4 +71,3 @@ await slot.dispose(draining.slotId, { timeoutMs: 100 });
- Foundation tests that need a real `Router`/`PipelineRouter` without a Hono peer.
- Plugin tests that previously hand-rolled their own router shim (`api-router-hono` carries the Hono peer-dep cost).
- The default `router: "in-memory"` slot in the Stage-5 `@suaveplan/api-host/testing` adapter table.

View File

@@ -75,4 +75,3 @@ const { dispatch } = createMainBridge(channel.port1 as never);
const res = await dispatch(new Request("https://api.local/world"));
console.log(await res.text()); // "hi /world"
```

View File

@@ -95,4 +95,3 @@ import { runRouterConformance } from "@suaveplan/api-router/testing";
## License
MIT

View File

@@ -24,7 +24,7 @@ values via wrapping responses and inspecting the request shape.
list; order is preserved.
- `next()` enforcement: a middleware that calls `next()` twice in a row
has its dispatch rejected. (Multiple sequential `next()` calls across
*different* middlewares are correct; only same-middleware repeats fail.)
_different_ middlewares are correct; only same-middleware repeats fail.)
- Synchronous return values are accepted (wrapped in `Promise.resolve`).
## Usage: Basic

View File

@@ -72,7 +72,7 @@ isolated copies and never accidentally share state across branches. The
runtime cost is one object-spread per call; modern V8 inlines this away
for short builder chains.
The `body` setter is typed as a *re-parameterising* method — calling
The `body` setter is typed as a _re-parameterising_ method — calling
`builder.body<T>(value)` returns a `ResponseBuilder<T>`, picking up the
new body type. This lets adapters call `.body(zodValidatedShape)` and the
inferred `RouterResponse.body` lines up with the validation output. The

View File

@@ -104,7 +104,7 @@ keeps the steps-7-8 insertion contract honest: middleware only enters
through `use()`, and only at the post-validation boundary when supplied
by plugins.
Collision detection compares the *compiled* path key (`":id"` vs.
Collision detection compares the _compiled_ path key (`":id"` vs.
`":userId"` both normalise to `:`-form). Adapters that need parameter-name
preservation can introspect `RouteMatch.path` for the originally registered
form.

View File

@@ -84,4 +84,3 @@ participant whose `actions[name]` is missing fails at install with
`0.1.0` — bottom-up rebuild stage. Will graduate to `1.0.0` per the
foundation umbrella's Stage 6 acceptance gate (`a multi-step saga in
api-plugin-example runs end-to-end including a compensation path`).

View File

@@ -104,7 +104,7 @@ router.post("/webhook/saga", async (req) => {
## Implementation Notes
The emitter validates *outbound* payloads before pushing them onto the
The emitter validates _outbound_ payloads before pushing them onto the
bus. This is deliberate — `bus.emit` is fire-and-forget; if the
emitter trusted the caller and pushed a bad payload, every listener
would see corrupt data with no callback to recover. By failing at the

View File

@@ -96,4 +96,3 @@ if (result.outcome === "deny") {
Runtime: `@suaveplan/api-types`, `@suaveplan/error`, `@suaveplan/types`,
`@suaveplan/opentelemetry`, `@opentelemetry/api`, `tslib`, `zod`. No
`@suaveplan/api-*` runtime beyond `api-types`.

View File

@@ -92,4 +92,3 @@ lifecycle delegation (`LIFECYCLE_FAILED`).
the spec mandates: route registration, request round-trip, idempotent
lifecycle, error propagation with `cause` chain, and capability
passthrough including denied capability surfacing `SAND_PERM.DENIED`.

View File

@@ -89,4 +89,3 @@ import { runVmSandboxConformance } from "@suaveplan/api-sandbox-vm/testing";
runVmSandboxConformance("my-host", makeMyHandle);
```

View File

@@ -15,18 +15,19 @@ The split from `bridge.ts` is structural rather than mechanical: every
direct-variant import (`abi-direct/wasm-abi`, `abi-direct/memory`,
`abi-direct/marshal`) is referenced from this file only, so a future
removal of the direct variant collapses to deleting `bridge-direct.ts`
+ `abi-direct/` and trimming the dispatcher.
## Features
- `buildDirectInstall(options)` — accepts a `DirectVariantOptions`,
+ `buildDirectInstall(options)` — accepts a `DirectVariantOptions`,
returns the bridge's `SandboxedWasmPluginInstall`.
- Trap classification, capability-gate routing through
+ Trap classification, capability-gate routing through
`SAND_PERM.DENIED`, idempotent lifecycle — preserved exactly from
the shipped contract.
- Instrument registry plumbed with `abi_variant: "direct-i32-i64"` on
+ Instrument registry plumbed with `abi_variant: "direct-i32-i64"` on
every counter and histogram emission.
- Route closures are pure functions of the manifest + ABI exports;
+ Route closures are pure functions of the manifest + ABI exports;
re-instantiating the bridge against the same sandbox produces
identical `PipelineRoute[]` records.
@@ -81,7 +82,7 @@ try {
Internal entrypoint called by the dispatcher. Public consumers should
use `createSandboxedWasmPluginModule` from the package root.
- `options: DirectVariantOptions` — `sandbox`, `manifest`, optional
+ `options: DirectVariantOptions` — `sandbox`, `manifest`, optional
`instruments`.
Throws `SandboxWasmBridgeError` with code `INVALID_PLUGIN_SURFACE` if
@@ -89,14 +90,14 @@ ABI validation fails BEFORE any guest call.
## Implementation Notes
- The function never touches the sandbox's `instance` directly past
+ The function never touches the sandbox's `instance` directly past
the ABI validator — the typed `WasmAbiExports` view is the single
hand-off point.
- `freeBuffer` is called in a `finally` block so the request pointer
+ `freeBuffer` is called in a `finally` block so the request pointer
is released even when the response unmarshal throws. The response
pointer is released BEFORE unmarshal runs because Zod parsing may
allocate additional bytes that would shadow the original buffer.
- Capability denials surface through the canonical
+ Capability denials surface through the canonical
`SAND_PERM.DENIED` code, not the bridge-local `CAPABILITY_DENIED`.
Operators see one code for "permission denied" regardless of which
bridge raised it.

View File

@@ -98,4 +98,3 @@ bunx turbo lint typecheck test:coverage --filter=@suaveplan/api-sandbox-wasm
## License
MIT

View File

@@ -26,7 +26,9 @@ Shared Zod schemas describing Suaveplan API request/response shapes. The single
- [metadata](./src/events/metadata.md) — Defines the `EventMetadata` Zod schema for the distributed tracing and actor context attached to every domain event in…
- [helpers](./src/helpers/to-suaveplan-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [to-suaveplan-error](./src/helpers/to-suaveplan-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
<!-- end:auto-docs --> - [to-suaveplan-error](./src/helpers/to-suaveplan-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [to-suaveplan-error](./src/helpers/to-suaveplan-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [to-suaveplan-error](./src/helpers/to-suaveplan-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [to-suaveplan-error](./src/helpers/to-suaveplan-error.md) — <!-- begin:auto-docs --> _(no submodules)_
## Modules
| Module | Description |

View File

@@ -133,4 +133,3 @@ unchanged — see `src/adapter/adapter.spec-conformance.test.ts`.
## License
MIT

View File

@@ -131,4 +131,3 @@ unchanged — see `src/adapter/adapter.spec-conformance.test.ts`.
## License
MIT

View File

@@ -105,4 +105,3 @@ see `src/adapter/adapter.spec-conformance.test.ts`. The
`@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.

View File

@@ -79,4 +79,3 @@ proxy surface before Stage 4 can complete.
- `@suaveplan/api-types` — `SecretsLike` type.
- `@suaveplan/api-worker-rpc` — `MessagePort`-based RPC transport.
- `@suaveplan/error`, `tslib`, `zod`.

View File

@@ -68,4 +68,3 @@ Runtime: `@suaveplan/api-types`, `@suaveplan/error`, `tslib`, `zod`.
## License
MIT

View File

@@ -139,4 +139,3 @@ Stage-7 keystone. Conformance is pinned by the abstract
`runSseEngineConformance` harness from `@suaveplan/api-sse`; this
package's `runBunSseEngineConformance()` re-runs it bound to
`createBunSseEngine`.

View File

@@ -66,4 +66,3 @@ const since = buffer.since("0").length; // 0 (unknown ids throw SSE_CODES.LAST_E
- Version: `0.1.0`
- Stage: 1 of the API plugin system (contracts).
- Tier: universal — zero browser / Node-only deps; runs everywhere the host runs.

View File

@@ -67,4 +67,3 @@ Errors that the abstract contract itself can raise
Stage 4 (Base adapters) of the API plugin system umbrella — see
the design document.

View File

@@ -48,4 +48,3 @@ tooling can fan out one invocation per tenant.
## Stage
Contracts of the API plugin system umbrella.

Some files were not shown because too many files have changed in this diff Show More