@routedock/routedock 0.2.0 → 0.3.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 +305 -0
- package/dist/MppSessionHandler-1EL8QBAn.d.cts +215 -0
- package/dist/MppSessionHandler-Bq4S-JTE.d.ts +215 -0
- package/dist/{ProviderRegistry-C50nyhaF.d.ts → ProviderRegistry-CA_TdREG.d.ts} +2 -2
- package/dist/{ProviderRegistry-BJ9oJLVz.d.cts → ProviderRegistry-D-0rqK0N.d.cts} +2 -2
- package/dist/{RouteDockClient-B1roCa8h.d.cts → RouteDockClient-Bh86bVly.d.ts} +23 -9
- package/dist/{RouteDockClient-BbkqjhMG.d.ts → RouteDockClient-go9aopfF.d.cts} +23 -9
- package/dist/{SessionReconciler-Dscw43F3.d.ts → SessionReconciler-Bw-PoBVl.d.ts} +14 -5
- package/dist/{SessionReconciler-bi0z2qtN.d.cts → SessionReconciler-Cz2nuOlJ.d.cts} +14 -5
- package/dist/{SessionStore-DvkZv8-E.d.ts → SessionStore-B4-Hi4H8.d.cts} +34 -2
- package/dist/{SessionStore-BpK8vv0L.d.cts → SessionStore-BaYiegP0.d.ts} +34 -2
- package/dist/client.cjs +429 -117
- package/dist/client.d.cts +9 -8
- package/dist/client.d.ts +9 -8
- package/dist/client.js +421 -119
- package/dist/index.cjs +652 -220
- package/dist/index.d.cts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.js +643 -221
- package/dist/{types-DmhmfLzP.d.cts → logger-D8_Q2ytp.d.cts} +58 -1
- package/dist/{types-DmhmfLzP.d.ts → logger-D8_Q2ytp.d.ts} +58 -1
- package/dist/provider/fastify.cjs +306 -89
- package/dist/provider/fastify.d.cts +9 -4
- package/dist/provider/fastify.d.ts +9 -4
- package/dist/provider/fastify.js +305 -88
- package/dist/provider/hono.cjs +286 -82
- package/dist/provider/hono.d.cts +9 -7
- package/dist/provider/hono.d.ts +9 -7
- package/dist/provider/hono.js +282 -78
- package/dist/provider.cjs +326 -98
- package/dist/provider.d.cts +14 -10
- package/dist/provider.d.ts +14 -10
- package/dist/provider.js +318 -98
- package/dist/react.cjs +407 -117
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +408 -118
- package/dist/{routedockMiddleware-BlDsHuPl.d.ts → routedockMiddleware-57gUaEMf.d.ts} +9 -4
- package/dist/{routedockMiddleware-D97A5ptQ.d.cts → routedockMiddleware-DlyLrxp7.d.cts} +9 -4
- package/dist/schema.cjs +40 -0
- package/dist/schema.js +40 -0
- package/dist/{sign-Dpj2Mp7k.d.ts → sign-AKH67sft.d.cts} +1 -1
- package/dist/{sign-CUf3rhTx.d.cts → sign-BEq-OsSq.d.ts} +1 -1
- package/dist/testing.cjs +6 -4
- package/dist/testing.d.cts +32 -13
- package/dist/testing.d.ts +32 -13
- package/dist/testing.js +6 -4
- package/package.json +2 -2
- package/dist/MppSessionHandler-B4TyD7Xg.d.cts +0 -121
- package/dist/MppSessionHandler-CLB5SzgN.d.ts +0 -121
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
|
-
import { P as PaymentMode,
|
|
3
|
-
import { O as OrphanedSessionInfo, S as SeenTxStore } from './MppSessionHandler-
|
|
2
|
+
import { P as PaymentMode, h as RouteDockManifest, g as RouteDockLogger } from './logger-D8_Q2ytp.js';
|
|
3
|
+
import { O as OrphanedSessionInfo, S as SeenTxStore } from './MppSessionHandler-Bq4S-JTE.js';
|
|
4
4
|
|
|
5
5
|
interface RouteDockMiddlewareOptions {
|
|
6
6
|
modes: PaymentMode[];
|
|
@@ -12,9 +12,9 @@ interface RouteDockMiddlewareOptions {
|
|
|
12
12
|
channelFactory: string;
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
|
-
asset
|
|
15
|
+
asset?: string;
|
|
16
16
|
/** Stellar Asset Contract address for the payment asset */
|
|
17
|
-
assetContract
|
|
17
|
+
assetContract?: string;
|
|
18
18
|
payee: string;
|
|
19
19
|
network: 'testnet' | 'mainnet';
|
|
20
20
|
/** Private key (S...) of the server/payee account */
|
|
@@ -53,6 +53,11 @@ interface RouteDockMiddlewareOptions {
|
|
|
53
53
|
* duplicate settlement on agent retries. Defaults to per-handler in-memory.
|
|
54
54
|
*/
|
|
55
55
|
seenTxStore?: SeenTxStore;
|
|
56
|
+
/**
|
|
57
|
+
* Structured log sink for every adapter diagnostic (settlement errors,
|
|
58
|
+
* callback failures, orphaned sessions). Defaults to a console-backed logger.
|
|
59
|
+
*/
|
|
60
|
+
logger?: RouteDockLogger;
|
|
56
61
|
}
|
|
57
62
|
declare function routedock(opts: RouteDockMiddlewareOptions): RequestHandler;
|
|
58
63
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
|
-
import { P as PaymentMode,
|
|
3
|
-
import { O as OrphanedSessionInfo, S as SeenTxStore } from './MppSessionHandler-
|
|
2
|
+
import { P as PaymentMode, h as RouteDockManifest, g as RouteDockLogger } from './logger-D8_Q2ytp.cjs';
|
|
3
|
+
import { O as OrphanedSessionInfo, S as SeenTxStore } from './MppSessionHandler-1EL8QBAn.cjs';
|
|
4
4
|
|
|
5
5
|
interface RouteDockMiddlewareOptions {
|
|
6
6
|
modes: PaymentMode[];
|
|
@@ -12,9 +12,9 @@ interface RouteDockMiddlewareOptions {
|
|
|
12
12
|
channelFactory: string;
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
|
-
asset
|
|
15
|
+
asset?: string;
|
|
16
16
|
/** Stellar Asset Contract address for the payment asset */
|
|
17
|
-
assetContract
|
|
17
|
+
assetContract?: string;
|
|
18
18
|
payee: string;
|
|
19
19
|
network: 'testnet' | 'mainnet';
|
|
20
20
|
/** Private key (S...) of the server/payee account */
|
|
@@ -53,6 +53,11 @@ interface RouteDockMiddlewareOptions {
|
|
|
53
53
|
* duplicate settlement on agent retries. Defaults to per-handler in-memory.
|
|
54
54
|
*/
|
|
55
55
|
seenTxStore?: SeenTxStore;
|
|
56
|
+
/**
|
|
57
|
+
* Structured log sink for every adapter diagnostic (settlement errors,
|
|
58
|
+
* callback failures, orphaned sessions). Defaults to a console-backed logger.
|
|
59
|
+
*/
|
|
60
|
+
logger?: RouteDockLogger;
|
|
56
61
|
}
|
|
57
62
|
declare function routedock(opts: RouteDockMiddlewareOptions): RequestHandler;
|
|
58
63
|
|
package/dist/schema.cjs
CHANGED
|
@@ -81,6 +81,14 @@ var routedock_schema_default = {
|
|
|
81
81
|
type: "string",
|
|
82
82
|
description: "Stellar Asset Contract (SAC) address for the payment asset"
|
|
83
83
|
},
|
|
84
|
+
assets: {
|
|
85
|
+
type: "array",
|
|
86
|
+
minItems: 1,
|
|
87
|
+
items: {
|
|
88
|
+
$ref: "#/definitions/AssetConfig"
|
|
89
|
+
},
|
|
90
|
+
description: "Payment assets accepted by this provider. Each asset can be scoped to specific modes and endpoints. When present, assets[0] must match the root-level asset and asset_contract."
|
|
91
|
+
},
|
|
84
92
|
payee: {
|
|
85
93
|
type: "string",
|
|
86
94
|
description: "Stellar address (G...) that receives payments"
|
|
@@ -213,6 +221,38 @@ var routedock_schema_default = {
|
|
|
213
221
|
enum: ["x402", "mpp-charge", "mpp-session", "mpp-session-ws"],
|
|
214
222
|
description: "A supported RouteDock payment mode"
|
|
215
223
|
},
|
|
224
|
+
AssetConfig: {
|
|
225
|
+
type: "object",
|
|
226
|
+
description: "Payment asset configuration with optional mode and endpoint scoping",
|
|
227
|
+
required: ["asset", "asset_contract"],
|
|
228
|
+
additionalProperties: false,
|
|
229
|
+
properties: {
|
|
230
|
+
asset: {
|
|
231
|
+
type: "string",
|
|
232
|
+
description: "Asset ticker symbol (e.g. 'USDC' or 'XLM')"
|
|
233
|
+
},
|
|
234
|
+
asset_contract: {
|
|
235
|
+
type: "string",
|
|
236
|
+
description: "Stellar Asset Contract (SAC) address for the payment asset"
|
|
237
|
+
},
|
|
238
|
+
modes: {
|
|
239
|
+
type: "array",
|
|
240
|
+
items: {
|
|
241
|
+
$ref: "#/definitions/PaymentMode"
|
|
242
|
+
},
|
|
243
|
+
uniqueItems: true,
|
|
244
|
+
description: "Optional: restrict this asset to specific payment modes. If omitted, available for all modes."
|
|
245
|
+
},
|
|
246
|
+
endpoints: {
|
|
247
|
+
type: "array",
|
|
248
|
+
items: {
|
|
249
|
+
type: "string"
|
|
250
|
+
},
|
|
251
|
+
uniqueItems: true,
|
|
252
|
+
description: "Optional: restrict this asset to specific endpoints (by name). If omitted, available for all endpoints."
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
},
|
|
216
256
|
PricingConfig: {
|
|
217
257
|
type: "object",
|
|
218
258
|
description: "Per-request pricing for x402 or mpp-charge modes",
|
package/dist/schema.js
CHANGED
|
@@ -77,6 +77,14 @@ var routedock_schema_default = {
|
|
|
77
77
|
type: "string",
|
|
78
78
|
description: "Stellar Asset Contract (SAC) address for the payment asset"
|
|
79
79
|
},
|
|
80
|
+
assets: {
|
|
81
|
+
type: "array",
|
|
82
|
+
minItems: 1,
|
|
83
|
+
items: {
|
|
84
|
+
$ref: "#/definitions/AssetConfig"
|
|
85
|
+
},
|
|
86
|
+
description: "Payment assets accepted by this provider. Each asset can be scoped to specific modes and endpoints. When present, assets[0] must match the root-level asset and asset_contract."
|
|
87
|
+
},
|
|
80
88
|
payee: {
|
|
81
89
|
type: "string",
|
|
82
90
|
description: "Stellar address (G...) that receives payments"
|
|
@@ -209,6 +217,38 @@ var routedock_schema_default = {
|
|
|
209
217
|
enum: ["x402", "mpp-charge", "mpp-session", "mpp-session-ws"],
|
|
210
218
|
description: "A supported RouteDock payment mode"
|
|
211
219
|
},
|
|
220
|
+
AssetConfig: {
|
|
221
|
+
type: "object",
|
|
222
|
+
description: "Payment asset configuration with optional mode and endpoint scoping",
|
|
223
|
+
required: ["asset", "asset_contract"],
|
|
224
|
+
additionalProperties: false,
|
|
225
|
+
properties: {
|
|
226
|
+
asset: {
|
|
227
|
+
type: "string",
|
|
228
|
+
description: "Asset ticker symbol (e.g. 'USDC' or 'XLM')"
|
|
229
|
+
},
|
|
230
|
+
asset_contract: {
|
|
231
|
+
type: "string",
|
|
232
|
+
description: "Stellar Asset Contract (SAC) address for the payment asset"
|
|
233
|
+
},
|
|
234
|
+
modes: {
|
|
235
|
+
type: "array",
|
|
236
|
+
items: {
|
|
237
|
+
$ref: "#/definitions/PaymentMode"
|
|
238
|
+
},
|
|
239
|
+
uniqueItems: true,
|
|
240
|
+
description: "Optional: restrict this asset to specific payment modes. If omitted, available for all modes."
|
|
241
|
+
},
|
|
242
|
+
endpoints: {
|
|
243
|
+
type: "array",
|
|
244
|
+
items: {
|
|
245
|
+
type: "string"
|
|
246
|
+
},
|
|
247
|
+
uniqueItems: true,
|
|
248
|
+
description: "Optional: restrict this asset to specific endpoints (by name). If omitted, available for all endpoints."
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
},
|
|
212
252
|
PricingConfig: {
|
|
213
253
|
type: "object",
|
|
214
254
|
description: "Per-request pricing for x402 or mpp-charge modes",
|
package/dist/testing.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// src/testing/createMockRoutedockMiddleware.ts
|
|
4
4
|
var DEFAULT_TX_HASH = "0000000000000000000000000000000000000000000000000000000000000000";
|
|
5
5
|
var DEFAULT_CHANNEL_ID = "CCK4XOW3YKQUEZFONUTINKMSNW7SNMRQZURME5U3UP7E6WNGK7UHUCAH";
|
|
6
|
+
var DEFAULT_PAYER = "GAIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCF6M";
|
|
6
7
|
function format7(scaled) {
|
|
7
8
|
return (Number(scaled) / 1e7).toFixed(7);
|
|
8
9
|
}
|
|
@@ -16,11 +17,12 @@ async function runMockSettlement(opts) {
|
|
|
16
17
|
if ((opts.payment ?? "auto-pass") === "auto-fail") return null;
|
|
17
18
|
const s = opts.synthetic ?? {};
|
|
18
19
|
const txHash = s.txHash ?? DEFAULT_TX_HASH;
|
|
19
|
-
|
|
20
|
+
const payer = s.payer === void 0 ? DEFAULT_PAYER : s.payer;
|
|
21
|
+
if (mode === "mpp-session" || mode === "mpp-session-ws") {
|
|
20
22
|
const channelId = s.channelId ?? DEFAULT_CHANNEL_ID;
|
|
21
23
|
const rate = toScaled(s.rate ?? "0.0001");
|
|
22
24
|
const count = s.voucherCount ?? 3;
|
|
23
|
-
if (opts.onSessionOpen) await opts.onSessionOpen(channelId);
|
|
25
|
+
if (opts.onSessionOpen) await opts.onSessionOpen(channelId, payer);
|
|
24
26
|
const vouchers = [];
|
|
25
27
|
for (let i = 1; i <= count; i++) {
|
|
26
28
|
const cumulativeAmount = format7(rate * BigInt(i));
|
|
@@ -28,11 +30,11 @@ async function runMockSettlement(opts) {
|
|
|
28
30
|
if (opts.onVoucher) await opts.onVoucher(channelId, i, cumulativeAmount, "0000000000000000000000000000000000000000000000000000000000000000");
|
|
29
31
|
}
|
|
30
32
|
const totalPaid = format7(rate * BigInt(count));
|
|
31
|
-
if (opts.onSettled) await opts.onSettled(txHash, totalPaid,
|
|
33
|
+
if (opts.onSettled) await opts.onSettled(txHash, totalPaid, mode, payer);
|
|
32
34
|
return { mode, txHash, amount: totalPaid, channelId, vouchers };
|
|
33
35
|
}
|
|
34
36
|
const amount = s.amount ?? "0.001";
|
|
35
|
-
if (opts.onSettled) await opts.onSettled(txHash, amount, mode);
|
|
37
|
+
if (opts.onSettled) await opts.onSettled(txHash, amount, mode, payer);
|
|
36
38
|
return { mode, txHash, amount };
|
|
37
39
|
}
|
|
38
40
|
function createMockRoutedockMiddleware(opts = {}) {
|
package/dist/testing.d.cts
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
|
-
import { P as PaymentMode } from './
|
|
2
|
+
import { P as PaymentMode } from './logger-D8_Q2ytp.cjs';
|
|
3
|
+
import { R as RouteDockMiddlewareOptions } from './routedockMiddleware-DlyLrxp7.cjs';
|
|
3
4
|
import 'mppx';
|
|
5
|
+
import './MppSessionHandler-1EL8QBAn.cjs';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
8
|
+
* Loosen a production callback's return type so a plain sync test spy works,
|
|
9
|
+
* while keeping its exact parameter list (the real adapter's signature).
|
|
10
|
+
*/
|
|
11
|
+
type TestCallback<F> = F extends (...args: infer A) => unknown ? (...args: A) => void | Promise<void> : never;
|
|
12
|
+
/**
|
|
13
|
+
* Provider settlement callbacks under test. Same parameter list as the real
|
|
14
|
+
* `RouteDockMiddlewareOptions` callbacks — including `payer` — but they accept
|
|
15
|
+
* sync or async fns so a plain test spy works without wrapping it in a Promise.
|
|
9
16
|
*/
|
|
10
17
|
interface MockRoutedockCallbacks {
|
|
11
18
|
/** Called after each (synthetic) on-chain settlement. */
|
|
12
|
-
onSettled?:
|
|
13
|
-
/** Called once when a synthetic
|
|
14
|
-
onSessionOpen?:
|
|
15
|
-
/** Called for each synthetic voucher in
|
|
16
|
-
onVoucher?:
|
|
19
|
+
onSettled?: TestCallback<NonNullable<RouteDockMiddlewareOptions['onSettled']>>;
|
|
20
|
+
/** Called once when a synthetic session is opened (first voucher). */
|
|
21
|
+
onSessionOpen?: TestCallback<NonNullable<RouteDockMiddlewareOptions['onSessionOpen']>>;
|
|
22
|
+
/** Called for each synthetic voucher in a session (1-based index). */
|
|
23
|
+
onVoucher?: TestCallback<NonNullable<RouteDockMiddlewareOptions['onVoucher']>>;
|
|
17
24
|
}
|
|
18
25
|
/** Synthetic settlement values handed to the callbacks. All optional — sensible defaults per mode. */
|
|
19
26
|
interface SyntheticPayment {
|
|
@@ -21,12 +28,19 @@ interface SyntheticPayment {
|
|
|
21
28
|
txHash?: string;
|
|
22
29
|
/** Settled amount (x402 / mpp-charge) passed to onSettled. Default: '0.001'. */
|
|
23
30
|
amount?: string;
|
|
24
|
-
/** Channel address (
|
|
31
|
+
/** Channel address (session modes) passed to onSessionOpen. Default: a fixed C... address. */
|
|
25
32
|
channelId?: string;
|
|
26
|
-
/** Per-voucher rate (
|
|
33
|
+
/** Per-voucher rate (session modes), in decimal string. Default: '0.0001'. */
|
|
27
34
|
rate?: string;
|
|
28
|
-
/** Number of vouchers to emit before close (
|
|
35
|
+
/** Number of vouchers to emit before close (session modes). Default: 3. */
|
|
29
36
|
voucherCount?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Payer passed to onSettled (4th arg) and onSessionOpen (2nd arg). Default: a
|
|
39
|
+
* valid Stellar G... account. Pass `null` to exercise the address-unavailable
|
|
40
|
+
* path; `null` is passed through untouched (an explicit null is not replaced
|
|
41
|
+
* by the default).
|
|
42
|
+
*/
|
|
43
|
+
payer?: string | null;
|
|
30
44
|
}
|
|
31
45
|
interface MockRoutedockOptions extends MockRoutedockCallbacks {
|
|
32
46
|
/** Payment mode the synthetic payment uses. Default: 'x402'. */
|
|
@@ -87,7 +101,12 @@ declare function runMockSettlement(opts: MockRoutedockOptions): Promise<MockSett
|
|
|
87
101
|
* app.get('/price', (_req, res) => res.json({ price: '42' }))
|
|
88
102
|
*
|
|
89
103
|
* await request(app).get('/price').expect(200)
|
|
90
|
-
* expect(onSettled).toHaveBeenCalledWith(
|
|
104
|
+
* expect(onSettled).toHaveBeenCalledWith(
|
|
105
|
+
* expect.any(String),
|
|
106
|
+
* '0.001',
|
|
107
|
+
* 'x402',
|
|
108
|
+
* expect.any(String), // payer
|
|
109
|
+
* )
|
|
91
110
|
* ```
|
|
92
111
|
*/
|
|
93
112
|
declare function createMockRoutedockMiddleware(opts?: MockRoutedockOptions): RequestHandler;
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
|
-
import { P as PaymentMode } from './
|
|
2
|
+
import { P as PaymentMode } from './logger-D8_Q2ytp.js';
|
|
3
|
+
import { R as RouteDockMiddlewareOptions } from './routedockMiddleware-57gUaEMf.js';
|
|
3
4
|
import 'mppx';
|
|
5
|
+
import './MppSessionHandler-Bq4S-JTE.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
8
|
+
* Loosen a production callback's return type so a plain sync test spy works,
|
|
9
|
+
* while keeping its exact parameter list (the real adapter's signature).
|
|
10
|
+
*/
|
|
11
|
+
type TestCallback<F> = F extends (...args: infer A) => unknown ? (...args: A) => void | Promise<void> : never;
|
|
12
|
+
/**
|
|
13
|
+
* Provider settlement callbacks under test. Same parameter list as the real
|
|
14
|
+
* `RouteDockMiddlewareOptions` callbacks — including `payer` — but they accept
|
|
15
|
+
* sync or async fns so a plain test spy works without wrapping it in a Promise.
|
|
9
16
|
*/
|
|
10
17
|
interface MockRoutedockCallbacks {
|
|
11
18
|
/** Called after each (synthetic) on-chain settlement. */
|
|
12
|
-
onSettled?:
|
|
13
|
-
/** Called once when a synthetic
|
|
14
|
-
onSessionOpen?:
|
|
15
|
-
/** Called for each synthetic voucher in
|
|
16
|
-
onVoucher?:
|
|
19
|
+
onSettled?: TestCallback<NonNullable<RouteDockMiddlewareOptions['onSettled']>>;
|
|
20
|
+
/** Called once when a synthetic session is opened (first voucher). */
|
|
21
|
+
onSessionOpen?: TestCallback<NonNullable<RouteDockMiddlewareOptions['onSessionOpen']>>;
|
|
22
|
+
/** Called for each synthetic voucher in a session (1-based index). */
|
|
23
|
+
onVoucher?: TestCallback<NonNullable<RouteDockMiddlewareOptions['onVoucher']>>;
|
|
17
24
|
}
|
|
18
25
|
/** Synthetic settlement values handed to the callbacks. All optional — sensible defaults per mode. */
|
|
19
26
|
interface SyntheticPayment {
|
|
@@ -21,12 +28,19 @@ interface SyntheticPayment {
|
|
|
21
28
|
txHash?: string;
|
|
22
29
|
/** Settled amount (x402 / mpp-charge) passed to onSettled. Default: '0.001'. */
|
|
23
30
|
amount?: string;
|
|
24
|
-
/** Channel address (
|
|
31
|
+
/** Channel address (session modes) passed to onSessionOpen. Default: a fixed C... address. */
|
|
25
32
|
channelId?: string;
|
|
26
|
-
/** Per-voucher rate (
|
|
33
|
+
/** Per-voucher rate (session modes), in decimal string. Default: '0.0001'. */
|
|
27
34
|
rate?: string;
|
|
28
|
-
/** Number of vouchers to emit before close (
|
|
35
|
+
/** Number of vouchers to emit before close (session modes). Default: 3. */
|
|
29
36
|
voucherCount?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Payer passed to onSettled (4th arg) and onSessionOpen (2nd arg). Default: a
|
|
39
|
+
* valid Stellar G... account. Pass `null` to exercise the address-unavailable
|
|
40
|
+
* path; `null` is passed through untouched (an explicit null is not replaced
|
|
41
|
+
* by the default).
|
|
42
|
+
*/
|
|
43
|
+
payer?: string | null;
|
|
30
44
|
}
|
|
31
45
|
interface MockRoutedockOptions extends MockRoutedockCallbacks {
|
|
32
46
|
/** Payment mode the synthetic payment uses. Default: 'x402'. */
|
|
@@ -87,7 +101,12 @@ declare function runMockSettlement(opts: MockRoutedockOptions): Promise<MockSett
|
|
|
87
101
|
* app.get('/price', (_req, res) => res.json({ price: '42' }))
|
|
88
102
|
*
|
|
89
103
|
* await request(app).get('/price').expect(200)
|
|
90
|
-
* expect(onSettled).toHaveBeenCalledWith(
|
|
104
|
+
* expect(onSettled).toHaveBeenCalledWith(
|
|
105
|
+
* expect.any(String),
|
|
106
|
+
* '0.001',
|
|
107
|
+
* 'x402',
|
|
108
|
+
* expect.any(String), // payer
|
|
109
|
+
* )
|
|
91
110
|
* ```
|
|
92
111
|
*/
|
|
93
112
|
declare function createMockRoutedockMiddleware(opts?: MockRoutedockOptions): RequestHandler;
|
package/dist/testing.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/testing/createMockRoutedockMiddleware.ts
|
|
2
2
|
var DEFAULT_TX_HASH = "0000000000000000000000000000000000000000000000000000000000000000";
|
|
3
3
|
var DEFAULT_CHANNEL_ID = "CCK4XOW3YKQUEZFONUTINKMSNW7SNMRQZURME5U3UP7E6WNGK7UHUCAH";
|
|
4
|
+
var DEFAULT_PAYER = "GAIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCEIRCF6M";
|
|
4
5
|
function format7(scaled) {
|
|
5
6
|
return (Number(scaled) / 1e7).toFixed(7);
|
|
6
7
|
}
|
|
@@ -14,11 +15,12 @@ async function runMockSettlement(opts) {
|
|
|
14
15
|
if ((opts.payment ?? "auto-pass") === "auto-fail") return null;
|
|
15
16
|
const s = opts.synthetic ?? {};
|
|
16
17
|
const txHash = s.txHash ?? DEFAULT_TX_HASH;
|
|
17
|
-
|
|
18
|
+
const payer = s.payer === void 0 ? DEFAULT_PAYER : s.payer;
|
|
19
|
+
if (mode === "mpp-session" || mode === "mpp-session-ws") {
|
|
18
20
|
const channelId = s.channelId ?? DEFAULT_CHANNEL_ID;
|
|
19
21
|
const rate = toScaled(s.rate ?? "0.0001");
|
|
20
22
|
const count = s.voucherCount ?? 3;
|
|
21
|
-
if (opts.onSessionOpen) await opts.onSessionOpen(channelId);
|
|
23
|
+
if (opts.onSessionOpen) await opts.onSessionOpen(channelId, payer);
|
|
22
24
|
const vouchers = [];
|
|
23
25
|
for (let i = 1; i <= count; i++) {
|
|
24
26
|
const cumulativeAmount = format7(rate * BigInt(i));
|
|
@@ -26,11 +28,11 @@ async function runMockSettlement(opts) {
|
|
|
26
28
|
if (opts.onVoucher) await opts.onVoucher(channelId, i, cumulativeAmount, "0000000000000000000000000000000000000000000000000000000000000000");
|
|
27
29
|
}
|
|
28
30
|
const totalPaid = format7(rate * BigInt(count));
|
|
29
|
-
if (opts.onSettled) await opts.onSettled(txHash, totalPaid,
|
|
31
|
+
if (opts.onSettled) await opts.onSettled(txHash, totalPaid, mode, payer);
|
|
30
32
|
return { mode, txHash, amount: totalPaid, channelId, vouchers };
|
|
31
33
|
}
|
|
32
34
|
const amount = s.amount ?? "0.001";
|
|
33
|
-
if (opts.onSettled) await opts.onSettled(txHash, amount, mode);
|
|
35
|
+
if (opts.onSettled) await opts.onSettled(txHash, amount, mode, payer);
|
|
34
36
|
return { mode, txHash, amount };
|
|
35
37
|
}
|
|
36
38
|
function createMockRoutedockMiddleware(opts = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@routedock/routedock",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Unified payment execution layer for autonomous agents on Stellar",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"@x402/core": "^2.9.0",
|
|
132
132
|
"@x402/stellar": "^2.9.0",
|
|
133
133
|
"mppx": "^0.5.7",
|
|
134
|
-
"@routedock/nulth-sdk": "0.2.
|
|
134
|
+
"@routedock/nulth-sdk": "0.2.1"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
137
|
"express": "^4.18.0",
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { RequestHandler } from 'express';
|
|
2
|
-
import { Store } from 'mppx';
|
|
3
|
-
import { R as RouteDockManifest } from './types-DmhmfLzP.cjs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Idempotency store for payment settlement.
|
|
7
|
-
*
|
|
8
|
-
* `x402Handler` and `MppChargeHandler` settle on every request carrying a
|
|
9
|
-
* payment header. An agent that retries after a post-settlement network
|
|
10
|
-
* timeout resends the *same* signed payment, which would settle a second time
|
|
11
|
-
* and invoke `onSettled` twice — double-counting in billing.
|
|
12
|
-
*
|
|
13
|
-
* Before settling, a handler derives an idempotency key from the inbound
|
|
14
|
-
* payment header(s) and checks this store. On a hit it replays the cached
|
|
15
|
-
* settlement response and skips both the on-chain settle and `onSettled`.
|
|
16
|
-
*
|
|
17
|
-
* The default {@link InMemorySeenTxStore} is per-handler and per-process. For
|
|
18
|
-
* multi-instance deployments, supply a shared implementation backed by Redis,
|
|
19
|
-
* Supabase, etc.
|
|
20
|
-
*/
|
|
21
|
-
/** Cached outcome of a settlement, replayed on a duplicate payment. */
|
|
22
|
-
interface SettlementRecord {
|
|
23
|
-
/** On-chain transaction hash (or settlement reference), if known. */
|
|
24
|
-
txHash: string | null;
|
|
25
|
-
/** Response headers to re-apply on a replay (e.g. `X-Payment-Response`). */
|
|
26
|
-
headers?: Record<string, string>;
|
|
27
|
-
}
|
|
28
|
-
interface SeenTxStore {
|
|
29
|
-
/** Returns the cached settlement for a key, or `undefined` if unseen. */
|
|
30
|
-
get(key: string): Promise<SettlementRecord | undefined> | SettlementRecord | undefined;
|
|
31
|
-
/** Records the settlement outcome for a key. */
|
|
32
|
-
set(key: string, record: SettlementRecord): Promise<void> | void;
|
|
33
|
-
}
|
|
34
|
-
interface InMemorySeenTxStoreOptions {
|
|
35
|
-
/** Maximum number of entries before FIFO eviction. Defaults to 10,000. */
|
|
36
|
-
maxEntries?: number;
|
|
37
|
-
/** Log a startup warning about non-durability. Defaults to true. */
|
|
38
|
-
warn?: boolean;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Default in-memory {@link SeenTxStore}. Bounded by `maxEntries` with FIFO
|
|
42
|
-
* eviction so a long-running process cannot grow without limit.
|
|
43
|
-
*
|
|
44
|
-
* **Not durable.** On serverless/edge runtimes each request may land on a
|
|
45
|
-
* fresh isolate with an empty cache, which causes duplicate settlements.
|
|
46
|
-
* Supply a persistent implementation (Supabase, Redis, …) in production.
|
|
47
|
-
*/
|
|
48
|
-
declare class InMemorySeenTxStore implements SeenTxStore {
|
|
49
|
-
private readonly map;
|
|
50
|
-
private readonly order;
|
|
51
|
-
constructor(maxEntriesOrOptions?: number | InMemorySeenTxStoreOptions);
|
|
52
|
-
private readonly maxEntries;
|
|
53
|
-
get(key: string): SettlementRecord | undefined;
|
|
54
|
-
set(key: string, record: SettlementRecord): void;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Derive a collision-resistant idempotency key from the inbound
|
|
58
|
-
* payment-bearing headers. Uses SHA-256 instead of 32-bit FNV-1a
|
|
59
|
-
* (which has a 2^32 keyspace — birthday collisions become likely
|
|
60
|
-
* well before the 10_000-entry default store is full).
|
|
61
|
-
*
|
|
62
|
-
* x402 clients send the signed payment in `payment-signature` / `x-payment`;
|
|
63
|
-
* mppx clients send it in `authorization` (the `Payment` scheme). A retry
|
|
64
|
-
* resends byte-identical headers, so hashing the first present one yields a
|
|
65
|
-
* stable key. Returns `null` when no payment header is present (nothing to
|
|
66
|
-
* dedupe — e.g. the initial 402 challenge request).
|
|
67
|
-
*/
|
|
68
|
-
declare function paymentIdempotencyKey(getHeader: (name: string) => string | undefined): Promise<string | null>;
|
|
69
|
-
|
|
70
|
-
/** Store shape extended with optional atomic update operation. */
|
|
71
|
-
type ChannelStore = Store.Store & {
|
|
72
|
-
update?: (key: string, fn: (prev: unknown) => unknown) => Promise<unknown>;
|
|
73
|
-
};
|
|
74
|
-
/** Expected payload shape for voucher cumulative amount entries. */
|
|
75
|
-
interface VoucherStoreValue {
|
|
76
|
-
amount: string;
|
|
77
|
-
[key: string]: unknown;
|
|
78
|
-
}
|
|
79
|
-
/** Validates that a stored store value is an object containing a numeric string amount. */
|
|
80
|
-
declare function isVoucherStoreValue(value: unknown): value is VoucherStoreValue;
|
|
81
|
-
type Network = 'testnet' | 'mainnet';
|
|
82
|
-
/** Why a live session was flagged as orphaned (never cleanly closed). */
|
|
83
|
-
type OrphanReason = 'connection-closed' | 'idle-timeout';
|
|
84
|
-
/** Latest signed state of an orphaned session, enough for the reconciler to settle. */
|
|
85
|
-
interface OrphanedSessionInfo {
|
|
86
|
-
/** Cumulative amount of the highest voucher seen (human-readable, 7 dp). */
|
|
87
|
-
cumulativeAmount: string;
|
|
88
|
-
/** Hex-encoded signature of the highest voucher seen. */
|
|
89
|
-
lastSignature: string;
|
|
90
|
-
/** Number of vouchers received before teardown. */
|
|
91
|
-
voucherCount: number;
|
|
92
|
-
/** What triggered the orphan flag. */
|
|
93
|
-
reason: OrphanReason;
|
|
94
|
-
}
|
|
95
|
-
interface MppSessionHandlerOptions {
|
|
96
|
-
payeeSecretKey: string;
|
|
97
|
-
network: Network;
|
|
98
|
-
channelFactory: string;
|
|
99
|
-
rate: string;
|
|
100
|
-
assetContract: string;
|
|
101
|
-
manifest: RouteDockManifest;
|
|
102
|
-
commitmentPublicKey: string;
|
|
103
|
-
onSettled?: (txHash: string, totalPaid: string, mode: string, payer: string | null) => Promise<void>;
|
|
104
|
-
onSessionOpen?: (channelId: string, payer: string | null) => Promise<void>;
|
|
105
|
-
onVoucher?: (channelId: string, voucherIndex: number, cumulativeAmount: string, signature: string) => Promise<void>;
|
|
106
|
-
onCallbackError?: (err: unknown, cb: string) => void;
|
|
107
|
-
/**
|
|
108
|
-
* Called when the client connection drops mid-session or the session goes
|
|
109
|
-
* idle, before a clean close. Persist the session as `closing` so the
|
|
110
|
-
* SessionReconciler can settle it with the latest signed voucher.
|
|
111
|
-
*/
|
|
112
|
-
onOrphaned?: (channelId: string, info: OrphanedSessionInfo) => Promise<void>;
|
|
113
|
-
/**
|
|
114
|
-
* Flag the session orphaned after this many milliseconds with no voucher
|
|
115
|
-
* activity. Disabled when unset.
|
|
116
|
-
*/
|
|
117
|
-
idleTimeoutMs?: number;
|
|
118
|
-
}
|
|
119
|
-
declare function createMppSessionHandler(opts: MppSessionHandlerOptions): RequestHandler;
|
|
120
|
-
|
|
121
|
-
export { type ChannelStore as C, InMemorySeenTxStore as I, type MppSessionHandlerOptions as M, type OrphanedSessionInfo as O, type SeenTxStore as S, type VoucherStoreValue as V, type SettlementRecord as a, type InMemorySeenTxStoreOptions as b, type OrphanReason as c, createMppSessionHandler as d, isVoucherStoreValue as i, paymentIdempotencyKey as p };
|