mppx 0.5.1 → 0.5.4
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/CHANGELOG.md +20 -0
- package/dist/Credential.d.ts +12 -0
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Credential.js +22 -4
- package/dist/Credential.js.map +1 -1
- package/dist/Method.d.ts +4 -0
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +2 -1
- package/dist/Method.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +11 -9
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/plugins/tempo.d.ts.map +1 -1
- package/dist/cli/plugins/tempo.js +3 -3
- package/dist/cli/plugins/tempo.js.map +1 -1
- package/dist/cli/utils.d.ts +2 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +10 -5
- package/dist/cli/utils.js.map +1 -1
- package/dist/proxy/Proxy.d.ts.map +1 -1
- package/dist/proxy/Proxy.js +52 -8
- package/dist/proxy/Proxy.js.map +1 -1
- package/dist/proxy/internal/Route.d.ts.map +1 -1
- package/dist/proxy/internal/Route.js +7 -3
- package/dist/proxy/internal/Route.js.map +1 -1
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +90 -71
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Transport.d.ts +5 -1
- package/dist/server/Transport.d.ts.map +1 -1
- package/dist/server/Transport.js +71 -7
- package/dist/server/Transport.js.map +1 -1
- package/dist/server/internal/html/config.d.ts +144 -0
- package/dist/server/internal/html/config.d.ts.map +1 -0
- package/dist/server/internal/html/config.js +303 -0
- package/dist/server/internal/html/config.js.map +1 -0
- package/dist/server/internal/html/serviceWorker.gen.d.ts +2 -0
- package/dist/server/internal/html/serviceWorker.gen.d.ts.map +1 -0
- package/dist/server/internal/html/serviceWorker.gen.js +3 -0
- package/dist/server/internal/html/serviceWorker.gen.js.map +1 -0
- package/dist/stripe/internal/types.d.ts +6 -0
- package/dist/stripe/internal/types.d.ts.map +1 -1
- package/dist/stripe/server/Charge.d.ts +30 -16
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +35 -6
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/internal/html/types.d.ts +2 -0
- package/dist/stripe/server/internal/html/types.d.ts.map +1 -0
- package/dist/stripe/server/internal/html/types.js +2 -0
- package/dist/stripe/server/internal/html/types.js.map +1 -0
- package/dist/stripe/server/internal/html.gen.d.ts +2 -0
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -0
- package/dist/stripe/server/internal/html.gen.js +3 -0
- package/dist/stripe/server/internal/html.gen.js.map +1 -0
- package/dist/tempo/server/Charge.d.ts +33 -26
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +46 -11
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js +3 -2
- package/dist/tempo/server/Session.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +2 -0
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -0
- package/dist/tempo/server/internal/html.gen.js +3 -0
- package/dist/tempo/server/internal/html.gen.js.map +1 -0
- package/dist/tempo/server/internal/transport.d.ts +1 -1
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +45 -58
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/package.json +2 -2
- package/src/Credential.ts +28 -4
- package/src/Method.ts +6 -1
- package/src/cli/cli.ts +11 -8
- package/src/cli/plugins/tempo.ts +3 -2
- package/src/cli/utils.test.ts +64 -0
- package/src/cli/utils.ts +10 -4
- package/src/env.d.ts +1 -0
- package/src/mcp-sdk/server/Transport.test.ts +6 -0
- package/src/proxy/Proxy.test.ts +188 -1
- package/src/proxy/Proxy.ts +58 -9
- package/src/proxy/internal/Route.test.ts +9 -0
- package/src/proxy/internal/Route.ts +5 -2
- package/src/server/Mppx.test.ts +171 -18
- package/src/server/Mppx.ts +120 -79
- package/src/server/Transport.test.ts +232 -2
- package/src/server/Transport.ts +84 -7
- package/src/server/internal/html/config.ts +414 -0
- package/src/server/internal/html/serviceWorker.client.ts +28 -0
- package/src/server/internal/html/serviceWorker.gen.ts +2 -0
- package/src/server/internal/html/serviceWorker.ts +27 -0
- package/src/server/internal/html/tsconfig.worker.client.json +8 -0
- package/src/server/internal/html/tsconfig.worker.json +8 -0
- package/src/stripe/internal/types.ts +20 -0
- package/src/stripe/server/Charge.ts +62 -6
- package/src/stripe/server/internal/html/main.ts +174 -0
- package/src/stripe/server/internal/html/node_modules/.bin/mppx.src +21 -0
- package/src/stripe/server/internal/html/package.json +9 -0
- package/src/stripe/server/internal/html/stripe-js-pure.d.ts +7 -0
- package/src/stripe/server/internal/html/tsconfig.json +8 -0
- package/src/stripe/server/internal/html/types.ts +5 -0
- package/src/stripe/server/internal/html.gen.ts +2 -0
- package/src/tempo/server/Charge.ts +64 -10
- package/src/tempo/server/Session.ts +3 -2
- package/src/tempo/server/internal/html/main.ts +111 -0
- package/src/tempo/server/internal/html/node_modules/.bin/mppx.src +21 -0
- package/src/tempo/server/internal/html/package.json +10 -0
- package/src/tempo/server/internal/html/tsconfig.json +8 -0
- package/src/tempo/server/internal/html.gen.ts +2 -0
- package/src/tempo/server/internal/transport.test.ts +37 -31
- package/src/tempo/server/internal/transport.ts +44 -58
- package/src/tsconfig.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.gen.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/html.gen.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,IAAI,GAAG,2r9aAA2r9a,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../src/tempo/server/internal/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,SAAS,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../src/tempo/server/internal/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,SAAS,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAA;AAGhD,mDAAmD;AACnD,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAA;AAE3D;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG;IAAE,KAAK,EAAE,YAAY,CAAC,YAAY,CAAA;CAAE,GAAG,GAAG,CAsGpF;AAED,MAAM,CAAC,OAAO,WAAW,GAAG,CAAC;IAC3B,KAAK,OAAO,GAAG;QACb;;;;;;;;;WASG;QACH,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;QAC1B,sDAAsD;QACtD,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KACrC,CAAA;CACF;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACpC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IAC7E,WAAW,EAAE,MAAM,CAAA;CACpB,GAAG,QAAQ,CAwBX"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tempo-specific SSE transport that wraps the base HTTP transport
|
|
3
|
-
* with metering logic (context capture from credentials, per-token
|
|
3
|
+
* with metering logic (context capture from verified credentials, per-token
|
|
4
4
|
* charging via Sse.serve).
|
|
5
5
|
*
|
|
6
6
|
* @internal
|
|
@@ -28,27 +28,21 @@ export function sse(options) {
|
|
|
28
28
|
const { waitForUpdate: _, ...store } = options.store;
|
|
29
29
|
return store;
|
|
30
30
|
})();
|
|
31
|
-
const contextMap = new Map();
|
|
32
31
|
const base = Transport.http();
|
|
33
32
|
return Transport.from({
|
|
34
33
|
name: 'sse',
|
|
35
34
|
getCredential(request) {
|
|
36
|
-
|
|
37
|
-
if (credential) {
|
|
38
|
-
try {
|
|
39
|
-
const ctx = Sse_core.fromRequest(request);
|
|
40
|
-
contextMap.set(ctx.challengeId, { ...ctx, signal: request.signal });
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
// ignore — non-SSE credentials won't have session context
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return credential;
|
|
35
|
+
return base.getCredential(request);
|
|
47
36
|
},
|
|
48
37
|
respondChallenge(options) {
|
|
49
38
|
return base.respondChallenge(options);
|
|
50
39
|
},
|
|
51
|
-
respondReceipt({ receipt, response, challengeId }) {
|
|
40
|
+
respondReceipt({ credential, receipt, response, challengeId, input }) {
|
|
41
|
+
const payload = credential.payload;
|
|
42
|
+
if (!payload.channelId)
|
|
43
|
+
throw new Error('No SSE context available');
|
|
44
|
+
const channelId = payload.channelId;
|
|
45
|
+
const tickCost = BigInt(credential.challenge.request.amount);
|
|
52
46
|
// Auto-detect upstream SSE responses and parse them into an
|
|
53
47
|
// AsyncIterable so they flow through the metered pipeline.
|
|
54
48
|
// This lets proxy consumers simply pass `result.withReceipt(upstreamRes)`
|
|
@@ -57,10 +51,6 @@ export function sse(options) {
|
|
|
57
51
|
? Sse_core.iterateData(response, { skip: (d) => d === '[DONE]' })
|
|
58
52
|
: response;
|
|
59
53
|
if (isAsyncGeneratorFunction(resolved) || isAsyncIterable(resolved)) {
|
|
60
|
-
const ctx = contextMap.get(challengeId);
|
|
61
|
-
if (!ctx)
|
|
62
|
-
throw new Error('No SSE context available — credential was not parsed');
|
|
63
|
-
contextMap.delete(challengeId);
|
|
64
54
|
// Pass async generator functions directly so Sse.serve gives them
|
|
65
55
|
// a SessionController for manual charge(). Pass raw AsyncIterables
|
|
66
56
|
// as-is so Sse.serve auto-charges per yielded value.
|
|
@@ -69,60 +59,57 @@ export function sse(options) {
|
|
|
69
59
|
: resolved;
|
|
70
60
|
const stream = Sse_core.serve({
|
|
71
61
|
store,
|
|
72
|
-
channelId
|
|
62
|
+
channelId,
|
|
73
63
|
challengeId,
|
|
74
|
-
tickCost
|
|
64
|
+
tickCost,
|
|
75
65
|
pollIntervalMs: pollingInterval,
|
|
76
66
|
generate,
|
|
77
|
-
signal:
|
|
67
|
+
signal: input.signal,
|
|
78
68
|
});
|
|
79
69
|
return Sse_core.toResponse(stream);
|
|
80
70
|
}
|
|
81
71
|
const baseResponse = base.respondReceipt({
|
|
72
|
+
credential,
|
|
73
|
+
input,
|
|
82
74
|
receipt,
|
|
83
75
|
response: response,
|
|
84
76
|
challengeId,
|
|
85
77
|
});
|
|
86
78
|
// Non-SSE response (e.g. upstream returned JSON instead of event-stream).
|
|
87
79
|
// Need to deduct tickCost so request isn't free.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// response body per Fetch/HTTP semantics.
|
|
93
|
-
if (isNullBodyStatus(baseResponse.status)) {
|
|
94
|
-
return baseResponse;
|
|
95
|
-
}
|
|
96
|
-
const stream = new ReadableStream({
|
|
97
|
-
async start(controller) {
|
|
98
|
-
// deduction completes before consumer reads
|
|
99
|
-
await ChannelStore.deductFromChannel(store, ctx.channelId, ctx.tickCost);
|
|
100
|
-
if (!baseResponse.body) {
|
|
101
|
-
controller.close();
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const reader = baseResponse.body.getReader();
|
|
105
|
-
try {
|
|
106
|
-
while (true) {
|
|
107
|
-
const { done, value } = await reader.read();
|
|
108
|
-
if (done)
|
|
109
|
-
break;
|
|
110
|
-
controller.enqueue(value);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
finally {
|
|
114
|
-
reader.releaseLock();
|
|
115
|
-
controller.close();
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
return new Response(stream, {
|
|
120
|
-
status: baseResponse.status,
|
|
121
|
-
statusText: baseResponse.statusText,
|
|
122
|
-
headers: baseResponse.headers,
|
|
123
|
-
});
|
|
80
|
+
// Null-body statuses (e.g. 204 from management actions) cannot carry a
|
|
81
|
+
// response body per Fetch/HTTP semantics.
|
|
82
|
+
if (isNullBodyStatus(baseResponse.status)) {
|
|
83
|
+
return baseResponse;
|
|
124
84
|
}
|
|
125
|
-
|
|
85
|
+
const stream = new ReadableStream({
|
|
86
|
+
async start(controller) {
|
|
87
|
+
// deduction completes before consumer reads
|
|
88
|
+
await ChannelStore.deductFromChannel(store, channelId, tickCost);
|
|
89
|
+
if (!baseResponse.body) {
|
|
90
|
+
controller.close();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const reader = baseResponse.body.getReader();
|
|
94
|
+
try {
|
|
95
|
+
while (true) {
|
|
96
|
+
const { done, value } = await reader.read();
|
|
97
|
+
if (done)
|
|
98
|
+
break;
|
|
99
|
+
controller.enqueue(value);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
reader.releaseLock();
|
|
104
|
+
controller.close();
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
return new Response(stream, {
|
|
109
|
+
status: baseResponse.status,
|
|
110
|
+
statusText: baseResponse.statusText,
|
|
111
|
+
headers: baseResponse.headers,
|
|
112
|
+
});
|
|
126
113
|
},
|
|
127
114
|
});
|
|
128
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,SAAS,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,SAAS,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAA;AAMhD;;;;;;;;GAQG;AACH,MAAM,UAAU,GAAG,CAAC,OAA2D;IAC7E,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IAEzC,oEAAoE;IACpE,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE;QAClB,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAC,KAAK,CAAA;QAC/B,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpD,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,EAAE,CAAA;IAEJ,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,CAAA;IAC7B,OAAO,SAAS,CAAC,IAAI,CAAgE;QACnF,IAAI,EAAE,KAAK;QAEX,aAAa,CAAC,OAAO;YACnB,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QACpC,CAAC;QAED,gBAAgB,CAAC,OAAO;YACtB,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAa,CAAA;QACnD,CAAC;QAED,cAAc,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE;YAClE,MAAM,OAAO,GAAG,UAAU,CAAC,OAA4C,CAAA;YACvE,IAAI,CAAC,OAAO,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;YACnE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAA;YACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,MAAgB,CAAC,CAAA;YAEtE,4DAA4D;YAC5D,2DAA2D;YAC3D,0EAA0E;YAC1E,4CAA4C;YAC5C,MAAM,QAAQ,GACZ,QAAQ,YAAY,QAAQ,IAAI,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,IAAI;gBAC/E,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACjE,CAAC,CAAC,QAAQ,CAAA;YAEd,IAAI,wBAAwB,CAAC,QAAQ,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpE,kEAAkE;gBAClE,mEAAmE;gBACnE,qDAAqD;gBACrD,MAAM,QAAQ,GAAuC,wBAAwB,CAAC,QAAQ,CAAC;oBACrF,CAAC,CAAE,QAA+C;oBAClD,CAAC,CAAE,QAAkC,CAAA;gBACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC;oBAC5B,KAAK;oBACL,SAAS;oBACT,WAAW;oBACX,QAAQ;oBACR,cAAc,EAAE,eAAe;oBAC/B,QAAQ;oBACR,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAA;gBACF,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YACpC,CAAC;YAED,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC;gBACvC,UAAU;gBACV,KAAK;gBACL,OAAO;gBACP,QAAQ,EAAE,QAAoB;gBAC9B,WAAW;aACZ,CAAC,CAAA;YAEF,0EAA0E;YAC1E,iDAAiD;YACjD,uEAAuE;YACvE,0CAA0C;YAC1C,IAAI,gBAAgB,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1C,OAAO,YAAY,CAAA;YACrB,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;gBAC5C,KAAK,CAAC,KAAK,CAAC,UAAU;oBACpB,4CAA4C;oBAC5C,MAAM,YAAY,CAAC,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;oBAChE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;wBACvB,UAAU,CAAC,KAAK,EAAE,CAAA;wBAClB,OAAM;oBACR,CAAC;oBACD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;oBAC5C,IAAI,CAAC;wBACH,OAAO,IAAI,EAAE,CAAC;4BACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;4BAC3C,IAAI,IAAI;gCAAE,MAAK;4BACf,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;wBAC3B,CAAC;oBACH,CAAC;4BAAS,CAAC;wBACT,MAAM,CAAC,WAAW,EAAE,CAAA;wBACpB,UAAU,CAAC,KAAK,EAAE,CAAA;oBACpB,CAAC;gBACH,CAAC;aACF,CAAC,CAAA;YACF,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;gBAC1B,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,UAAU,EAAE,YAAY,CAAC,UAAU;gBACnC,OAAO,EAAE,YAAY,CAAC,OAAO;aAC9B,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAoBD,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAAC,OAG5B;IACC,MAAM,QAAQ,GACZ,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAgB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAA;IAChG,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;QAC5C,KAAK,CAAC,KAAK,CAAC,UAAU;YACpB,IAAI,CAAC;gBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;oBACnC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,yBAAyB,KAAK,MAAM,CAAC,CAAC,CAAA;gBAC1E,CAAC;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACrB,CAAC;oBAAS,CAAC;gBACT,UAAU,CAAC,KAAK,EAAE,CAAA;YACpB,CAAC;QACH,CAAC;KACF,CAAC,CAAA;IACF,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;QAC1B,OAAO,EAAE;YACP,cAAc,EAAE,kCAAkC;YAClD,eAAe,EAAE,wBAAwB;YACzC,UAAU,EAAE,YAAY;SACzB;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAc;IAEd,IAAI,OAAO,KAAK,KAAK,UAAU;QAAE,OAAO,KAAK,CAAA;IAC7C,OAAO,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,wBAAwB,CAAA;AAC7D,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,IAAK,KAAgB,CAAA;AACjG,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAc;IACtC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;AAC9C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mppx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.4",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"files": [
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"@remix-run/fetch-proxy": "^0.7.1",
|
|
122
122
|
"@remix-run/node-fetch-server": "^0.13.0",
|
|
123
123
|
"incur": "^0.3.1",
|
|
124
|
-
"ox": "
|
|
124
|
+
"ox": "0.14.7",
|
|
125
125
|
"zod": "^4.3.6"
|
|
126
126
|
},
|
|
127
127
|
"repository": {
|
package/src/Credential.ts
CHANGED
|
@@ -18,6 +18,30 @@ export type Credential<
|
|
|
18
18
|
source?: string
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export class MissingAuthorizationHeaderError extends Error {
|
|
22
|
+
override readonly name = 'MissingAuthorizationHeaderError'
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
super('Missing Authorization header.')
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class MissingPaymentSchemeError extends Error {
|
|
30
|
+
override readonly name = 'MissingPaymentSchemeError'
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
super('Missing Payment scheme.')
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class InvalidCredentialEncodingError extends Error {
|
|
38
|
+
override readonly name = 'InvalidCredentialEncodingError'
|
|
39
|
+
|
|
40
|
+
constructor() {
|
|
41
|
+
super('Invalid base64url or JSON.')
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
21
45
|
/**
|
|
22
46
|
* Deserializes an Authorization header value to a credential.
|
|
23
47
|
*
|
|
@@ -33,7 +57,7 @@ export type Credential<
|
|
|
33
57
|
*/
|
|
34
58
|
export function deserialize<payload = unknown>(value: string): Credential<payload> {
|
|
35
59
|
const prefixMatch = value.match(/^Payment\s+(.+)$/i)
|
|
36
|
-
if (!prefixMatch?.[1]) throw new
|
|
60
|
+
if (!prefixMatch?.[1]) throw new MissingPaymentSchemeError()
|
|
37
61
|
try {
|
|
38
62
|
const json = Base64.toString(prefixMatch[1])
|
|
39
63
|
const parsed = JSON.parse(json) as {
|
|
@@ -51,7 +75,7 @@ export function deserialize<payload = unknown>(value: string): Credential<payloa
|
|
|
51
75
|
...(parsed.source && { source: parsed.source }),
|
|
52
76
|
} as Credential<payload>
|
|
53
77
|
} catch {
|
|
54
|
-
throw new
|
|
78
|
+
throw new InvalidCredentialEncodingError()
|
|
55
79
|
}
|
|
56
80
|
}
|
|
57
81
|
|
|
@@ -108,9 +132,9 @@ export declare namespace from {
|
|
|
108
132
|
*/
|
|
109
133
|
export function fromRequest<payload = unknown>(request: Request): Credential<payload> {
|
|
110
134
|
const header = request.headers.get('Authorization')
|
|
111
|
-
if (!header) throw new
|
|
135
|
+
if (!header) throw new MissingAuthorizationHeaderError()
|
|
112
136
|
const payment = extractPaymentScheme(header)
|
|
113
|
-
if (!payment) throw new
|
|
137
|
+
if (!payment) throw new MissingPaymentSchemeError()
|
|
114
138
|
return deserialize<payload>(payment)
|
|
115
139
|
}
|
|
116
140
|
|
package/src/Method.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type * as Challenge from './Challenge.js'
|
|
|
2
2
|
import type * as Credential from './Credential.js'
|
|
3
3
|
import type { ExactPartial, LooseOmit, MaybePromise } from './internal/types.js'
|
|
4
4
|
import type * as Receipt from './Receipt.js'
|
|
5
|
+
import type * as Html from './server/internal/html/config.js'
|
|
5
6
|
import type * as Transport from './server/Transport.js'
|
|
6
7
|
import type * as z from './zod.js'
|
|
7
8
|
|
|
@@ -10,6 +11,7 @@ import type * as z from './zod.js'
|
|
|
10
11
|
*/
|
|
11
12
|
export type Method = {
|
|
12
13
|
name: string
|
|
14
|
+
html?: Html.Options | undefined
|
|
13
15
|
intent: string
|
|
14
16
|
schema: {
|
|
15
17
|
credential: {
|
|
@@ -74,6 +76,7 @@ export type Server<
|
|
|
74
76
|
transportOverride = undefined,
|
|
75
77
|
> = method & {
|
|
76
78
|
defaults?: defaults | undefined
|
|
79
|
+
html?: Html.Options | undefined
|
|
77
80
|
request?: RequestFn<method> | undefined
|
|
78
81
|
respond?: RespondFn<method> | undefined
|
|
79
82
|
transport?: transportOverride | undefined
|
|
@@ -202,10 +205,11 @@ export function toServer<
|
|
|
202
205
|
method: method,
|
|
203
206
|
options: toServer.Options<method, defaults, transportOverride>,
|
|
204
207
|
): Server<method, defaults, transportOverride> {
|
|
205
|
-
const { defaults, request, respond, transport, verify } = options
|
|
208
|
+
const { defaults, html, request, respond, transport, verify } = options
|
|
206
209
|
return {
|
|
207
210
|
...method,
|
|
208
211
|
defaults,
|
|
212
|
+
html,
|
|
209
213
|
request,
|
|
210
214
|
respond,
|
|
211
215
|
transport,
|
|
@@ -220,6 +224,7 @@ export declare namespace toServer {
|
|
|
220
224
|
transportOverride extends Transport.AnyTransport | undefined = undefined,
|
|
221
225
|
> = {
|
|
222
226
|
defaults?: defaults | undefined
|
|
227
|
+
html?: Html.Options | undefined
|
|
223
228
|
request?: RequestFn<method> | undefined
|
|
224
229
|
respond?: RespondFn<method> | undefined
|
|
225
230
|
transport?: transportOverride | undefined
|
package/src/cli/cli.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
printResponseHeaders,
|
|
33
33
|
prompt,
|
|
34
34
|
resolveChain,
|
|
35
|
+
resolveRpcUrl,
|
|
35
36
|
} from './utils.js'
|
|
36
37
|
|
|
37
38
|
const packageJson = createRequire(import.meta.url)('../../package.json') as {
|
|
@@ -516,8 +517,9 @@ const account = Cli.create('account', {
|
|
|
516
517
|
? link(`${explorerUrl}/address/${acct.address}`, acct.address)
|
|
517
518
|
: acct.address
|
|
518
519
|
console.log(pc.dim(`Address ${addrDisplay}`))
|
|
519
|
-
|
|
520
|
-
|
|
520
|
+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
|
|
521
|
+
resolveChain({ rpcUrl })
|
|
522
|
+
.then((chain) => createClient({ chain, transport: http(rpcUrl) }))
|
|
521
523
|
.then((client) =>
|
|
522
524
|
import('viem/tempo').then(({ Actions }) =>
|
|
523
525
|
Actions.faucet.fund(client, { account: acct }).catch(() => {}),
|
|
@@ -629,8 +631,9 @@ const account = Cli.create('account', {
|
|
|
629
631
|
return c.error({ code: 'ACCOUNT_NOT_FOUND', message: 'No account found.', exitCode: 69 })
|
|
630
632
|
}
|
|
631
633
|
const acct = privateKeyToAccount(key as `0x${string}`)
|
|
632
|
-
const
|
|
633
|
-
const
|
|
634
|
+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
|
|
635
|
+
const chain = await resolveChain({ rpcUrl })
|
|
636
|
+
const client = createClient({ chain, transport: http(rpcUrl) })
|
|
634
637
|
console.log(`Funding "${accountName}" on ${chainName(chain)}`)
|
|
635
638
|
try {
|
|
636
639
|
const { Actions } = await import('viem/tempo')
|
|
@@ -711,8 +714,8 @@ const account = Cli.create('account', {
|
|
|
711
714
|
})
|
|
712
715
|
}
|
|
713
716
|
const address = tempoEntry.wallet_address as Address
|
|
714
|
-
const rpcUrl = c.options.rpcUrl
|
|
715
|
-
const chain =
|
|
717
|
+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
|
|
718
|
+
const chain = await resolveChain({ rpcUrl })
|
|
716
719
|
const explorerUrl = chain.blockExplorers?.default?.url
|
|
717
720
|
const addrDisplay = explorerUrl
|
|
718
721
|
? link(`${explorerUrl}/address/${address}`, address)
|
|
@@ -744,8 +747,8 @@ const account = Cli.create('account', {
|
|
|
744
747
|
return c.error({ code: 'ACCOUNT_NOT_FOUND', message: 'No account found.', exitCode: 69 })
|
|
745
748
|
}
|
|
746
749
|
const acct = privateKeyToAccount(key as `0x${string}`)
|
|
747
|
-
const rpcUrl = c.options.rpcUrl
|
|
748
|
-
const chain =
|
|
750
|
+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
|
|
751
|
+
const chain = await resolveChain({ rpcUrl })
|
|
749
752
|
const explorerUrl = chain.blockExplorers?.default?.url
|
|
750
753
|
const addrDisplay = explorerUrl
|
|
751
754
|
? link(`${explorerUrl}/address/${acct.address}`, acct.address)
|
package/src/cli/plugins/tempo.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
link,
|
|
25
25
|
pc,
|
|
26
26
|
resolveChain,
|
|
27
|
+
resolveRpcUrl,
|
|
27
28
|
} from '../utils.js'
|
|
28
29
|
import { createPlugin, type Plugin } from './plugin.js'
|
|
29
30
|
|
|
@@ -67,7 +68,7 @@ export function tempo() {
|
|
|
67
68
|
useTempoCliSign = true
|
|
68
69
|
const tempoEntry = resolveTempoAccount(accountName)
|
|
69
70
|
if (tempoEntry) {
|
|
70
|
-
const rpcUrl = options.rpcUrl
|
|
71
|
+
const rpcUrl = resolveRpcUrl(options.rpcUrl)
|
|
71
72
|
client = createClient({
|
|
72
73
|
chain: await resolveChain({ rpcUrl }),
|
|
73
74
|
transport: http(rpcUrl),
|
|
@@ -107,7 +108,7 @@ export function tempo() {
|
|
|
107
108
|
} else account = privateKeyToAccount(privateKey as `0x${string}`)
|
|
108
109
|
|
|
109
110
|
if (!useTempoCliSign && account) {
|
|
110
|
-
const rpcUrl = options.rpcUrl
|
|
111
|
+
const rpcUrl = resolveRpcUrl(options.rpcUrl)
|
|
111
112
|
client = createClient({
|
|
112
113
|
chain: await resolveChain({ rpcUrl }),
|
|
113
114
|
transport: http(rpcUrl),
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { tempo as tempoMainnet, tempoModerato } from 'viem/chains'
|
|
2
|
+
import { afterEach, describe, expect, test } from 'vp/test'
|
|
3
|
+
|
|
4
|
+
import { resolveChain, resolveRpcUrl } from './utils.js'
|
|
5
|
+
|
|
6
|
+
describe('resolveRpcUrl', () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
delete process.env.MPPX_RPC_URL
|
|
9
|
+
delete process.env.RPC_URL
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('returns explicit value when provided', () => {
|
|
13
|
+
process.env.MPPX_RPC_URL = 'https://env.example.com'
|
|
14
|
+
expect(resolveRpcUrl('https://explicit.example.com')).toBe('https://explicit.example.com')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('falls back to MPPX_RPC_URL env var', () => {
|
|
18
|
+
process.env.MPPX_RPC_URL = 'https://mppx.example.com'
|
|
19
|
+
process.env.RPC_URL = 'https://rpc.example.com'
|
|
20
|
+
expect(resolveRpcUrl()).toBe('https://mppx.example.com')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('falls back to RPC_URL env var when MPPX_RPC_URL is not set', () => {
|
|
24
|
+
process.env.RPC_URL = 'https://rpc.example.com'
|
|
25
|
+
expect(resolveRpcUrl()).toBe('https://rpc.example.com')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('returns undefined when nothing is set', () => {
|
|
29
|
+
expect(resolveRpcUrl()).toBeUndefined()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('trims whitespace from env vars', () => {
|
|
33
|
+
process.env.MPPX_RPC_URL = ' https://mppx.example.com '
|
|
34
|
+
expect(resolveRpcUrl()).toBe('https://mppx.example.com')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('skips empty MPPX_RPC_URL and falls back to RPC_URL', () => {
|
|
38
|
+
process.env.MPPX_RPC_URL = ' '
|
|
39
|
+
process.env.RPC_URL = 'https://rpc.example.com'
|
|
40
|
+
expect(resolveRpcUrl()).toBe('https://rpc.example.com')
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('resolveChain', () => {
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
delete process.env.MPPX_RPC_URL
|
|
47
|
+
delete process.env.RPC_URL
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('defaults to tempo mainnet when no rpcUrl is provided', async () => {
|
|
51
|
+
const chain = await resolveChain()
|
|
52
|
+
expect(chain.id).toBe(tempoMainnet.id)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('defaults to tempo mainnet when rpcUrl is undefined', async () => {
|
|
56
|
+
const chain = await resolveChain({ rpcUrl: undefined })
|
|
57
|
+
expect(chain.id).toBe(tempoMainnet.id)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('does not default to testnet', async () => {
|
|
61
|
+
const chain = await resolveChain()
|
|
62
|
+
expect(chain.id).not.toBe(tempoModerato.id)
|
|
63
|
+
})
|
|
64
|
+
})
|
package/src/cli/utils.ts
CHANGED
|
@@ -221,17 +221,23 @@ export function fmtBalance(
|
|
|
221
221
|
return `${dec ? `${formatted}.${dec}` : formatted} ${sym}`
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/** Resolve RPC URL from explicit option, then MPPX_RPC_URL, then RPC_URL env vars. */
|
|
225
|
+
export function resolveRpcUrl(explicit?: string | undefined): string | undefined {
|
|
226
|
+
return explicit ?? (process.env.MPPX_RPC_URL?.trim() || process.env.RPC_URL?.trim() || undefined)
|
|
227
|
+
}
|
|
228
|
+
|
|
224
229
|
export async function resolveChain(opts: { rpcUrl?: string | undefined } = {}): Promise<Chain> {
|
|
225
|
-
|
|
230
|
+
const rpcUrl = resolveRpcUrl(opts.rpcUrl)
|
|
231
|
+
if (!rpcUrl) return tempoMainnet
|
|
226
232
|
const { getChainId } = await import('viem/actions')
|
|
227
|
-
const chainId = await getChainId(createClient({ transport: http(
|
|
233
|
+
const chainId = await getChainId(createClient({ transport: http(rpcUrl) }))
|
|
228
234
|
const allExports = Object.values(await import('viem/chains')) as unknown[]
|
|
229
235
|
const candidates = allExports.filter(
|
|
230
236
|
(c): c is Chain =>
|
|
231
237
|
typeof c === 'object' && c !== null && 'id' in c && (c as Chain).id === chainId,
|
|
232
238
|
)
|
|
233
239
|
const found = candidates.find((c) => 'serializers' in c && c.serializers) ?? candidates[0]
|
|
234
|
-
if (!found) throw new Error(`Unknown chain ID ${chainId} from RPC ${
|
|
240
|
+
if (!found) throw new Error(`Unknown chain ID ${chainId} from RPC ${rpcUrl}`)
|
|
235
241
|
return found
|
|
236
242
|
}
|
|
237
243
|
|
|
@@ -306,7 +312,7 @@ export async function fetchBalanceLines(
|
|
|
306
312
|
|
|
307
313
|
const mainnetClient = createClient({
|
|
308
314
|
chain: tempoMainnet,
|
|
309
|
-
transport: http(
|
|
315
|
+
transport: http(resolveRpcUrl()),
|
|
310
316
|
})
|
|
311
317
|
const mainnetExplorerUrl = tempoMainnet.blockExplorers?.default?.url
|
|
312
318
|
const mainnetResults = await Promise.all(
|
package/src/env.d.ts
CHANGED
|
@@ -113,6 +113,8 @@ describe('mcpSdk', () => {
|
|
|
113
113
|
|
|
114
114
|
const result = transport.respondReceipt({
|
|
115
115
|
challengeId: 'test-challenge-id',
|
|
116
|
+
credential,
|
|
117
|
+
input: {} as Extra,
|
|
116
118
|
receipt,
|
|
117
119
|
response,
|
|
118
120
|
})
|
|
@@ -139,6 +141,8 @@ describe('mcpSdk', () => {
|
|
|
139
141
|
|
|
140
142
|
const result = transport.respondReceipt({
|
|
141
143
|
challengeId: 'cid',
|
|
144
|
+
credential,
|
|
145
|
+
input: {} as Extra,
|
|
142
146
|
receipt,
|
|
143
147
|
response,
|
|
144
148
|
})
|
|
@@ -162,6 +166,8 @@ describe('mcpSdk', () => {
|
|
|
162
166
|
|
|
163
167
|
const result = transport.respondReceipt({
|
|
164
168
|
challengeId: 'cid',
|
|
169
|
+
credential,
|
|
170
|
+
input: {} as Extra,
|
|
165
171
|
receipt,
|
|
166
172
|
response,
|
|
167
173
|
})
|