@routedock/routedock 0.3.0 → 0.4.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/README.md +113 -12
- package/dist/{MppSessionHandler-1EL8QBAn.d.cts → MppSessionHandler-3QfCHI5x.d.ts} +40 -2
- package/dist/{MppSessionHandler-Bq4S-JTE.d.ts → MppSessionHandler-xu4Kxu6N.d.cts} +40 -2
- package/dist/{ProviderRegistry-CA_TdREG.d.ts → ProviderRegistry-D9KqyuH-.d.cts} +16 -36
- package/dist/{ProviderRegistry-D-0rqK0N.d.cts → ProviderRegistry-DVi2uzgk.d.ts} +16 -36
- package/dist/{RouteDockClient-go9aopfF.d.cts → RouteDockClient-6rmgkbYb.d.cts} +124 -142
- package/dist/{RouteDockClient-Bh86bVly.d.ts → RouteDockClient-CnAkxwrW.d.ts} +124 -142
- package/dist/{SessionReconciler-Bw-PoBVl.d.ts → SessionReconciler-Cce9MXO1.d.ts} +10 -3
- package/dist/{SessionReconciler-Cz2nuOlJ.d.cts → SessionReconciler-Dpe9qXdD.d.cts} +10 -3
- package/dist/{SessionStore-BaYiegP0.d.ts → SessionStore-DkLBxFQu.d.cts} +28 -3
- package/dist/{SessionStore-B4-Hi4H8.d.cts → SessionStore-_ZkoBzFY.d.ts} +28 -3
- package/dist/SpendStore-BUclV02i.d.ts +73 -0
- package/dist/SpendStore-s_dfcemj.d.cts +73 -0
- package/dist/client.cjs +767 -487
- package/dist/client.d.cts +80 -10
- package/dist/client.d.ts +80 -10
- package/dist/client.js +733 -468
- package/dist/index.cjs +1295 -590
- package/dist/index.d.cts +13 -10
- package/dist/index.d.ts +13 -10
- package/dist/index.js +1247 -559
- package/dist/logger-DVa7VT4c.d.cts +41 -0
- package/dist/logger-DVa7VT4c.d.ts +41 -0
- package/dist/network.cjs +57 -0
- package/dist/network.d.cts +72 -0
- package/dist/network.d.ts +72 -0
- package/dist/network.js +49 -0
- package/dist/node.cjs +166 -0
- package/dist/node.d.cts +77 -0
- package/dist/node.d.ts +77 -0
- package/dist/node.js +159 -0
- package/dist/provider/fastify.cjs +847 -62
- package/dist/provider/fastify.d.cts +10 -3
- package/dist/provider/fastify.d.ts +10 -3
- package/dist/provider/fastify.js +848 -63
- package/dist/provider/hono.cjs +936 -60
- package/dist/provider/hono.d.cts +23 -8
- package/dist/provider/hono.d.ts +23 -8
- package/dist/provider/hono.js +937 -61
- package/dist/provider.cjs +894 -70
- package/dist/provider.d.cts +9 -8
- package/dist/provider.d.ts +9 -8
- package/dist/provider.js +895 -72
- package/dist/react.cjs +736 -436
- package/dist/react.d.cts +7 -5
- package/dist/react.d.ts +7 -5
- package/dist/react.js +725 -425
- package/dist/{routedockMiddleware-57gUaEMf.d.ts → routedockMiddleware-Cq9HOJEa.d.ts} +9 -2
- package/dist/{routedockMiddleware-DlyLrxp7.d.cts → routedockMiddleware-CxsWkSKa.d.cts} +9 -2
- package/dist/schema.cjs +7 -0
- package/dist/schema.js +7 -0
- package/dist/{sign-AKH67sft.d.cts → sign-Bq08SeFq.d.ts} +2 -2
- package/dist/{sign-BEq-OsSq.d.ts → sign-DqGE0Plv.d.cts} +2 -2
- package/dist/testing.d.cts +4 -3
- package/dist/testing.d.ts +4 -3
- package/dist/{logger-D8_Q2ytp.d.cts → types-DXaS5Wip.d.cts} +85 -47
- package/dist/{logger-D8_Q2ytp.d.ts → types-DXaS5Wip.d.ts} +85 -47
- package/package.json +50 -4
package/README.md
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
# @routedock/
|
|
1
|
+
# @routedock/routedock
|
|
2
2
|
|
|
3
3
|
Unified payment execution layer for autonomous agents on Stellar. One SDK for x402, MPP charge, and MPP session — mode selected automatically from the provider's `routedock.json` manifest.
|
|
4
4
|
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
Node.js **22 or newer**, matching the supported runtime of all RouteDock npm packages.
|
|
8
|
+
|
|
5
9
|
## Install
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
|
-
npm install @routedock/
|
|
12
|
+
npm install @routedock/routedock
|
|
9
13
|
```
|
|
10
14
|
|
|
11
15
|
## Agent Usage
|
|
12
16
|
|
|
13
17
|
```ts
|
|
14
|
-
import { RouteDockClient } from '@routedock/
|
|
18
|
+
import { RouteDockClient } from '@routedock/routedock/client'
|
|
15
19
|
import { Keypair } from '@stellar/stellar-sdk'
|
|
16
20
|
|
|
17
21
|
const client = new RouteDockClient({
|
|
@@ -35,6 +39,47 @@ for await (const update of session.stream()) {
|
|
|
35
39
|
await session.close() // triggers on-chain settlement
|
|
36
40
|
```
|
|
37
41
|
|
|
42
|
+
### POST endpoints and custom headers
|
|
43
|
+
|
|
44
|
+
`pay()` sends a `GET` with no body by default. For endpoints that take input,
|
|
45
|
+
pass `request` with the method, headers and body to send:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const result = await client.pay('https://provider.example.com/infer', {
|
|
49
|
+
request: {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: { 'content-type': 'application/json', 'x-trace-id': 'trace-123' },
|
|
52
|
+
body: JSON.stringify({ prompt: 'Explain MPP charge in one sentence' }),
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The same request is replayed on the unpaid 402 probe, the paid request and any
|
|
58
|
+
retry, so the body is buffered once (streams are drained up front). Payment
|
|
59
|
+
headers set by the SDK — `PAYMENT-SIGNATURE`/`X-PAYMENT` for x402 and
|
|
60
|
+
`Authorization` for MPP — always win over a caller header with the same name.
|
|
61
|
+
The method also scopes the per-endpoint sunset check, so a sunset `GET /infer`
|
|
62
|
+
no longer blocks an active `POST /infer`.
|
|
63
|
+
|
|
64
|
+
Sessions accept the same field per stream:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
for await (const update of session.stream({
|
|
68
|
+
request: { method: 'POST', body: JSON.stringify({ channel: 'XLM/USDC' }) },
|
|
69
|
+
})) {
|
|
70
|
+
console.log(update)
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Spend cap and other assets
|
|
75
|
+
|
|
76
|
+
The cap is a single USDC total. If the asset selected for a payment is not
|
|
77
|
+
`spendCap.asset` (for example a provider that prices in XLM), `pay()` and
|
|
78
|
+
`openSession()` throw `RouteDockPolicyRejectError` with reason
|
|
79
|
+
`local_cap_asset_mismatch` before anything is paid, and nothing is added to the
|
|
80
|
+
USDC total. USDC-only providers are unaffected. See
|
|
81
|
+
`docs/MULTI_ASSET_SUPPORT.md`.
|
|
82
|
+
|
|
38
83
|
### Durable spend cap
|
|
39
84
|
|
|
40
85
|
The `spendCap` is enforced via a pluggable `SpendStore` (`read()` / `write()`).
|
|
@@ -44,7 +89,7 @@ production, inject a persistent implementation so a crash or restart can't reset
|
|
|
44
89
|
the accumulator and bypass the cap:
|
|
45
90
|
|
|
46
91
|
```ts
|
|
47
|
-
import { RouteDockClient, type SpendStore, type DailySpend } from '@routedock/
|
|
92
|
+
import { RouteDockClient, type SpendStore, type DailySpend } from '@routedock/routedock/client'
|
|
48
93
|
|
|
49
94
|
const redisSpendStore: SpendStore = {
|
|
50
95
|
async read(): Promise<DailySpend | null> {
|
|
@@ -64,11 +109,42 @@ const client = new RouteDockClient({
|
|
|
64
109
|
})
|
|
65
110
|
```
|
|
66
111
|
|
|
112
|
+
On Node you can use the file-backed store instead. It depends on `node:fs`, so it
|
|
113
|
+
lives in a Node-only entry point and is **not** exported from `/client`:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { RouteDockClient } from '@routedock/routedock/client'
|
|
117
|
+
import { FileSpendStore } from '@routedock/routedock/node' // Node only (node:fs)
|
|
118
|
+
|
|
119
|
+
const client = new RouteDockClient({
|
|
120
|
+
// ...
|
|
121
|
+
spendStore: new FileSpendStore('~/.routedock/spend.json'),
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Sharing one store between processes.** The client serializes its own
|
|
126
|
+
read → check → write, but that only protects one `RouteDockClient`. If two
|
|
127
|
+
processes can use the same store (the MCP server and the example agent both
|
|
128
|
+
default to `~/.routedock/spend.json`), a plain `read()` / `write()` store can
|
|
129
|
+
lose updates and let the cap be exceeded. A shared store must implement the
|
|
130
|
+
optional atomic `update(fn)` method, which the client uses automatically.
|
|
131
|
+
`FileSpendStore` implements it with an exclusive lock file
|
|
132
|
+
(`<file>.lock`, stale locks from crashed processes are broken after 10 s):
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const store: SpendStore = {
|
|
136
|
+
read, write,
|
|
137
|
+
// fn(prev) returns the next state, or undefined to leave it unchanged.
|
|
138
|
+
// Make the read, fn and write atomic (a transaction, CAS loop, lock, ...).
|
|
139
|
+
async update(fn) { /* ... */ },
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
67
143
|
## Provider Usage
|
|
68
144
|
|
|
69
145
|
```ts
|
|
70
146
|
import express from 'express'
|
|
71
|
-
import { routedock } from '@routedock/
|
|
147
|
+
import { routedock } from '@routedock/routedock/provider'
|
|
72
148
|
|
|
73
149
|
const app = express()
|
|
74
150
|
|
|
@@ -441,6 +517,26 @@ import from `@routedock/routedock/provider` in a Workers snippet — that's the
|
|
|
441
517
|
Node-only Express entry point and pulls in dependencies (like `express`) that
|
|
442
518
|
don't run on Workers.
|
|
443
519
|
|
|
520
|
+
### Runtime-neutral entry points
|
|
521
|
+
|
|
522
|
+
`@routedock/routedock/client`, `/react` and `/provider/hono` use only
|
|
523
|
+
Web-standard APIs. They run in browsers, Cloudflare Workers (no `nodejs_compat`
|
|
524
|
+
needed for this package), Bun, Deno and Node, and contain no `node:*` imports or
|
|
525
|
+
`Buffer` references. CI enforces this (`node scripts/check-runtime-neutral.mjs`)
|
|
526
|
+
against the built output.
|
|
527
|
+
|
|
528
|
+
Anything that needs Node built-ins is kept out of those entries:
|
|
529
|
+
|
|
530
|
+
| Import | Runtime | Notes |
|
|
531
|
+
| --- | --- | --- |
|
|
532
|
+
| `@routedock/routedock/client`, `/react`, `/provider/hono` | any | runtime-neutral |
|
|
533
|
+
| `@routedock/routedock/node` | Node only | `FileSpendStore` (`node:fs`) |
|
|
534
|
+
| `@routedock/routedock/provider`, `/provider/fastify` | Node only | Express/Fastify adapters |
|
|
535
|
+
| `@routedock/routedock` | Node | full SDK, includes `FileSpendStore` |
|
|
536
|
+
|
|
537
|
+
Third-party dependencies are outside this guarantee: for example `mppx` imports
|
|
538
|
+
`node:util`, so a Worker that uses it can still need `nodejs_compat`.
|
|
539
|
+
|
|
444
540
|
## React Integration
|
|
445
541
|
|
|
446
542
|
> **Warning:** These hooks create a RouteDockClient in the browser, so the wallet secret and any commitmentSecret are readable by anyone who loads the page.
|
|
@@ -451,10 +547,10 @@ don't run on Workers.
|
|
|
451
547
|
>
|
|
452
548
|
> For production or mainnet, keep RouteDockClient on the server (a route handler or server action) and read the key from a non-public variable such as `AGENT_SECRET`, as the Agent Usage section does.
|
|
453
549
|
|
|
454
|
-
`@routedock/
|
|
550
|
+
`@routedock/routedock/react` provides hooks for client construction, payments, sessions, and live tx log subscription. Wrap your app with `RouteDockProvider`:
|
|
455
551
|
|
|
456
552
|
```tsx
|
|
457
|
-
import { RouteDockProvider, useRouteDockClient } from '@routedock/
|
|
553
|
+
import { RouteDockProvider, useRouteDockClient } from '@routedock/routedock/react'
|
|
458
554
|
import { createClient } from '@supabase/supabase-js'
|
|
459
555
|
|
|
460
556
|
// Dedicated throwaway testnet key. Never a funded or mainnet key.
|
|
@@ -482,7 +578,7 @@ function App({ children }: { children: React.ReactNode }) {
|
|
|
482
578
|
|
|
483
579
|
```ts
|
|
484
580
|
// app/api/price/route.ts (runs on the server only)
|
|
485
|
-
import { RouteDockClient } from '@routedock/
|
|
581
|
+
import { RouteDockClient } from '@routedock/routedock/client'
|
|
486
582
|
|
|
487
583
|
const client = new RouteDockClient({
|
|
488
584
|
wallet: process.env.AGENT_SECRET!,
|
|
@@ -499,7 +595,7 @@ export async function POST() {
|
|
|
499
595
|
### `usePay(url, options?)`
|
|
500
596
|
|
|
501
597
|
```tsx
|
|
502
|
-
import { usePay } from '@routedock/
|
|
598
|
+
import { usePay } from '@routedock/routedock/react'
|
|
503
599
|
|
|
504
600
|
function PriceButton() {
|
|
505
601
|
const { pay, result, loading, error } = usePay('https://provider.example.com/price')
|
|
@@ -516,7 +612,7 @@ function PriceButton() {
|
|
|
516
612
|
|
|
517
613
|
```tsx
|
|
518
614
|
import { useEffect } from 'react'
|
|
519
|
-
import { useSession } from '@routedock/
|
|
615
|
+
import { useSession } from '@routedock/routedock/react'
|
|
520
616
|
|
|
521
617
|
function StreamingFeed() {
|
|
522
618
|
const { open, close, status, vouchers, cumulative } = useSession(
|
|
@@ -537,7 +633,7 @@ The hook automatically fires `session.close()` in the background on unmount when
|
|
|
537
633
|
### `useTxLog(filter?)`
|
|
538
634
|
|
|
539
635
|
```tsx
|
|
540
|
-
import { useTxLog } from '@routedock/
|
|
636
|
+
import { useTxLog } from '@routedock/routedock/react'
|
|
541
637
|
|
|
542
638
|
function ActivityFeed({ channelId }: { channelId: string }) {
|
|
543
639
|
const txLog = useTxLog({ channelId, limit: 25 })
|
|
@@ -572,8 +668,9 @@ import {
|
|
|
572
668
|
RouteDockError,
|
|
573
669
|
RouteDockFacilitatorError,
|
|
574
670
|
RouteDockManifestError,
|
|
671
|
+
RouteDockPaymentRejectedError,
|
|
575
672
|
RouteDockPolicyRejectError,
|
|
576
|
-
} from '@routedock/
|
|
673
|
+
} from '@routedock/routedock/client'
|
|
577
674
|
|
|
578
675
|
const client = new RouteDockClient({
|
|
579
676
|
wallet: process.env.AGENT_SECRET!,
|
|
@@ -587,6 +684,9 @@ try {
|
|
|
587
684
|
} catch (err) {
|
|
588
685
|
if (err instanceof RouteDockPolicyRejectError) {
|
|
589
686
|
console.error('Spend cap exceeded:', err.reason)
|
|
687
|
+
} else if (err instanceof RouteDockPaymentRejectedError) {
|
|
688
|
+
// The provider refused the signed payment; `reason` is its explanation.
|
|
689
|
+
console.error(`Payment rejected (HTTP ${err.status}):`, err.reason ?? err.providerError)
|
|
590
690
|
} else if (err instanceof RouteDockFacilitatorError) {
|
|
591
691
|
console.error(`Facilitator HTTP ${err.status} (retryable=${err.retryable})`)
|
|
592
692
|
} else if (err instanceof RouteDockManifestError) {
|
|
@@ -604,6 +704,7 @@ try {
|
|
|
604
704
|
| `RouteDockManifestError` | no | Invalid manifest, missing pricing fields |
|
|
605
705
|
| `RouteDockNoSupportedModeError` | no | Provider has no compatible payment mode |
|
|
606
706
|
| `RouteDockFacilitatorError` | yes | Facilitator/provider 429 or 5xx |
|
|
707
|
+
| `RouteDockPaymentRejectedError` | no | Provider refused the signed paid request (HTTP 401/402/other 4xx); `status` and `reason` carry why |
|
|
607
708
|
| `RouteDockNetworkError` | yes | Timeouts, connection failures |
|
|
608
709
|
| `RouteDockSignatureError` | no | Signing or commitment failure |
|
|
609
710
|
| `RouteDockVoucherMonotonicityError` | no | Non-increasing voucher amount |
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as RouteDockLogger } from './logger-DVa7VT4c.js';
|
|
2
2
|
import { RequestHandler } from 'express';
|
|
3
3
|
import { Store } from 'mppx';
|
|
4
|
+
import { R as RouteDockManifest } from './types-DXaS5Wip.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Idempotency store for payment settlement.
|
|
@@ -99,6 +100,20 @@ type SettlementReplayCheck = {
|
|
|
99
100
|
} | {
|
|
100
101
|
kind: 'spent';
|
|
101
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* Record a settlement so a retry of the same payment is deduped.
|
|
105
|
+
*
|
|
106
|
+
* Call this only AFTER the payment has settled. By then the funds have moved,
|
|
107
|
+
* so a failing store write must not turn a paid request into a 500: the
|
|
108
|
+
* failure is logged and reported through `onCallbackError(err, 'seenTxStore.set')`
|
|
109
|
+
* and the request carries on to `onSettled` and the route. Never throws.
|
|
110
|
+
*/
|
|
111
|
+
declare function recordSettlement(store: SeenTxStore, key: string, record: SettlementRecord, ctx: {
|
|
112
|
+
logger: RouteDockLogger;
|
|
113
|
+
/** Log prefix, e.g. `[x402]` or `[mpp-charge]`. */
|
|
114
|
+
label: string;
|
|
115
|
+
onCallbackError?: ((err: unknown, cb: string) => void) | undefined;
|
|
116
|
+
}): Promise<void>;
|
|
102
117
|
/**
|
|
103
118
|
* Decide what a payment bearing `key` should do.
|
|
104
119
|
*
|
|
@@ -159,6 +174,22 @@ declare class InMemorySeenTxStore implements SeenTxStore {
|
|
|
159
174
|
*/
|
|
160
175
|
declare function paymentIdempotencyKey(getHeader: (name: string) => string | undefined, scope: SettlementScope): Promise<string | null>;
|
|
161
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Explicit provider configuration for recording `session_settled` on the
|
|
179
|
+
* agent vault after a clean mpp-session close.
|
|
180
|
+
*
|
|
181
|
+
* This replaced the old `process.env.AGENT_VAULT_CONTRACT` read inside the
|
|
182
|
+
* provider handlers: Workers have no `process.env` without `nodejs_compat`,
|
|
183
|
+
* and the docs told operators to set `AGENT_VAULT_CONTRACT_ID`, which the SDK
|
|
184
|
+
* never read. Passing the contract in as an option works on every runtime.
|
|
185
|
+
*/
|
|
186
|
+
interface VaultSettlementConfig {
|
|
187
|
+
/** Agent vault contract id (C...) whose `record_session_settlement` entry point records the session. */
|
|
188
|
+
contract: string;
|
|
189
|
+
/** Soroban RPC endpoint override; defaults to the public endpoint for the configured network. */
|
|
190
|
+
rpcUrl?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
162
193
|
/** Store shape extended with optional atomic update operation. */
|
|
163
194
|
type ChannelStore = Store.Store & {
|
|
164
195
|
update?: (key: string, fn: (prev: unknown) => unknown) => Promise<unknown>;
|
|
@@ -209,7 +240,14 @@ interface MppSessionHandlerOptions {
|
|
|
209
240
|
idleTimeoutMs?: number;
|
|
210
241
|
/** Log sink for internal error paths. Defaults to a console-backed logger. */
|
|
211
242
|
logger?: RouteDockLogger;
|
|
243
|
+
/**
|
|
244
|
+
* Record `session_settled` on the agent vault after each clean close.
|
|
245
|
+
* `contract` is the vault's C... id; `rpcUrl` overrides the default Soroban
|
|
246
|
+
* RPC endpoint for the configured network. Falls back to the deprecated
|
|
247
|
+
* `AGENT_VAULT_CONTRACT`/`AGENT_VAULT_CONTRACT_ID` env vars when unset.
|
|
248
|
+
*/
|
|
249
|
+
vaultSettlement?: VaultSettlementConfig;
|
|
212
250
|
}
|
|
213
251
|
declare function createMppSessionHandler(opts: MppSessionHandlerOptions): RequestHandler;
|
|
214
252
|
|
|
215
|
-
export { type ChannelStore as C, InMemorySeenTxStore as I, MAX_SETTLEMENT_REPLAYS as M, type OrphanedSessionInfo as O, type SeenTxStore as S, type
|
|
253
|
+
export { type ChannelStore as C, InMemorySeenTxStore as I, MAX_SETTLEMENT_REPLAYS as M, type OrphanedSessionInfo as O, type SeenTxStore as S, type VaultSettlementConfig as V, type SettlementRecord as a, type InMemorySeenTxStoreOptions as b, type MppSessionHandlerOptions as c, type OrphanReason as d, SETTLEMENT_REPLAY_WINDOW_MS as e, type SettlementReplayCheck as f, type SettlementScope as g, type VoucherStoreValue as h, checkSettlementReplay as i, createMppSessionHandler as j, isVoucherStoreValue as k, paymentIdempotencyKey as p, recordSettlement as r };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as RouteDockLogger } from './logger-DVa7VT4c.cjs';
|
|
2
2
|
import { RequestHandler } from 'express';
|
|
3
3
|
import { Store } from 'mppx';
|
|
4
|
+
import { R as RouteDockManifest } from './types-DXaS5Wip.cjs';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Idempotency store for payment settlement.
|
|
@@ -99,6 +100,20 @@ type SettlementReplayCheck = {
|
|
|
99
100
|
} | {
|
|
100
101
|
kind: 'spent';
|
|
101
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* Record a settlement so a retry of the same payment is deduped.
|
|
105
|
+
*
|
|
106
|
+
* Call this only AFTER the payment has settled. By then the funds have moved,
|
|
107
|
+
* so a failing store write must not turn a paid request into a 500: the
|
|
108
|
+
* failure is logged and reported through `onCallbackError(err, 'seenTxStore.set')`
|
|
109
|
+
* and the request carries on to `onSettled` and the route. Never throws.
|
|
110
|
+
*/
|
|
111
|
+
declare function recordSettlement(store: SeenTxStore, key: string, record: SettlementRecord, ctx: {
|
|
112
|
+
logger: RouteDockLogger;
|
|
113
|
+
/** Log prefix, e.g. `[x402]` or `[mpp-charge]`. */
|
|
114
|
+
label: string;
|
|
115
|
+
onCallbackError?: ((err: unknown, cb: string) => void) | undefined;
|
|
116
|
+
}): Promise<void>;
|
|
102
117
|
/**
|
|
103
118
|
* Decide what a payment bearing `key` should do.
|
|
104
119
|
*
|
|
@@ -159,6 +174,22 @@ declare class InMemorySeenTxStore implements SeenTxStore {
|
|
|
159
174
|
*/
|
|
160
175
|
declare function paymentIdempotencyKey(getHeader: (name: string) => string | undefined, scope: SettlementScope): Promise<string | null>;
|
|
161
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Explicit provider configuration for recording `session_settled` on the
|
|
179
|
+
* agent vault after a clean mpp-session close.
|
|
180
|
+
*
|
|
181
|
+
* This replaced the old `process.env.AGENT_VAULT_CONTRACT` read inside the
|
|
182
|
+
* provider handlers: Workers have no `process.env` without `nodejs_compat`,
|
|
183
|
+
* and the docs told operators to set `AGENT_VAULT_CONTRACT_ID`, which the SDK
|
|
184
|
+
* never read. Passing the contract in as an option works on every runtime.
|
|
185
|
+
*/
|
|
186
|
+
interface VaultSettlementConfig {
|
|
187
|
+
/** Agent vault contract id (C...) whose `record_session_settlement` entry point records the session. */
|
|
188
|
+
contract: string;
|
|
189
|
+
/** Soroban RPC endpoint override; defaults to the public endpoint for the configured network. */
|
|
190
|
+
rpcUrl?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
162
193
|
/** Store shape extended with optional atomic update operation. */
|
|
163
194
|
type ChannelStore = Store.Store & {
|
|
164
195
|
update?: (key: string, fn: (prev: unknown) => unknown) => Promise<unknown>;
|
|
@@ -209,7 +240,14 @@ interface MppSessionHandlerOptions {
|
|
|
209
240
|
idleTimeoutMs?: number;
|
|
210
241
|
/** Log sink for internal error paths. Defaults to a console-backed logger. */
|
|
211
242
|
logger?: RouteDockLogger;
|
|
243
|
+
/**
|
|
244
|
+
* Record `session_settled` on the agent vault after each clean close.
|
|
245
|
+
* `contract` is the vault's C... id; `rpcUrl` overrides the default Soroban
|
|
246
|
+
* RPC endpoint for the configured network. Falls back to the deprecated
|
|
247
|
+
* `AGENT_VAULT_CONTRACT`/`AGENT_VAULT_CONTRACT_ID` env vars when unset.
|
|
248
|
+
*/
|
|
249
|
+
vaultSettlement?: VaultSettlementConfig;
|
|
212
250
|
}
|
|
213
251
|
declare function createMppSessionHandler(opts: MppSessionHandlerOptions): RequestHandler;
|
|
214
252
|
|
|
215
|
-
export { type ChannelStore as C, InMemorySeenTxStore as I, MAX_SETTLEMENT_REPLAYS as M, type OrphanedSessionInfo as O, type SeenTxStore as S, type
|
|
253
|
+
export { type ChannelStore as C, InMemorySeenTxStore as I, MAX_SETTLEMENT_REPLAYS as M, type OrphanedSessionInfo as O, type SeenTxStore as S, type VaultSettlementConfig as V, type SettlementRecord as a, type InMemorySeenTxStoreOptions as b, type MppSessionHandlerOptions as c, type OrphanReason as d, SETTLEMENT_REPLAY_WINDOW_MS as e, type SettlementReplayCheck as f, type SettlementScope as g, type VoucherStoreValue as h, checkSettlementReplay as i, createMppSessionHandler as j, isVoucherStoreValue as k, paymentIdempotencyKey as p, recordSettlement as r };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { usdcToStroops } from '@routedock/nulth-sdk';
|
|
2
|
-
import {
|
|
3
|
-
import { ClientStellarSigner } from '@x402/stellar';
|
|
4
|
-
import { h as RouteDockManifest, c as PaymentResult } from './logger-D8_Q2ytp.js';
|
|
2
|
+
import { R as RouteDockManifest, c as PaymentRequest, d as PaymentResult } from './types-DXaS5Wip.cjs';
|
|
5
3
|
import { Keypair } from '@stellar/stellar-sdk';
|
|
4
|
+
import { R as RetryPolicy } from './RouteDockClient-6rmgkbYb.cjs';
|
|
6
5
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -20,46 +19,27 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
20
19
|
declare const usdcToUnits: typeof usdcToStroops;
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
|
-
*
|
|
22
|
+
* Validate semantic constraints for manifest fields beyond JSON schema syntax.
|
|
23
|
+
* Enforces:
|
|
24
|
+
* - All keys in `latency_hints` must be a subset of declared `regions`.
|
|
25
|
+
* - If `assets` is defined, it must be a non-empty array whose first entry
|
|
26
|
+
* (`assets[0]`) matches the root-level `asset` and `asset_contract`.
|
|
27
|
+
* - Every mode in `modes` has a matching `pricing` entry, so `pay()` and
|
|
28
|
+
* `estimateCost()` never read a missing price.
|
|
29
|
+
* - Every entry in `deprecated_modes` is also listed in `modes`.
|
|
30
|
+
* - Every price (`amount`, `rate`, `min_deposit`) is a decimal the SDK can
|
|
31
|
+
* convert to base units (non-negative, at most 7 fractional digits).
|
|
24
32
|
*
|
|
25
|
-
*
|
|
26
|
-
* cumulative spending totals across process restarts, crashes, and redeploys.
|
|
27
|
-
*
|
|
28
|
-
* ### Error semantics
|
|
29
|
-
* - File absent (ENOENT): returns null — legitimately no spend recorded yet.
|
|
30
|
-
* - File present but unreadable or malformed: throws — a safety control must
|
|
31
|
-
* fail closed, not assume nothing was spent.
|
|
32
|
-
*
|
|
33
|
-
* ### Write atomicity
|
|
34
|
-
* Writes go to `<filePath>.tmp` first, then `fs.rename` onto the target.
|
|
35
|
-
* `rename` is atomic within a filesystem, so there is no window where the
|
|
36
|
-
* target file is truncated but not yet fully written.
|
|
33
|
+
* Every failure is a {@link RouteDockManifestError}.
|
|
37
34
|
*/
|
|
38
|
-
declare
|
|
39
|
-
readonly filePath: string;
|
|
40
|
-
constructor(filePath: string);
|
|
41
|
-
read(): Promise<DailySpend | null>;
|
|
42
|
-
write(state: DailySpend): Promise<void>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
type Network = 'testnet' | 'mainnet';
|
|
46
|
-
declare class X402Client {
|
|
47
|
-
private readonly network;
|
|
48
|
-
private readonly retryPolicy?;
|
|
49
|
-
private readonly httpClient;
|
|
50
|
-
private readonly signer;
|
|
51
|
-
constructor(secretKeyOrSigner: string | ClientStellarSigner, network: Network, retryPolicy?: RetryPolicy | undefined);
|
|
52
|
-
/** Replace signer (e.g. swap to Nulth ZK account payer before pay) */
|
|
53
|
-
withSigner(signer: ClientStellarSigner): X402Client;
|
|
54
|
-
pay(url: string, manifest: RouteDockManifest): Promise<PaymentResult>;
|
|
55
|
-
}
|
|
35
|
+
declare function assertManifestValid(manifest: RouteDockManifest, baseUrl?: string): void;
|
|
56
36
|
|
|
57
37
|
declare class MppChargeClient {
|
|
58
38
|
private readonly keypair;
|
|
59
39
|
private readonly network;
|
|
60
40
|
private readonly retryPolicy?;
|
|
61
41
|
constructor(keypair: Keypair, network: 'testnet' | 'mainnet', retryPolicy?: RetryPolicy | undefined);
|
|
62
|
-
pay(url: string, manifest: RouteDockManifest): Promise<PaymentResult>;
|
|
42
|
+
pay(url: string, manifest: RouteDockManifest, request?: PaymentRequest): Promise<PaymentResult>;
|
|
63
43
|
}
|
|
64
44
|
|
|
65
45
|
interface OnChainProviderInfo {
|
|
@@ -139,4 +119,4 @@ declare class ProviderRegistry {
|
|
|
139
119
|
fetchProviderManifest(record: ProviderRecord): Promise<RouteDockManifest>;
|
|
140
120
|
}
|
|
141
121
|
|
|
142
|
-
export {
|
|
122
|
+
export { MppChargeClient as M, type OnChainProviderInfo as O, type ProviderRecord as P, OnChainRegistry as a, ProviderRegistry as b, type ProviderRegistryConfig as c, assertManifestValid as d, usdcToUnits as u };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { usdcToStroops } from '@routedock/nulth-sdk';
|
|
2
|
-
import {
|
|
3
|
-
import { ClientStellarSigner } from '@x402/stellar';
|
|
4
|
-
import { h as RouteDockManifest, c as PaymentResult } from './logger-D8_Q2ytp.cjs';
|
|
2
|
+
import { R as RouteDockManifest, c as PaymentRequest, d as PaymentResult } from './types-DXaS5Wip.js';
|
|
5
3
|
import { Keypair } from '@stellar/stellar-sdk';
|
|
4
|
+
import { R as RetryPolicy } from './RouteDockClient-CnAkxwrW.js';
|
|
6
5
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -20,46 +19,27 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
20
19
|
declare const usdcToUnits: typeof usdcToStroops;
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
|
-
*
|
|
22
|
+
* Validate semantic constraints for manifest fields beyond JSON schema syntax.
|
|
23
|
+
* Enforces:
|
|
24
|
+
* - All keys in `latency_hints` must be a subset of declared `regions`.
|
|
25
|
+
* - If `assets` is defined, it must be a non-empty array whose first entry
|
|
26
|
+
* (`assets[0]`) matches the root-level `asset` and `asset_contract`.
|
|
27
|
+
* - Every mode in `modes` has a matching `pricing` entry, so `pay()` and
|
|
28
|
+
* `estimateCost()` never read a missing price.
|
|
29
|
+
* - Every entry in `deprecated_modes` is also listed in `modes`.
|
|
30
|
+
* - Every price (`amount`, `rate`, `min_deposit`) is a decimal the SDK can
|
|
31
|
+
* convert to base units (non-negative, at most 7 fractional digits).
|
|
24
32
|
*
|
|
25
|
-
*
|
|
26
|
-
* cumulative spending totals across process restarts, crashes, and redeploys.
|
|
27
|
-
*
|
|
28
|
-
* ### Error semantics
|
|
29
|
-
* - File absent (ENOENT): returns null — legitimately no spend recorded yet.
|
|
30
|
-
* - File present but unreadable or malformed: throws — a safety control must
|
|
31
|
-
* fail closed, not assume nothing was spent.
|
|
32
|
-
*
|
|
33
|
-
* ### Write atomicity
|
|
34
|
-
* Writes go to `<filePath>.tmp` first, then `fs.rename` onto the target.
|
|
35
|
-
* `rename` is atomic within a filesystem, so there is no window where the
|
|
36
|
-
* target file is truncated but not yet fully written.
|
|
33
|
+
* Every failure is a {@link RouteDockManifestError}.
|
|
37
34
|
*/
|
|
38
|
-
declare
|
|
39
|
-
readonly filePath: string;
|
|
40
|
-
constructor(filePath: string);
|
|
41
|
-
read(): Promise<DailySpend | null>;
|
|
42
|
-
write(state: DailySpend): Promise<void>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
type Network = 'testnet' | 'mainnet';
|
|
46
|
-
declare class X402Client {
|
|
47
|
-
private readonly network;
|
|
48
|
-
private readonly retryPolicy?;
|
|
49
|
-
private readonly httpClient;
|
|
50
|
-
private readonly signer;
|
|
51
|
-
constructor(secretKeyOrSigner: string | ClientStellarSigner, network: Network, retryPolicy?: RetryPolicy | undefined);
|
|
52
|
-
/** Replace signer (e.g. swap to Nulth ZK account payer before pay) */
|
|
53
|
-
withSigner(signer: ClientStellarSigner): X402Client;
|
|
54
|
-
pay(url: string, manifest: RouteDockManifest): Promise<PaymentResult>;
|
|
55
|
-
}
|
|
35
|
+
declare function assertManifestValid(manifest: RouteDockManifest, baseUrl?: string): void;
|
|
56
36
|
|
|
57
37
|
declare class MppChargeClient {
|
|
58
38
|
private readonly keypair;
|
|
59
39
|
private readonly network;
|
|
60
40
|
private readonly retryPolicy?;
|
|
61
41
|
constructor(keypair: Keypair, network: 'testnet' | 'mainnet', retryPolicy?: RetryPolicy | undefined);
|
|
62
|
-
pay(url: string, manifest: RouteDockManifest): Promise<PaymentResult>;
|
|
42
|
+
pay(url: string, manifest: RouteDockManifest, request?: PaymentRequest): Promise<PaymentResult>;
|
|
63
43
|
}
|
|
64
44
|
|
|
65
45
|
interface OnChainProviderInfo {
|
|
@@ -139,4 +119,4 @@ declare class ProviderRegistry {
|
|
|
139
119
|
fetchProviderManifest(record: ProviderRecord): Promise<RouteDockManifest>;
|
|
140
120
|
}
|
|
141
121
|
|
|
142
|
-
export {
|
|
122
|
+
export { MppChargeClient as M, type OnChainProviderInfo as O, type ProviderRecord as P, OnChainRegistry as a, ProviderRegistry as b, type ProviderRegistryConfig as c, assertManifestValid as d, usdcToUnits as u };
|