@agentcash/router 1.6.0 → 1.7.1

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 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.