mppx 0.5.0 → 0.5.3

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 (104) hide show
  1. package/CHANGELOG.md +19 -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/account.d.ts.map +1 -1
  11. package/dist/cli/account.js +12 -2
  12. package/dist/cli/account.js.map +1 -1
  13. package/dist/proxy/Proxy.d.ts.map +1 -1
  14. package/dist/proxy/Proxy.js +52 -8
  15. package/dist/proxy/Proxy.js.map +1 -1
  16. package/dist/proxy/internal/Route.d.ts.map +1 -1
  17. package/dist/proxy/internal/Route.js +7 -3
  18. package/dist/proxy/internal/Route.js.map +1 -1
  19. package/dist/server/Mppx.d.ts.map +1 -1
  20. package/dist/server/Mppx.js +90 -71
  21. package/dist/server/Mppx.js.map +1 -1
  22. package/dist/server/Transport.d.ts +5 -1
  23. package/dist/server/Transport.d.ts.map +1 -1
  24. package/dist/server/Transport.js +52 -7
  25. package/dist/server/Transport.js.map +1 -1
  26. package/dist/server/internal/html/config.d.ts +7 -0
  27. package/dist/server/internal/html/config.d.ts.map +1 -0
  28. package/dist/server/internal/html/config.js +3 -0
  29. package/dist/server/internal/html/config.js.map +1 -0
  30. package/dist/server/internal/html/serviceWorker.gen.d.ts +2 -0
  31. package/dist/server/internal/html/serviceWorker.gen.d.ts.map +1 -0
  32. package/dist/server/internal/html/serviceWorker.gen.js +3 -0
  33. package/dist/server/internal/html/serviceWorker.gen.js.map +1 -0
  34. package/dist/stripe/server/Charge.d.ts +5 -0
  35. package/dist/stripe/server/Charge.d.ts.map +1 -1
  36. package/dist/stripe/server/Charge.js +14 -6
  37. package/dist/stripe/server/Charge.js.map +1 -1
  38. package/dist/stripe/server/internal/html.gen.d.ts +2 -0
  39. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -0
  40. package/dist/stripe/server/internal/html.gen.js +3 -0
  41. package/dist/stripe/server/internal/html.gen.js.map +1 -0
  42. package/dist/tempo/internal/proof.d.ts +6 -0
  43. package/dist/tempo/internal/proof.d.ts.map +1 -1
  44. package/dist/tempo/internal/proof.js +15 -0
  45. package/dist/tempo/internal/proof.js.map +1 -1
  46. package/dist/tempo/server/Charge.d.ts +10 -3
  47. package/dist/tempo/server/Charge.d.ts.map +1 -1
  48. package/dist/tempo/server/Charge.js +38 -10
  49. package/dist/tempo/server/Charge.js.map +1 -1
  50. package/dist/tempo/server/Session.d.ts.map +1 -1
  51. package/dist/tempo/server/Session.js +3 -2
  52. package/dist/tempo/server/Session.js.map +1 -1
  53. package/dist/tempo/server/internal/html.gen.d.ts +2 -0
  54. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -0
  55. package/dist/tempo/server/internal/html.gen.js +3 -0
  56. package/dist/tempo/server/internal/html.gen.js.map +1 -0
  57. package/dist/tempo/server/internal/transport.d.ts +1 -1
  58. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  59. package/dist/tempo/server/internal/transport.js +45 -58
  60. package/dist/tempo/server/internal/transport.js.map +1 -1
  61. package/package.json +2 -2
  62. package/src/Credential.ts +28 -4
  63. package/src/Method.ts +6 -1
  64. package/src/cli/account.ts +13 -2
  65. package/src/env.d.ts +1 -0
  66. package/src/mcp-sdk/server/Transport.test.ts +6 -0
  67. package/src/middlewares/elysia.test.ts +3 -5
  68. package/src/middlewares/express.test.ts +3 -5
  69. package/src/middlewares/hono.test.ts +8 -5
  70. package/src/middlewares/nextjs.test.ts +3 -5
  71. package/src/proxy/Proxy.test.ts +188 -1
  72. package/src/proxy/Proxy.ts +58 -9
  73. package/src/proxy/internal/Route.test.ts +9 -0
  74. package/src/proxy/internal/Route.ts +5 -2
  75. package/src/server/Mppx.test.ts +171 -18
  76. package/src/server/Mppx.ts +120 -79
  77. package/src/server/Transport.test.ts +16 -2
  78. package/src/server/Transport.ts +61 -7
  79. package/src/server/internal/html/config.ts +8 -0
  80. package/src/server/internal/html/serviceWorker.client.ts +28 -0
  81. package/src/server/internal/html/serviceWorker.gen.ts +2 -0
  82. package/src/server/internal/html/serviceWorker.ts +27 -0
  83. package/src/server/internal/html/tsconfig.worker.client.json +8 -0
  84. package/src/server/internal/html/tsconfig.worker.json +8 -0
  85. package/src/stripe/server/Charge.ts +19 -5
  86. package/src/stripe/server/internal/html/main.ts +106 -0
  87. package/src/stripe/server/internal/html/node_modules/.bin/mppx.src +21 -0
  88. package/src/stripe/server/internal/html/package.json +9 -0
  89. package/src/stripe/server/internal/html/stripe-js-pure.d.ts +7 -0
  90. package/src/stripe/server/internal/html/tsconfig.json +8 -0
  91. package/src/stripe/server/internal/html.gen.ts +2 -0
  92. package/src/tempo/internal/proof.test.ts +47 -0
  93. package/src/tempo/internal/proof.ts +16 -0
  94. package/src/tempo/server/Charge.test.ts +298 -0
  95. package/src/tempo/server/Charge.ts +61 -12
  96. package/src/tempo/server/Session.ts +3 -2
  97. package/src/tempo/server/internal/html/main.ts +71 -0
  98. package/src/tempo/server/internal/html/node_modules/.bin/mppx.src +21 -0
  99. package/src/tempo/server/internal/html/package.json +10 -0
  100. package/src/tempo/server/internal/html/tsconfig.json +8 -0
  101. package/src/tempo/server/internal/html.gen.ts +2 -0
  102. package/src/tempo/server/internal/transport.test.ts +37 -31
  103. package/src/tempo/server/internal/transport.ts +44 -58
  104. 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,8wwaAA8wwa,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.0",
4
+ "version": "0.5.3",
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
@@ -4,13 +4,19 @@ import * as os from 'node:os'
4
4
  import * as path from 'node:path'
5
5
 
6
6
  const SERVICE_NAME = 'mppx'
7
+ const defaultCommandTimeoutMs = 10_000
8
+
9
+ function commandTimeoutMs() {
10
+ const value = Number.parseInt(process.env.MPPX_KEYCHAIN_COMMAND_TIMEOUT_MS ?? '', 10)
11
+ return Number.isFinite(value) && value > 0 ? value : defaultCommandTimeoutMs
12
+ }
7
13
 
8
14
  export function execCommand(
9
15
  command: string,
10
16
  args: string[],
11
17
  ): Promise<{ stdout: string; stderr: string; error: Error | null }> {
12
18
  return new Promise((resolve) => {
13
- child.execFile(command, args, (error, stdout, stderr) => {
19
+ child.execFile(command, args, { timeout: commandTimeoutMs() }, (error, stdout, stderr) => {
14
20
  resolve({ stdout: stdout.trim(), stderr: stderr.trim(), error })
15
21
  })
16
22
  })
@@ -134,14 +140,19 @@ export function createKeychain(account = 'main') {
134
140
  'account',
135
141
  account,
136
142
  ])
143
+ const timeout = setTimeout(() => proc.kill(), commandTimeoutMs())
137
144
  proc.stdin?.write(value)
138
145
  proc.stdin?.end()
139
146
  return new Promise((resolve, reject) => {
140
147
  proc.on('close', (code) => {
148
+ clearTimeout(timeout)
141
149
  if (code === 0) resolve()
142
150
  else reject(new Error(`secret-tool exited with code ${code}`))
143
151
  })
144
- proc.on('error', reject)
152
+ proc.on('error', (error) => {
153
+ clearTimeout(timeout)
154
+ reject(error)
155
+ })
145
156
  })
146
157
  }
147
158
  throw new Error(`Unsupported platform: ${platform}`)
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
  })
@@ -8,11 +8,12 @@ import { tempo as tempo_server } from 'mppx/server'
8
8
  import type { Address } from 'viem'
9
9
  import { Addresses } from 'viem/tempo'
10
10
  import { beforeAll, describe, expect, test } from 'vp/test'
11
+ import * as TestHttp from '~test/Http.js'
11
12
  import { deployEscrow } from '~test/tempo/session.js'
12
13
  import { accounts, asset, client, fundAccount } from '~test/tempo/viem.js'
13
14
 
14
15
  function createServer(app: Elysia<any, any, any, any, any, any, any>) {
15
- return new Promise<{ url: string; close: () => void }>((resolve) => {
16
+ return new Promise<TestHttp.TestServer>((resolve) => {
16
17
  const server = http.createServer(async (req, res) => {
17
18
  const url = `http://localhost${req.url}`
18
19
  const headers = new Headers()
@@ -27,10 +28,7 @@ function createServer(app: Elysia<any, any, any, any, any, any, any>) {
27
28
  })
28
29
  server.listen(0, () => {
29
30
  const { port } = server.address() as { port: number }
30
- resolve({
31
- url: `http://localhost:${port}`,
32
- close: () => server.close(),
33
- })
31
+ resolve(TestHttp.wrapServer(server, { port, url: `http://localhost:${port}` }))
34
32
  })
35
33
  })
36
34
  }
@@ -6,17 +6,15 @@ import { Mppx as Mppx_server, tempo as tempo_server } from 'mppx/server'
6
6
  import type { Address } from 'viem'
7
7
  import { Addresses } from 'viem/tempo'
8
8
  import { beforeAll, describe, expect, test } from 'vp/test'
9
+ import * as Http from '~test/Http.js'
9
10
  import { deployEscrow } from '~test/tempo/session.js'
10
11
  import { accounts, asset, client, fundAccount } from '~test/tempo/viem.js'
11
12
 
12
13
  function createServer(app: express.Express) {
13
- return new Promise<{ url: string; close: () => void }>((resolve) => {
14
+ return new Promise<Http.TestServer>((resolve) => {
14
15
  const server = app.listen(0, () => {
15
16
  const { port } = server.address() as { port: number }
16
- resolve({
17
- url: `http://localhost:${port}`,
18
- close: () => server.close(),
19
- })
17
+ resolve(Http.wrapServer(server, { port, url: `http://localhost:${port}` }))
20
18
  })
21
19
  })
22
20
  }
@@ -7,16 +7,19 @@ import { tempo as tempo_server } from 'mppx/server'
7
7
  import type { Address } from 'viem'
8
8
  import { Addresses } from 'viem/tempo'
9
9
  import { beforeAll, describe, expect, test } from 'vp/test'
10
+ import * as Http from '~test/Http.js'
10
11
  import { deployEscrow } from '~test/tempo/session.js'
11
12
  import { accounts, asset, client, fundAccount } from '~test/tempo/viem.js'
12
13
 
13
14
  function createServer(app: Hono) {
14
- return new Promise<{ url: string; close: () => void }>((resolve) => {
15
+ return new Promise<Http.TestServer>((resolve) => {
15
16
  const server = serve({ fetch: app.fetch, port: 0 }, (info) => {
16
- resolve({
17
- url: `http://localhost:${info.port}`,
18
- close: () => server.close(),
19
- })
17
+ resolve(
18
+ Http.wrapServer(server as unknown as import('node:http').Server, {
19
+ port: info.port,
20
+ url: `http://localhost:${info.port}`,
21
+ }),
22
+ )
20
23
  })
21
24
  })
22
25
  }
@@ -7,11 +7,12 @@ import { tempo as tempo_server } from 'mppx/server'
7
7
  import type { Address } from 'viem'
8
8
  import { Addresses } from 'viem/tempo'
9
9
  import { beforeAll, describe, expect, test } from 'vp/test'
10
+ import * as TestHttp from '~test/Http.js'
10
11
  import { deployEscrow } from '~test/tempo/session.js'
11
12
  import { accounts, asset, chain, client, fundAccount } from '~test/tempo/viem.js'
12
13
 
13
14
  function createServer(handler: (request: Request) => Promise<Response> | Response) {
14
- return new Promise<{ url: string; close: () => void }>((resolve) => {
15
+ return new Promise<TestHttp.TestServer>((resolve) => {
15
16
  const server = http.createServer(async (req, res) => {
16
17
  const url = `http://localhost${req.url}`
17
18
  const headers = new Headers()
@@ -26,10 +27,7 @@ function createServer(handler: (request: Request) => Promise<Response> | Respons
26
27
  })
27
28
  server.listen(0, () => {
28
29
  const { port } = server.address() as { port: number }
29
- resolve({
30
- url: `http://localhost:${port}`,
31
- close: () => server.close(),
32
- })
30
+ resolve(TestHttp.wrapServer(server, { port, url: `http://localhost:${port}` }))
33
31
  })
34
32
  })
35
33
  }