@agentcash/router 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +85 -0
- package/README.md +133 -550
- package/dist/index.cjs +567 -525
- package/dist/index.d.cts +90 -71
- package/dist/index.d.ts +90 -71
- package/dist/index.js +559 -506
- package/package.json +6 -14
- package/.claude/CLAUDE.md +0 -343
- package/.claude/skills/router-guide/SKILL.md +0 -585
package/AGENTS.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI agents working on `@agentcash/router`.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
A protocol-agnostic route framework for Next.js App Router APIs. Provides x402 payments, MPP payments, SIWX identity auth, and API key auth behind a single fluent builder. A route definition is 3 to 6 lines; everything else (pricing, discovery, OpenAPI, settlement) is derived.
|
|
8
|
+
|
|
9
|
+
## Guiding principles
|
|
10
|
+
|
|
11
|
+
1. Route definition is 3 to 6 lines.
|
|
12
|
+
2. Single source of truth: the route registry drives discovery, OpenAPI, and pricing.
|
|
13
|
+
3. Auth and pricing are orthogonal: `.paid()`, `.siwx()`, `.apiKey()`, `.unprotected()`.
|
|
14
|
+
4. Observability is pluggable via `RouterPlugin`. No boilerplate.
|
|
15
|
+
5. The package owns x402 and MPP server lifecycles (init, verify, settle).
|
|
16
|
+
6. Compose, do not reimplement. Delegate to `@x402/*`, `@coinbase/x402`, and `mppx`.
|
|
17
|
+
|
|
18
|
+
## Layout
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
src/
|
|
22
|
+
index.ts public surface — createRouter / createRouterFromEnv
|
|
23
|
+
builder.ts fluent RouteBuilder
|
|
24
|
+
registry.ts Map-backed route registry
|
|
25
|
+
constants.ts network ids, USDC asset/decimals, default facilitator
|
|
26
|
+
types.ts core types (RouteEntry, HandlerContext, HttpError)
|
|
27
|
+
plugin/ RouterPlugin types + lifecycle dispatch
|
|
28
|
+
init/ protocol init (x402.ts, mpp.ts) + env reader (from-env.ts)
|
|
29
|
+
protocols/ x402/ and mpp/ strategies, detect.ts, accepts
|
|
30
|
+
auth/ siwx.ts, api-key.ts, normalize-wallet.ts
|
|
31
|
+
kv-store/ one KvStore backs siwx nonce, siwx entitlement, mpp replay
|
|
32
|
+
pricing/ fixed, tiered, dynamic, atomic conversion
|
|
33
|
+
pipeline/ flows (paid, siwx-only, api-key-only, unprotected)
|
|
34
|
+
discovery/ well-known, openapi, llms-txt
|
|
35
|
+
config/ RouterConfig validation, RouterConfigError, issue codes
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Pipeline
|
|
39
|
+
|
|
40
|
+
`auth check -> body parse -> validate -> 402 challenge -> payment verify -> handler -> settle -> finalize`
|
|
41
|
+
|
|
42
|
+
## Critical rules
|
|
43
|
+
|
|
44
|
+
- **Error handling.** Respect `.status` on any thrown error, not just `HttpError`. Pattern: `throw Object.assign(new Error('msg'), { status: 409 })`.
|
|
45
|
+
- **SIWX challenge.** Must return an x402v2 challenge with `PAYMENT-REQUIRED` header and a JSON body whose `extensions['sign-in-with-x']` has `domain`, `uri`, `version`, `chainId`, `type`, `nonce`, `issuedAt`.
|
|
46
|
+
- **Discovery visibility.** `authMode !== 'unprotected'` determines well-known visibility, not the protocol list. SIWX routes are discoverable.
|
|
47
|
+
- **OpenAPI.** Merge paths for multi-method endpoints (GET + DELETE on same path). Never overwrite.
|
|
48
|
+
- **Duplicate route keys.** Registry silently overwrites (last write wins) with a dev-only `console.warn`. This is intentional: Next.js module load order is non-deterministic, so stub + real handler may register either order.
|
|
49
|
+
- **Args-driven pricing.** Body is parsed before the 402 challenge via `request.clone()` when pricing is a function. `maxPrice` is optional and acts as a cap and a fallback on pricing function errors.
|
|
50
|
+
- **MPP operator vs fee-payer.** `mpp.operatorKey` and `mpp.feePayerKey` MUST resolve to different addresses. Tempo rejects fee-delegated txs where `sender === feePayer`. `createRouter` validates this at construction and throws `mpp_operator_equals_fee_payer`.
|
|
51
|
+
- **MPP operator address.** Must equal `recipient` / payee. mppx's close handler asserts `sender === payee` on settle.
|
|
52
|
+
- **Streaming requires MPP.** `.stream()` only works on MPP. x402 has no streaming primitive.
|
|
53
|
+
|
|
54
|
+
## Two entry points
|
|
55
|
+
|
|
56
|
+
Two ways to initialize, both publicly exported:
|
|
57
|
+
|
|
58
|
+
- **`createRouterFromEnv(options)`** — paved road. Reads `process.env`, validates every value, throws a single `RouterConfigError` with all problems at once. Auto-emits `exact` + `upto` accepts on Base, auto-adds Solana when `SOLANA_PAYEE_ADDRESS` is set, auto-enables MPP session mode when `MPP_OPERATOR_KEY` is set.
|
|
59
|
+
- **`createRouter(config)`** — lower-level. Caller passes a fully-built `RouterConfig`. Use when env doesn't cover the case (custom networks, multi-payee setups, non-standard assets, fully programmatic configs).
|
|
60
|
+
|
|
61
|
+
Implementation: `createRouterFromEnv(options)` ≡ `createRouter(routerConfigFromEnv(options))`. `routerConfigFromEnv` is also exported, so consumers who want "env-derived base + programmatic tweaks" can spread the result and override fields before passing to `createRouter`.
|
|
62
|
+
|
|
63
|
+
## Environment variables
|
|
64
|
+
|
|
65
|
+
`src/config/schema.ts` is the single source of truth — `envShape` declares every var the router reads (each field's `.refine(...)` carries both the shape check and the user-facing description). `ENV_KEYS` is derived from it. README and `.env.example` are drift-tested against `ENV_KEYS` (see `tests/env-drift.test.ts`); when adding/renaming an env var, edit `schema.ts` and the two user-facing docs together.
|
|
66
|
+
|
|
67
|
+
## Build and test
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pnpm build # tsup
|
|
71
|
+
pnpm test # vitest
|
|
72
|
+
pnpm typecheck # tsc --noEmit
|
|
73
|
+
pnpm check # format + lint + typecheck + build + test
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Releasing
|
|
77
|
+
|
|
78
|
+
Uses [changesets](https://github.com/changesets/changesets).
|
|
79
|
+
|
|
80
|
+
1. `pnpm changeset`, describe the change (patch / minor / major).
|
|
81
|
+
2. Commit the changeset file with the PR.
|
|
82
|
+
3. On merge to `main`, the action opens a "chore: version packages" PR.
|
|
83
|
+
4. Merging the version PR publishes to npm.
|
|
84
|
+
|
|
85
|
+
Troubleshooting: publish needs `NPM_TOKEN` with write access to `@agentcash`. Version PR not created means no `.changeset/*.md` in the merged PR.
|