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.
Files changed (111) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/Credential.d.ts +12 -0
  3. package/dist/Credential.d.ts.map +1 -1
  4. package/dist/Credential.js +22 -4
  5. package/dist/Credential.js.map +1 -1
  6. package/dist/Method.d.ts +4 -0
  7. package/dist/Method.d.ts.map +1 -1
  8. package/dist/Method.js +2 -1
  9. package/dist/Method.js.map +1 -1
  10. package/dist/cli/cli.d.ts.map +1 -1
  11. package/dist/cli/cli.js +11 -9
  12. package/dist/cli/cli.js.map +1 -1
  13. package/dist/cli/plugins/tempo.d.ts.map +1 -1
  14. package/dist/cli/plugins/tempo.js +3 -3
  15. package/dist/cli/plugins/tempo.js.map +1 -1
  16. package/dist/cli/utils.d.ts +2 -0
  17. package/dist/cli/utils.d.ts.map +1 -1
  18. package/dist/cli/utils.js +10 -5
  19. package/dist/cli/utils.js.map +1 -1
  20. package/dist/proxy/Proxy.d.ts.map +1 -1
  21. package/dist/proxy/Proxy.js +52 -8
  22. package/dist/proxy/Proxy.js.map +1 -1
  23. package/dist/proxy/internal/Route.d.ts.map +1 -1
  24. package/dist/proxy/internal/Route.js +7 -3
  25. package/dist/proxy/internal/Route.js.map +1 -1
  26. package/dist/server/Mppx.d.ts.map +1 -1
  27. package/dist/server/Mppx.js +90 -71
  28. package/dist/server/Mppx.js.map +1 -1
  29. package/dist/server/Transport.d.ts +5 -1
  30. package/dist/server/Transport.d.ts.map +1 -1
  31. package/dist/server/Transport.js +71 -7
  32. package/dist/server/Transport.js.map +1 -1
  33. package/dist/server/internal/html/config.d.ts +144 -0
  34. package/dist/server/internal/html/config.d.ts.map +1 -0
  35. package/dist/server/internal/html/config.js +303 -0
  36. package/dist/server/internal/html/config.js.map +1 -0
  37. package/dist/server/internal/html/serviceWorker.gen.d.ts +2 -0
  38. package/dist/server/internal/html/serviceWorker.gen.d.ts.map +1 -0
  39. package/dist/server/internal/html/serviceWorker.gen.js +3 -0
  40. package/dist/server/internal/html/serviceWorker.gen.js.map +1 -0
  41. package/dist/stripe/internal/types.d.ts +6 -0
  42. package/dist/stripe/internal/types.d.ts.map +1 -1
  43. package/dist/stripe/server/Charge.d.ts +30 -16
  44. package/dist/stripe/server/Charge.d.ts.map +1 -1
  45. package/dist/stripe/server/Charge.js +35 -6
  46. package/dist/stripe/server/Charge.js.map +1 -1
  47. package/dist/stripe/server/internal/html/types.d.ts +2 -0
  48. package/dist/stripe/server/internal/html/types.d.ts.map +1 -0
  49. package/dist/stripe/server/internal/html/types.js +2 -0
  50. package/dist/stripe/server/internal/html/types.js.map +1 -0
  51. package/dist/stripe/server/internal/html.gen.d.ts +2 -0
  52. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -0
  53. package/dist/stripe/server/internal/html.gen.js +3 -0
  54. package/dist/stripe/server/internal/html.gen.js.map +1 -0
  55. package/dist/tempo/server/Charge.d.ts +33 -26
  56. package/dist/tempo/server/Charge.d.ts.map +1 -1
  57. package/dist/tempo/server/Charge.js +46 -11
  58. package/dist/tempo/server/Charge.js.map +1 -1
  59. package/dist/tempo/server/Session.d.ts.map +1 -1
  60. package/dist/tempo/server/Session.js +3 -2
  61. package/dist/tempo/server/Session.js.map +1 -1
  62. package/dist/tempo/server/internal/html.gen.d.ts +2 -0
  63. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -0
  64. package/dist/tempo/server/internal/html.gen.js +3 -0
  65. package/dist/tempo/server/internal/html.gen.js.map +1 -0
  66. package/dist/tempo/server/internal/transport.d.ts +1 -1
  67. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  68. package/dist/tempo/server/internal/transport.js +45 -58
  69. package/dist/tempo/server/internal/transport.js.map +1 -1
  70. package/package.json +2 -2
  71. package/src/Credential.ts +28 -4
  72. package/src/Method.ts +6 -1
  73. package/src/cli/cli.ts +11 -8
  74. package/src/cli/plugins/tempo.ts +3 -2
  75. package/src/cli/utils.test.ts +64 -0
  76. package/src/cli/utils.ts +10 -4
  77. package/src/env.d.ts +1 -0
  78. package/src/mcp-sdk/server/Transport.test.ts +6 -0
  79. package/src/proxy/Proxy.test.ts +188 -1
  80. package/src/proxy/Proxy.ts +58 -9
  81. package/src/proxy/internal/Route.test.ts +9 -0
  82. package/src/proxy/internal/Route.ts +5 -2
  83. package/src/server/Mppx.test.ts +171 -18
  84. package/src/server/Mppx.ts +120 -79
  85. package/src/server/Transport.test.ts +232 -2
  86. package/src/server/Transport.ts +84 -7
  87. package/src/server/internal/html/config.ts +414 -0
  88. package/src/server/internal/html/serviceWorker.client.ts +28 -0
  89. package/src/server/internal/html/serviceWorker.gen.ts +2 -0
  90. package/src/server/internal/html/serviceWorker.ts +27 -0
  91. package/src/server/internal/html/tsconfig.worker.client.json +8 -0
  92. package/src/server/internal/html/tsconfig.worker.json +8 -0
  93. package/src/stripe/internal/types.ts +20 -0
  94. package/src/stripe/server/Charge.ts +62 -6
  95. package/src/stripe/server/internal/html/main.ts +174 -0
  96. package/src/stripe/server/internal/html/node_modules/.bin/mppx.src +21 -0
  97. package/src/stripe/server/internal/html/package.json +9 -0
  98. package/src/stripe/server/internal/html/stripe-js-pure.d.ts +7 -0
  99. package/src/stripe/server/internal/html/tsconfig.json +8 -0
  100. package/src/stripe/server/internal/html/types.ts +5 -0
  101. package/src/stripe/server/internal/html.gen.ts +2 -0
  102. package/src/tempo/server/Charge.ts +64 -10
  103. package/src/tempo/server/Session.ts +3 -2
  104. package/src/tempo/server/internal/html/main.ts +111 -0
  105. package/src/tempo/server/internal/html/node_modules/.bin/mppx.src +21 -0
  106. package/src/tempo/server/internal/html/package.json +10 -0
  107. package/src/tempo/server/internal/html/tsconfig.json +8 -0
  108. package/src/tempo/server/internal/html.gen.ts +2 -0
  109. package/src/tempo/server/internal/transport.test.ts +37 -31
  110. package/src/tempo/server/internal/transport.ts +44 -58
  111. 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,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
@@ -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;AAEhD,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,CAqHpF;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
+ {"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
- const credential = base.getCredential(request);
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: ctx.channelId,
62
+ channelId,
73
63
  challengeId,
74
- tickCost: ctx.tickCost,
64
+ tickCost,
75
65
  pollIntervalMs: pollingInterval,
76
66
  generate,
77
- signal: ctx.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
- const ctx = contextMap.get(challengeId);
89
- if (ctx) {
90
- contextMap.delete(challengeId);
91
- // Null-body statuses (e.g. 204 from management actions) cannot carry a
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
- return baseResponse;
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;AAKhD;;;;;;;;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,UAAU,GAAG,IAAI,GAAG,EAAmE,CAAA;IAE7F,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,CAAA;IAC7B,OAAO,SAAS,CAAC,IAAI,CAAgE;QACnF,IAAI,EAAE,KAAK;QAEX,aAAa,CAAC,OAAO;YACnB,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;YAC9C,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;oBACzC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;gBACrE,CAAC;gBAAC,MAAM,CAAC;oBACP,0DAA0D;gBAC5D,CAAC;YACH,CAAC;YACD,OAAO,UAAU,CAAA;QACnB,CAAC;QAED,gBAAgB,CAAC,OAAO;YACtB,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAa,CAAA;QACnD,CAAC;QAED,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE;YAC/C,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,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;gBACvC,IAAI,CAAC,GAAG;oBAAE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;gBACjF,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;gBAE9B,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,EAAE,GAAG,CAAC,SAAS;oBACxB,WAAW;oBACX,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,cAAc,EAAE,eAAe;oBAC/B,QAAQ;oBACR,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAA;gBACF,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YACpC,CAAC;YAED,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC;gBACvC,OAAO;gBACP,QAAQ,EAAE,QAAoB;gBAC9B,WAAW;aACZ,CAAC,CAAA;YAEF,0EAA0E;YAC1E,iDAAiD;YACjD,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;YACvC,IAAI,GAAG,EAAE,CAAC;gBACR,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;gBAE9B,uEAAuE;gBACvE,0CAA0C;gBAC1C,IAAI,gBAAgB,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC1C,OAAO,YAAY,CAAA;gBACrB,CAAC;gBAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;oBAC5C,KAAK,CAAC,KAAK,CAAC,UAAU;wBACpB,4CAA4C;wBAC5C,MAAM,YAAY,CAAC,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;wBACxE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;4BACvB,UAAU,CAAC,KAAK,EAAE,CAAA;4BAClB,OAAM;wBACR,CAAC;wBACD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;wBAC5C,IAAI,CAAC;4BACH,OAAO,IAAI,EAAE,CAAC;gCACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;gCAC3C,IAAI,IAAI;oCAAE,MAAK;gCACf,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;4BAC3B,CAAC;wBACH,CAAC;gCAAS,CAAC;4BACT,MAAM,CAAC,WAAW,EAAE,CAAA;4BACpB,UAAU,CAAC,KAAK,EAAE,CAAA;wBACpB,CAAC;oBACH,CAAC;iBACF,CAAC,CAAA;gBACF,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;oBAC1B,MAAM,EAAE,YAAY,CAAC,MAAM;oBAC3B,UAAU,EAAE,YAAY,CAAC,UAAU;oBACnC,OAAO,EAAE,YAAY,CAAC,OAAO;iBAC9B,CAAC,CAAA;YACJ,CAAC;YAED,OAAO,YAAY,CAAA;QACrB,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"}
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/transport.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mppx",
3
3
  "type": "module",
4
- "version": "0.5.1",
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": "^0.14.1",
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 Error('Missing Payment scheme.')
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 Error('Invalid base64url or JSON.')
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 Error('Missing Authorization header.')
135
+ if (!header) throw new MissingAuthorizationHeaderError()
112
136
  const payment = extractPaymentScheme(header)
113
- if (!payment) throw new Error('Missing Payment scheme.')
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
- resolveChain(c.options)
520
- .then((chain) => createClient({ chain, transport: http(c.options.rpcUrl) }))
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 chain = await resolveChain(c.options)
633
- const client = createClient({ chain, transport: http(c.options.rpcUrl) })
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 ?? (process.env.MPPX_RPC_URL || undefined)
715
- const chain = rpcUrl ? await resolveChain({ rpcUrl }) : tempoMainnet
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 ?? (process.env.MPPX_RPC_URL || undefined)
748
- const chain = rpcUrl ? await resolveChain({ rpcUrl }) : tempoMainnet
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)
@@ -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 ?? process.env.RPC_URL
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 ?? process.env.RPC_URL
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
- if (!opts.rpcUrl) return tempoModerato
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(opts.rpcUrl) }))
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 ${opts.rpcUrl}`)
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(process.env.MPPX_RPC_URL || undefined),
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
@@ -1,6 +1,7 @@
1
1
  /// <reference types="vite/client" />
2
2
 
3
3
  interface ImportMetaEnv {
4
+ readonly MODE: 'test' | 'production'
4
5
  readonly VITE_NODE_ENV: 'localnet' | 'testnet' | 'mainnet'
5
6
  readonly VITE_HTTP_LOG: 'true' | 'false'
6
7
  readonly VITE_RPC_CREDENTIALS: string
@@ -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
  })