mppx 0.4.8 → 0.4.9

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 (183) hide show
  1. package/CHANGELOG.md +9 -3
  2. package/README.md +13 -13
  3. package/dist/BodyDigest.d.ts.map +1 -1
  4. package/dist/BodyDigest.js.map +1 -1
  5. package/dist/Challenge.d.ts.map +1 -1
  6. package/dist/Challenge.js.map +1 -1
  7. package/dist/Credential.d.ts.map +1 -1
  8. package/dist/Credential.js.map +1 -1
  9. package/dist/Errors.js +64 -67
  10. package/dist/Errors.js.map +1 -1
  11. package/dist/PaymentRequest.d.ts.map +1 -1
  12. package/dist/PaymentRequest.js.map +1 -1
  13. package/dist/Receipt.d.ts.map +1 -1
  14. package/dist/Receipt.js.map +1 -1
  15. package/dist/Store.d.ts +9 -0
  16. package/dist/Store.d.ts.map +1 -1
  17. package/dist/Store.js +17 -0
  18. package/dist/Store.js.map +1 -1
  19. package/dist/cli/account.d.ts.map +1 -1
  20. package/dist/cli/account.js +40 -5
  21. package/dist/cli/account.js.map +1 -1
  22. package/dist/cli/cli.d.ts.map +1 -1
  23. package/dist/cli/cli.js +2 -1
  24. package/dist/cli/cli.js.map +1 -1
  25. package/dist/cli/internal.d.ts.map +1 -1
  26. package/dist/cli/internal.js.map +1 -1
  27. package/dist/cli/plugins/stripe.d.ts.map +1 -1
  28. package/dist/cli/plugins/stripe.js.map +1 -1
  29. package/dist/cli/plugins/tempo.d.ts.map +1 -1
  30. package/dist/cli/plugins/tempo.js +2 -1
  31. package/dist/cli/plugins/tempo.js.map +1 -1
  32. package/dist/cli/utils.d.ts.map +1 -1
  33. package/dist/cli/utils.js.map +1 -1
  34. package/dist/client/internal/Fetch.d.ts +2 -0
  35. package/dist/client/internal/Fetch.d.ts.map +1 -1
  36. package/dist/client/internal/Fetch.js +1 -1
  37. package/dist/client/internal/Fetch.js.map +1 -1
  38. package/dist/internal/types.d.ts.map +1 -1
  39. package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
  40. package/dist/mcp-sdk/client/McpClient.js +1 -1
  41. package/dist/mcp-sdk/client/McpClient.js.map +1 -1
  42. package/dist/mcp-sdk/server/Transport.d.ts.map +1 -1
  43. package/dist/mcp-sdk/server/Transport.js.map +1 -1
  44. package/dist/middlewares/elysia.d.ts.map +1 -1
  45. package/dist/middlewares/elysia.js.map +1 -1
  46. package/dist/middlewares/express.d.ts.map +1 -1
  47. package/dist/middlewares/express.js +5 -2
  48. package/dist/middlewares/express.js.map +1 -1
  49. package/dist/middlewares/hono.d.ts.map +1 -1
  50. package/dist/middlewares/hono.js.map +1 -1
  51. package/dist/proxy/Proxy.d.ts.map +1 -1
  52. package/dist/proxy/Proxy.js.map +1 -1
  53. package/dist/proxy/Service.js +1 -1
  54. package/dist/proxy/Service.js.map +1 -1
  55. package/dist/server/Mppx.d.ts.map +1 -1
  56. package/dist/server/Mppx.js +35 -17
  57. package/dist/server/Mppx.js.map +1 -1
  58. package/dist/server/Request.d.ts.map +1 -1
  59. package/dist/server/Request.js.map +1 -1
  60. package/dist/stripe/Methods.d.ts.map +1 -1
  61. package/dist/stripe/Methods.js.map +1 -1
  62. package/dist/tempo/Methods.d.ts.map +1 -1
  63. package/dist/tempo/Methods.js.map +1 -1
  64. package/dist/tempo/client/ChannelOps.d.ts.map +1 -1
  65. package/dist/tempo/client/ChannelOps.js.map +1 -1
  66. package/dist/tempo/client/Charge.d.ts.map +1 -1
  67. package/dist/tempo/client/Charge.js.map +1 -1
  68. package/dist/tempo/client/Session.d.ts.map +1 -1
  69. package/dist/tempo/client/Session.js.map +1 -1
  70. package/dist/tempo/client/SessionManager.d.ts.map +1 -1
  71. package/dist/tempo/client/SessionManager.js +1 -1
  72. package/dist/tempo/client/SessionManager.js.map +1 -1
  73. package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
  74. package/dist/tempo/internal/auto-swap.js +1 -1
  75. package/dist/tempo/internal/auto-swap.js.map +1 -1
  76. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  77. package/dist/tempo/internal/fee-payer.js +1 -1
  78. package/dist/tempo/internal/fee-payer.js.map +1 -1
  79. package/dist/tempo/server/Charge.d.ts.map +1 -1
  80. package/dist/tempo/server/Charge.js +1 -1
  81. package/dist/tempo/server/Charge.js.map +1 -1
  82. package/dist/tempo/server/Session.d.ts.map +1 -1
  83. package/dist/tempo/server/Session.js.map +1 -1
  84. package/dist/tempo/session/Chain.d.ts.map +1 -1
  85. package/dist/tempo/session/Chain.js.map +1 -1
  86. package/dist/tempo/session/ChannelStore.d.ts.map +1 -1
  87. package/dist/tempo/session/ChannelStore.js.map +1 -1
  88. package/dist/tempo/session/Receipt.d.ts.map +1 -1
  89. package/dist/tempo/session/Receipt.js.map +1 -1
  90. package/dist/tempo/session/Sse.d.ts.map +1 -1
  91. package/dist/tempo/session/Sse.js.map +1 -1
  92. package/dist/tempo/session/Voucher.d.ts.map +1 -1
  93. package/dist/tempo/session/Voucher.js.map +1 -1
  94. package/dist/viem/Client.d.ts.map +1 -1
  95. package/dist/viem/Client.js.map +1 -1
  96. package/package.json +1 -1
  97. package/src/BodyDigest.ts +1 -0
  98. package/src/Challenge.test-d.ts +1 -0
  99. package/src/Challenge.ts +1 -0
  100. package/src/Credential.ts +1 -0
  101. package/src/Errors.test.ts +27 -39
  102. package/src/Expires.test.ts +1 -0
  103. package/src/PaymentRequest.ts +1 -0
  104. package/src/Receipt.ts +1 -0
  105. package/src/Store.test-d.ts +1 -0
  106. package/src/Store.test.ts +56 -6
  107. package/src/Store.ts +25 -0
  108. package/src/cli/account.ts +65 -30
  109. package/src/cli/cli.test.ts +3 -1
  110. package/src/cli/cli.ts +4 -1
  111. package/src/cli/config.test.ts +1 -0
  112. package/src/cli/internal.ts +1 -0
  113. package/src/cli/plugins/stripe.ts +1 -0
  114. package/src/cli/plugins/tempo.ts +4 -1
  115. package/src/cli/utils.ts +1 -0
  116. package/src/client/Mppx.test-d.ts +1 -0
  117. package/src/client/internal/Fetch.browser.test.ts +1 -0
  118. package/src/client/internal/Fetch.test-d.ts +1 -0
  119. package/src/client/internal/Fetch.test.ts +1 -0
  120. package/src/client/internal/Fetch.ts +1 -1
  121. package/src/internal/constantTimeEqual.test.ts +1 -0
  122. package/src/internal/types.ts +1 -3
  123. package/src/mcp-sdk/client/McpClient.test-d.ts +1 -0
  124. package/src/mcp-sdk/client/McpClient.test.ts +1 -0
  125. package/src/mcp-sdk/client/McpClient.ts +2 -0
  126. package/src/mcp-sdk/server/Transport.test.ts +1 -0
  127. package/src/mcp-sdk/server/Transport.ts +1 -0
  128. package/src/middlewares/elysia.test.ts +1 -0
  129. package/src/middlewares/elysia.ts +1 -0
  130. package/src/middlewares/express.test.ts +62 -2
  131. package/src/middlewares/express.ts +6 -2
  132. package/src/middlewares/hono.ts +1 -0
  133. package/src/middlewares/internal/mppx.test.ts +1 -0
  134. package/src/middlewares/nextjs.test.ts +1 -0
  135. package/src/proxy/Proxy.test.ts +1 -0
  136. package/src/proxy/Proxy.ts +2 -0
  137. package/src/proxy/Service.test.ts +1 -0
  138. package/src/proxy/Service.ts +8 -2
  139. package/src/proxy/internal/Headers.test.ts +1 -0
  140. package/src/proxy/services/openai.test.ts +1 -0
  141. package/src/server/Mppx.test.ts +192 -0
  142. package/src/server/Mppx.ts +38 -19
  143. package/src/server/Request.test.ts +1 -0
  144. package/src/server/Request.ts +1 -0
  145. package/src/server/Response.test.ts +1 -0
  146. package/src/server/Transport.test.ts +1 -0
  147. package/src/stripe/Methods.ts +1 -0
  148. package/src/stripe/client/Charge.test.ts +1 -0
  149. package/src/stripe/server/Charge.test.ts +1 -0
  150. package/src/tempo/Attribution.test.ts +1 -0
  151. package/src/tempo/Methods.ts +1 -0
  152. package/src/tempo/client/ChannelOps.test.ts +1 -0
  153. package/src/tempo/client/ChannelOps.ts +1 -0
  154. package/src/tempo/client/Charge.ts +1 -0
  155. package/src/tempo/client/Session.test.ts +1 -0
  156. package/src/tempo/client/Session.ts +1 -0
  157. package/src/tempo/client/SessionManager.test.ts +28 -0
  158. package/src/tempo/client/SessionManager.ts +2 -1
  159. package/src/tempo/internal/auto-swap.test.ts +1 -0
  160. package/src/tempo/internal/auto-swap.ts +1 -0
  161. package/src/tempo/internal/defaults.test.ts +1 -0
  162. package/src/tempo/internal/fee-payer.test.ts +1 -0
  163. package/src/tempo/internal/fee-payer.ts +1 -0
  164. package/src/tempo/server/Charge.test.ts +1 -0
  165. package/src/tempo/server/Charge.ts +1 -0
  166. package/src/tempo/server/Session.test.ts +1 -0
  167. package/src/tempo/server/Session.ts +1 -0
  168. package/src/tempo/server/Sse.test.ts +1 -0
  169. package/src/tempo/server/internal/transport.test.ts +1 -0
  170. package/src/tempo/session/Chain.test.ts +1 -0
  171. package/src/tempo/session/Chain.ts +1 -0
  172. package/src/tempo/session/Channel.test.ts +1 -0
  173. package/src/tempo/session/ChannelStore.test.ts +1 -0
  174. package/src/tempo/session/ChannelStore.ts +1 -0
  175. package/src/tempo/session/Receipt.test.ts +1 -0
  176. package/src/tempo/session/Receipt.ts +1 -0
  177. package/src/tempo/session/Sse.test.ts +1 -0
  178. package/src/tempo/session/Sse.ts +1 -0
  179. package/src/tempo/session/Voucher.test.ts +1 -0
  180. package/src/tempo/session/Voucher.ts +1 -0
  181. package/src/viem/Account.test.ts +1 -0
  182. package/src/viem/Client.test.ts +1 -0
  183. package/src/viem/Client.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Client.js","sourceRoot":"","sources":["../../src/viem/Client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,YAAY,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAGzC,MAAM,UAAU,WAAW,CACzB,UAOC;IAED,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;IAE5D,IAAI,SAAS,EAAE,CAAC;QACd,+EAA+E;QAC/E,gFAAgF;QAChF,+EAA+E;QAC/E,kFAAkF;QAClF,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,WAAW;YAAE,OAAO,SAAS,CAAA;QACzD,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAA;YAEtC,oFAAoF;YACpF,IAAI,WAAW,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;gBACvD,MAAM,GAAG,GAAI,MAAM,CAAC,SAA8B,CAAC,GAAG,CAAA;gBACtD,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,OAAO,GAAG,YAAY,CAAC;wBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;wBACnB,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;qBACtD,CAAC,CAAA;oBACF,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;gBACnF,CAAC;YACH,CAAC;YAED,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW;gBAAE,OAAO,MAAM,CAAA;YAChF,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE;gBAC/B,KAAK,EAAE;oBACL,GAAG,KAAK;oBACR,GAAG,MAAM,CAAC,KAAK;oBACf,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,UAAU;oBACxD,yBAAyB,EACvB,MAAM,CAAC,KAAK,EAAE,yBAAyB,IAAI,KAAK,CAAC,yBAAyB;oBAC5E,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW;wBACjD,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW;wBAC1B,CAAC,CAAC,KAAK,CAAC,WAAW;iBACC;aACzB,CAAC,CAAA;QACJ,CAAC,CAAA;IACH,CAAC;IAED,OAAO,CAAC,EAAE,OAAO,EAAoC,EAAE,EAAE;QACvD,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;QACrD,MAAM,eAAe,GAAG,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAE,CAAA;QAClE,MAAM,GAAG,GAAG,MAAM,CAAC,eAAsC,CAAC,CAAA;QAC1D,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,eAAe,IAAI,CAAC,CAAA;QAC3F,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACtF,OAAO,YAAY,CAAC;YAClB,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,eAAe,EAAW;YACjD,SAAS;SACV,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"Client.js","sourceRoot":"","sources":["../../src/viem/Client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,YAAY,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAIzC,MAAM,UAAU,WAAW,CACzB,UAOC;IAED,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;IAE5D,IAAI,SAAS,EAAE,CAAC;QACd,+EAA+E;QAC/E,gFAAgF;QAChF,+EAA+E;QAC/E,kFAAkF;QAClF,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,WAAW;YAAE,OAAO,SAAS,CAAA;QACzD,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAA;YAEtC,oFAAoF;YACpF,IAAI,WAAW,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;gBACvD,MAAM,GAAG,GAAI,MAAM,CAAC,SAA8B,CAAC,GAAG,CAAA;gBACtD,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,OAAO,GAAG,YAAY,CAAC;wBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;wBACnB,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;qBACtD,CAAC,CAAA;oBACF,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;gBACnF,CAAC;YACH,CAAC;YAED,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW;gBAAE,OAAO,MAAM,CAAA;YAChF,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE;gBAC/B,KAAK,EAAE;oBACL,GAAG,KAAK;oBACR,GAAG,MAAM,CAAC,KAAK;oBACf,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,UAAU;oBACxD,yBAAyB,EACvB,MAAM,CAAC,KAAK,EAAE,yBAAyB,IAAI,KAAK,CAAC,yBAAyB;oBAC5E,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW;wBACjD,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW;wBAC1B,CAAC,CAAC,KAAK,CAAC,WAAW;iBACC;aACzB,CAAC,CAAA;QACJ,CAAC,CAAA;IACH,CAAC;IAED,OAAO,CAAC,EAAE,OAAO,EAAoC,EAAE,EAAE;QACvD,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;QACrD,MAAM,eAAe,GAAG,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAE,CAAA;QAClE,MAAM,GAAG,GAAG,MAAM,CAAC,eAAsC,CAAC,CAAA;QAC1D,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,eAAe,IAAI,CAAC,CAAA;QAC3F,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACtF,OAAO,YAAY,CAAC;YAClB,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,eAAe,EAAW;YACjD,SAAS;SACV,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mppx",
3
3
  "type": "module",
4
- "version": "0.4.8",
4
+ "version": "0.4.9",
5
5
  "main": "./dist/index.js",
6
6
  "license": "MIT",
7
7
  "files": [
package/src/BodyDigest.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Base64, Bytes, Hash } from 'ox'
2
+
2
3
  import { constantTimeEqual } from './internal/constantTimeEqual.js'
3
4
 
4
5
  /**
@@ -1,4 +1,5 @@
1
1
  import { assertType, describe, expectTypeOf, test } from 'vitest'
2
+
2
3
  import * as Challenge from './Challenge.js'
3
4
  import { Method } from './index.js'
4
5
  import * as Methods from './tempo/Methods.js'
package/src/Challenge.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Base64, Bytes, Hash } from 'ox'
2
+
2
3
  import { constantTimeEqual } from './internal/constantTimeEqual.js'
3
4
  import type { OneOf } from './internal/types.js'
4
5
  import type * as Method from './Method.js'
package/src/Credential.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Base64 } from 'ox'
2
+
2
3
  import * as Challenge from './Challenge.js'
3
4
  import * as PaymentRequest from './PaymentRequest.js'
4
5
 
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from 'vitest'
2
+
2
3
  import {
3
4
  AmountExceedsDepositError,
4
5
  BadRequestError,
@@ -41,9 +42,8 @@ describe('MalformedCredentialError', () => {
41
42
  })
42
43
 
43
44
  test('with reason', () => {
44
- expect(
45
- errorSnapshot(new MalformedCredentialError({ reason: 'invalid base64url' })),
46
- ).toMatchInlineSnapshot(`
45
+ expect(errorSnapshot(new MalformedCredentialError({ reason: 'invalid base64url' })))
46
+ .toMatchInlineSnapshot(`
47
47
  {
48
48
  "message": "Credential is malformed: invalid base64url.",
49
49
  "name": "MalformedCredentialError",
@@ -89,9 +89,8 @@ describe('InvalidChallengeError', () => {
89
89
  })
90
90
 
91
91
  test('with id and reason', () => {
92
- expect(
93
- errorSnapshot(new InvalidChallengeError({ id: 'abc123', reason: 'already used' })),
94
- ).toMatchInlineSnapshot(`
92
+ expect(errorSnapshot(new InvalidChallengeError({ id: 'abc123', reason: 'already used' })))
93
+ .toMatchInlineSnapshot(`
95
94
  {
96
95
  "message": "Challenge "abc123" is invalid: already used.",
97
96
  "name": "InvalidChallengeError",
@@ -115,9 +114,8 @@ describe('VerificationFailedError', () => {
115
114
  })
116
115
 
117
116
  test('with reason', () => {
118
- expect(
119
- errorSnapshot(new VerificationFailedError({ reason: 'invalid signature' })),
120
- ).toMatchInlineSnapshot(`
117
+ expect(errorSnapshot(new VerificationFailedError({ reason: 'invalid signature' })))
118
+ .toMatchInlineSnapshot(`
121
119
  {
122
120
  "message": "Payment verification failed: invalid signature.",
123
121
  "name": "VerificationFailedError",
@@ -141,9 +139,8 @@ describe('PaymentExpiredError', () => {
141
139
  })
142
140
 
143
141
  test('with expires', () => {
144
- expect(
145
- errorSnapshot(new PaymentExpiredError({ expires: '2025-01-26T12:00:00Z' })),
146
- ).toMatchInlineSnapshot(`
142
+ expect(errorSnapshot(new PaymentExpiredError({ expires: '2025-01-26T12:00:00Z' })))
143
+ .toMatchInlineSnapshot(`
147
144
  {
148
145
  "message": "Payment expired at 2025-01-26T12:00:00Z.",
149
146
  "name": "PaymentExpiredError",
@@ -167,9 +164,8 @@ describe('PaymentRequiredError', () => {
167
164
  })
168
165
 
169
166
  test('with description', () => {
170
- expect(
171
- errorSnapshot(new PaymentRequiredError({ description: 'API access fee' })),
172
- ).toMatchInlineSnapshot(`
167
+ expect(errorSnapshot(new PaymentRequiredError({ description: 'API access fee' })))
168
+ .toMatchInlineSnapshot(`
173
169
  {
174
170
  "message": "Payment is required (API access fee).",
175
171
  "name": "PaymentRequiredError",
@@ -193,9 +189,8 @@ describe('InvalidPayloadError', () => {
193
189
  })
194
190
 
195
191
  test('with reason', () => {
196
- expect(
197
- errorSnapshot(new InvalidPayloadError({ reason: 'missing signature field' })),
198
- ).toMatchInlineSnapshot(`
192
+ expect(errorSnapshot(new InvalidPayloadError({ reason: 'missing signature field' })))
193
+ .toMatchInlineSnapshot(`
199
194
  {
200
195
  "message": "Credential payload is invalid: missing signature field.",
201
196
  "name": "InvalidPayloadError",
@@ -219,9 +214,8 @@ describe('BadRequestError', () => {
219
214
  })
220
215
 
221
216
  test('with reason', () => {
222
- expect(
223
- errorSnapshot(new BadRequestError({ reason: 'cannot combine hash type with feePayer' })),
224
- ).toMatchInlineSnapshot(`
217
+ expect(errorSnapshot(new BadRequestError({ reason: 'cannot combine hash type with feePayer' })))
218
+ .toMatchInlineSnapshot(`
225
219
  {
226
220
  "message": "Bad request: cannot combine hash type with feePayer.",
227
221
  "name": "BadRequestError",
@@ -245,9 +239,8 @@ describe('PaymentInsufficientError', () => {
245
239
  })
246
240
 
247
241
  test('with reason', () => {
248
- expect(
249
- errorSnapshot(new PaymentInsufficientError({ reason: 'expected 1000, received 500' })),
250
- ).toMatchInlineSnapshot(`
242
+ expect(errorSnapshot(new PaymentInsufficientError({ reason: 'expected 1000, received 500' })))
243
+ .toMatchInlineSnapshot(`
251
244
  {
252
245
  "message": "Payment insufficient: expected 1000, received 500.",
253
246
  "name": "PaymentInsufficientError",
@@ -271,9 +264,8 @@ describe('PaymentMethodUnsupportedError', () => {
271
264
  })
272
265
 
273
266
  test('with method', () => {
274
- expect(
275
- errorSnapshot(new PaymentMethodUnsupportedError({ method: 'bitcoin' })),
276
- ).toMatchInlineSnapshot(`
267
+ expect(errorSnapshot(new PaymentMethodUnsupportedError({ method: 'bitcoin' })))
268
+ .toMatchInlineSnapshot(`
277
269
  {
278
270
  "message": "Payment method "bitcoin" is not supported.",
279
271
  "name": "PaymentMethodUnsupportedError",
@@ -297,9 +289,8 @@ describe('InsufficientBalanceError', () => {
297
289
  })
298
290
 
299
291
  test('with reason', () => {
300
- expect(
301
- errorSnapshot(new InsufficientBalanceError({ reason: 'requested 500, available 100' })),
302
- ).toMatchInlineSnapshot(`
292
+ expect(errorSnapshot(new InsufficientBalanceError({ reason: 'requested 500, available 100' })))
293
+ .toMatchInlineSnapshot(`
303
294
  {
304
295
  "message": "Insufficient balance: requested 500, available 100.",
305
296
  "name": "InsufficientBalanceError",
@@ -323,9 +314,8 @@ describe('InvalidSignatureError', () => {
323
314
  })
324
315
 
325
316
  test('with reason', () => {
326
- expect(
327
- errorSnapshot(new InvalidSignatureError({ reason: 'ECDSA recovery failed' })),
328
- ).toMatchInlineSnapshot(`
317
+ expect(errorSnapshot(new InvalidSignatureError({ reason: 'ECDSA recovery failed' })))
318
+ .toMatchInlineSnapshot(`
329
319
  {
330
320
  "message": "Invalid signature: ECDSA recovery failed.",
331
321
  "name": "InvalidSignatureError",
@@ -401,9 +391,8 @@ describe('ChannelClosedError', () => {
401
391
  })
402
392
 
403
393
  test('with reason', () => {
404
- expect(
405
- errorSnapshot(new ChannelClosedError({ reason: 'channel is finalized on-chain' })),
406
- ).toMatchInlineSnapshot(`
394
+ expect(errorSnapshot(new ChannelClosedError({ reason: 'channel is finalized on-chain' })))
395
+ .toMatchInlineSnapshot(`
407
396
  {
408
397
  "message": "Channel closed: channel is finalized on-chain.",
409
398
  "name": "ChannelClosedError",
@@ -427,9 +416,8 @@ describe('PaymentActionRequiredError', () => {
427
416
  })
428
417
 
429
418
  test('with reason', () => {
430
- expect(
431
- errorSnapshot(new PaymentActionRequiredError({ reason: 'requires_action' })),
432
- ).toMatchInlineSnapshot(`
419
+ expect(errorSnapshot(new PaymentActionRequiredError({ reason: 'requires_action' })))
420
+ .toMatchInlineSnapshot(`
433
421
  {
434
422
  "message": "Payment requires action: requires_action.",
435
423
  "name": "PaymentActionRequiredError",
@@ -1,4 +1,5 @@
1
1
  import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
2
+
2
3
  import * as Expires from './Expires.js'
3
4
 
4
5
  const FIXED_NOW = new Date('2025-06-15T12:00:00.000Z').getTime()
@@ -1,4 +1,5 @@
1
1
  import { Base64, Json } from 'ox'
2
+
2
3
  import type { Compute } from './internal/types.js'
3
4
  import type * as Method from './Method.js'
4
5
  import type * as z from './zod.js'
package/src/Receipt.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Base64 } from 'ox'
2
+
2
3
  import * as z from './zod.js'
3
4
 
4
5
  /**
@@ -1,4 +1,5 @@
1
1
  import { expectTypeOf, test } from 'vitest'
2
+
2
3
  import * as Store from './Store.js'
3
4
 
4
5
  test('default Store accepts any string key', () => {
package/src/Store.test.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from 'vitest'
2
+
2
3
  import * as Store from './Store.js'
3
4
 
4
5
  const nested = {
@@ -7,16 +8,16 @@ const nested = {
7
8
  meta: { active: true, tags: ['a', 'b'] },
8
9
  }
9
10
 
10
- function fakeKv(): Store.cloudflare.Parameters {
11
+ function fakeKv() {
11
12
  const map = new Map<string, string>()
12
13
  return {
13
- async get(key) {
14
+ async get(key: string) {
14
15
  return map.get(key) ?? null
15
16
  },
16
- async put(key, value) {
17
+ async put(key: string, value: string) {
17
18
  map.set(key, value)
18
19
  },
19
- async delete(key) {
20
+ async delete(key: string) {
20
21
  map.delete(key)
21
22
  },
22
23
  }
@@ -25,6 +26,17 @@ function fakeKv(): Store.cloudflare.Parameters {
25
26
  describe.each([
26
27
  { label: 'memory', create: () => Store.memory() },
27
28
  { label: 'cloudflare', create: () => Store.cloudflare(fakeKv()) },
29
+ {
30
+ label: 'redis',
31
+ create: () => {
32
+ const kv = fakeKv()
33
+ return Store.redis({
34
+ get: kv.get,
35
+ set: kv.put,
36
+ del: (key) => kv.delete(key),
37
+ })
38
+ },
39
+ },
28
40
  {
29
41
  label: 'upstash',
30
42
  create: () => {
@@ -64,6 +76,20 @@ describe.each([
64
76
  })
65
77
 
66
78
  describe('json roundtrip behavior', () => {
79
+ test('cloudflare json-roundtrips nested objects', async () => {
80
+ const store = Store.cloudflare(fakeKv())
81
+ const value = { a: [1, { b: 'c' }], d: null }
82
+ await store.put('k', value)
83
+ expect(await store.get('k')).toEqual(value)
84
+ })
85
+
86
+ test('cloudflare roundtrips BigInt values', async () => {
87
+ const store = Store.cloudflare(fakeKv())
88
+ const value = { amount: 1000000000000000000n, nested: { big: 42n } }
89
+ await store.put('k', value)
90
+ expect(await store.get('k')).toEqual(value)
91
+ })
92
+
67
93
  test('memory json-roundtrips nested objects', async () => {
68
94
  const store = Store.memory()
69
95
  const value = { a: [1, { b: 'c' }], d: null }
@@ -71,13 +97,37 @@ describe('json roundtrip behavior', () => {
71
97
  expect(await store.get('k')).toEqual(value)
72
98
  })
73
99
 
74
- test('cloudflare json-roundtrips nested objects', async () => {
75
- const store = Store.cloudflare(fakeKv())
100
+ test('memory roundtrips BigInt values', async () => {
101
+ const store = Store.memory()
102
+ const value = { amount: 1000000000000000000n, nested: { big: 42n } }
103
+ await store.put('k', value)
104
+ expect(await store.get('k')).toEqual(value)
105
+ })
106
+
107
+ test('redis json-roundtrips nested objects', async () => {
108
+ const kv = fakeKv()
109
+ const store = Store.redis({
110
+ get: kv.get,
111
+ set: kv.put,
112
+ del: (key) => kv.delete(key),
113
+ })
76
114
  const value = { a: [1, { b: 'c' }], d: null }
77
115
  await store.put('k', value)
78
116
  expect(await store.get('k')).toEqual(value)
79
117
  })
80
118
 
119
+ test('redis roundtrips BigInt values', async () => {
120
+ const kv = fakeKv()
121
+ const store = Store.redis({
122
+ get: kv.get,
123
+ set: kv.put,
124
+ del: (key) => kv.delete(key),
125
+ })
126
+ const value = { amount: 1000000000000000000n, nested: { big: 42n } }
127
+ await store.put('k', value)
128
+ expect(await store.get('k')).toEqual(value)
129
+ })
130
+
81
131
  test('upstash passes values through without json serialization', async () => {
82
132
  const kv = fakeKv()
83
133
  const store = Store.upstash({
package/src/Store.ts CHANGED
@@ -62,6 +62,31 @@ export function memory(): Store {
62
62
  })
63
63
  }
64
64
 
65
+ /** Wraps a standard Redis client (ioredis, node-redis, Valkey). */
66
+ export function redis(client: redis.Parameters): Store {
67
+ return from({
68
+ async get(key) {
69
+ const raw = await client.get(key)
70
+ if (raw == null) return null as any
71
+ return Json.parse(raw)
72
+ },
73
+ async put(key, value) {
74
+ await client.set(key, Json.stringify(value))
75
+ },
76
+ async delete(key) {
77
+ await client.del(key)
78
+ },
79
+ })
80
+ }
81
+
82
+ export declare namespace redis {
83
+ export type Parameters = {
84
+ get: (key: string) => Promise<string | null>
85
+ set: (key: string, value: string) => Promise<unknown>
86
+ del: (key: string) => Promise<unknown>
87
+ }
88
+ }
89
+
65
90
  /** Wraps an Upstash Redis instance (e.g. Vercel KV). */
66
91
  export function upstash(redis: upstash.Parameters): Store {
67
92
  return from({
@@ -55,50 +55,85 @@ export function createKeychain(account = 'main') {
55
55
  async list(): Promise<string[]> {
56
56
  const platform = os.platform()
57
57
  if (platform === 'darwin') {
58
- const { stdout, error } = await execCommand('security', ['dump-keychain'])
59
- if (error) return []
60
- const accounts: string[] = []
61
- const blocks = stdout.split('keychain:')
62
- for (const block of blocks) {
63
- const serviceMatch = block.match(/"svce"<blob>="([^"]*)"/)
64
- const accountMatch = block.match(/"acct"<blob>="([^"]*)"/)
65
- if (serviceMatch?.[1] === service && accountMatch?.[1]) accounts.push(accountMatch[1])
66
- }
67
- return accounts
58
+ const { stdout, error } = await execCommand('security', ['dump-keychain'])
59
+ if (error) return []
60
+ const accounts: string[] = []
61
+ const blocks = stdout.split('keychain:')
62
+ for (const block of blocks) {
63
+ const serviceMatch = block.match(/"svce"<blob>="([^"]*)"/)
64
+ const accountMatch = block.match(/"acct"<blob>="([^"]*)"/)
65
+ if (serviceMatch?.[1] === service && accountMatch?.[1]) accounts.push(accountMatch[1])
66
+ }
67
+ return accounts
68
68
  }
69
69
  if (platform === 'linux') {
70
- const { stdout, stderr, error } = await execCommand('secret-tool', ['search', '--all', '--unlock', 'service', service])
71
- if (error) return []
72
- const combined = `${stdout}\n${stderr}`
73
- const accounts: string[] = []
74
- const matches = combined.matchAll(/\baccount = (.+)/g)
75
- for (const match of matches) if (match[1]) accounts.push(match[1])
76
- return accounts
70
+ const { stdout, stderr, error } = await execCommand('secret-tool', [
71
+ 'search',
72
+ '--all',
73
+ '--unlock',
74
+ 'service',
75
+ service,
76
+ ])
77
+ if (error) return []
78
+ const combined = `${stdout}\n${stderr}`
79
+ const accounts: string[] = []
80
+ const matches = combined.matchAll(/\baccount = (.+)/g)
81
+ for (const match of matches) if (match[1]) accounts.push(match[1])
82
+ return accounts
77
83
  }
78
84
  throw new Error(`Unsupported platform: ${platform}`)
79
85
  },
80
86
  async get(): Promise<string | undefined> {
81
87
  const platform = os.platform()
82
88
  if (platform === 'darwin') {
83
- const { stdout, error } = await execCommand('security', ['find-generic-password', '-s', service, '-a', account, '-w'])
84
- return error ? undefined : stdout
89
+ const { stdout, error } = await execCommand('security', [
90
+ 'find-generic-password',
91
+ '-s',
92
+ service,
93
+ '-a',
94
+ account,
95
+ '-w',
96
+ ])
97
+ return error ? undefined : stdout
85
98
  }
86
99
  if (platform === 'linux') {
87
- const { stdout, error } = await execCommand('secret-tool', ['lookup', 'service', service, 'account', account])
88
- return error ? undefined : stdout || undefined
100
+ const { stdout, error } = await execCommand('secret-tool', [
101
+ 'lookup',
102
+ 'service',
103
+ service,
104
+ 'account',
105
+ account,
106
+ ])
107
+ return error ? undefined : stdout || undefined
89
108
  }
90
109
  throw new Error(`Unsupported platform: ${platform}`)
91
110
  },
92
111
  async set(value: string): Promise<void> {
93
112
  const platform = os.platform()
94
113
  if (platform === 'darwin') {
95
- await execCommand('security', ['delete-generic-password', '-s', service, '-a', account])
96
- const { error } = await execCommand('security', ['add-generic-password', '-s', service, '-a', account, '-w', value])
97
- if (error) throw error
98
- return
114
+ await execCommand('security', ['delete-generic-password', '-s', service, '-a', account])
115
+ const { error } = await execCommand('security', [
116
+ 'add-generic-password',
117
+ '-s',
118
+ service,
119
+ '-a',
120
+ account,
121
+ '-w',
122
+ value,
123
+ ])
124
+ if (error) throw error
125
+ return
99
126
  }
100
127
  if (platform === 'linux') {
101
- const proc = child.execFile('secret-tool', ['store', '--label', `${service} ${account}`, 'service', service, 'account', account])
128
+ const proc = child.execFile('secret-tool', [
129
+ 'store',
130
+ '--label',
131
+ `${service} ${account}`,
132
+ 'service',
133
+ service,
134
+ 'account',
135
+ account,
136
+ ])
102
137
  proc.stdin?.write(value)
103
138
  proc.stdin?.end()
104
139
  return new Promise((resolve, reject) => {
@@ -114,12 +149,12 @@ export function createKeychain(account = 'main') {
114
149
  async delete(): Promise<void> {
115
150
  const platform = os.platform()
116
151
  if (platform === 'darwin') {
117
- await execCommand('security', ['delete-generic-password', '-s', service, '-a', account])
118
- return
152
+ await execCommand('security', ['delete-generic-password', '-s', service, '-a', account])
153
+ return
119
154
  }
120
155
  if (platform === 'linux') {
121
- await execCommand('secret-tool', ['clear', 'service', service, 'account', account])
122
- return
156
+ await execCommand('secret-tool', ['clear', 'service', service, 'account', account])
157
+ return
123
158
  }
124
159
  throw new Error(`Unsupported platform: ${platform}`)
125
160
  },
@@ -2,6 +2,7 @@ import { spawnSync } from 'node:child_process'
2
2
  import * as fs from 'node:fs'
3
3
  import * as os from 'node:os'
4
4
  import * as path from 'node:path'
5
+
5
6
  import { parseUnits } from 'viem'
6
7
  import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
7
8
  import { Addresses } from 'viem/tempo'
@@ -10,10 +11,11 @@ import * as Http from '~test/Http.js'
10
11
  import { rpcUrl } from '~test/tempo/prool.js'
11
12
  import { deployEscrow } from '~test/tempo/session.js'
12
13
  import { accounts, asset, client, fundAccount } from '~test/tempo/viem.js'
14
+
13
15
  import * as Credential from '../Credential.js'
14
- import * as Store from '../Store.js'
15
16
  import * as Mppx_server from '../server/Mppx.js'
16
17
  import { toNodeListener } from '../server/Mppx.js'
18
+ import * as Store from '../Store.js'
17
19
  import { stripe as stripe_server } from '../stripe/server/Methods.js'
18
20
  import { tempo } from '../tempo/server/Methods.js'
19
21
  import type { SessionCredentialPayload } from '../tempo/session/Types.js'
package/src/cli/cli.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  import * as fs from 'node:fs'
2
2
  import { createRequire } from 'node:module'
3
3
  import * as path from 'node:path'
4
+
4
5
  import { Cli, Errors, z } from 'incur'
5
6
  import { Base64 } from 'ox'
6
7
  import { type Address, createClient, http } from 'viem'
7
8
  import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
8
9
  import { tempo as tempoMainnet } from 'viem/chains'
10
+
9
11
  import * as Challenge from '../Challenge.js'
12
+ import { normalizeHeaders } from '../client/internal/Fetch.js'
10
13
  import * as Mppx from '../client/Mppx.js'
11
14
  import { createDefaultStore, createKeychain, resolveAccountName } from './account.js'
12
15
  import { loadConfig, resolvePlugin } from './internal.js'
@@ -312,7 +315,7 @@ const cli = Cli.create('mppx', {
312
315
 
313
316
  // Send credential and get response
314
317
  const credentialHeaders = {
315
- ...(init.headers as Record<string, string>),
318
+ ...normalizeHeaders(init.headers),
316
319
  Authorization: credential,
317
320
  }
318
321
  plugin?.prepareCredentialRequest?.({ challenge, credential, headers: credentialHeaders })
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'node:fs'
2
2
  import * as os from 'node:os'
3
3
  import * as path from 'node:path'
4
+
4
5
  import { defineConfig } from './config.js'
5
6
  import { loadConfig } from './internal.js'
6
7
 
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs'
2
2
  import * as path from 'node:path'
3
+
3
4
  import type * as Challenge from '../Challenge.js'
4
5
  import type * as Method from '../Method.js'
5
6
  import type { Config } from './config.js'
@@ -1,4 +1,5 @@
1
1
  import { Errors, z } from 'incur'
2
+
2
3
  import { stripe as stripeMethods } from '../../stripe/client/index.js'
3
4
  import { pc } from '../utils.js'
4
5
  import { createPlugin } from './plugin.js'
@@ -3,11 +3,14 @@ import * as fs from 'node:fs'
3
3
  import { createRequire } from 'node:module'
4
4
  import * as os from 'node:os'
5
5
  import * as path from 'node:path'
6
+
6
7
  import { Errors, z } from 'incur'
7
8
  import { Base64 } from 'ox'
8
9
  import type { Address } from 'viem'
9
10
  import { createClient, http } from 'viem'
10
11
  import { privateKeyToAccount } from 'viem/accounts'
12
+
13
+ import { normalizeHeaders } from '../../client/internal/Fetch.js'
11
14
  import * as Credential from '../../Credential.js'
12
15
  import { tempo as tempoMethods } from '../../tempo/client/index.js'
13
16
  import type { SessionCredentialPayload } from '../../tempo/session/Types.js'
@@ -610,7 +613,7 @@ async function closeChannel(opts: {
610
613
  const closeRes = await globalThis.fetch(opts.fetchUrl, {
611
614
  ...opts.fetchInit,
612
615
  headers: {
613
- ...(opts.fetchInit.headers as Record<string, string>),
616
+ ...normalizeHeaders(opts.fetchInit.headers),
614
617
  Authorization: closeCred,
615
618
  },
616
619
  })
package/src/cli/utils.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as readline from 'node:readline'
2
+
2
3
  import type { Chain } from 'viem'
3
4
  import { type Address, createClient, http } from 'viem'
4
5
  import { tempo as tempoMainnet, tempoModerato } from 'viem/chains'
@@ -1,5 +1,6 @@
1
1
  import type { Account } from 'viem'
2
2
  import { describe, expectTypeOf, test } from 'vitest'
3
+
3
4
  import * as Method from '../Method.js'
4
5
  import { charge } from '../tempo/client/Charge.js'
5
6
  import { tempo } from '../tempo/client/Methods.js'
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test, vi } from 'vitest'
2
+
2
3
  import * as Fetch from './Fetch.js'
3
4
 
4
5
  const noopMethod = {
@@ -1,5 +1,6 @@
1
1
  import type { Account } from 'viem'
2
2
  import { describe, expectTypeOf, test } from 'vitest'
3
+
3
4
  import { charge } from '../../tempo/client/Charge.js'
4
5
  import * as Fetch from './Fetch.js'
5
6
 
@@ -6,6 +6,7 @@ import { describe, expect, test, vi } from 'vitest'
6
6
  import * as Http from '~test/Http.js'
7
7
  import { rpcUrl } from '~test/tempo/prool.js'
8
8
  import { accounts, asset, chain, client, http } from '~test/tempo/viem.js'
9
+
9
10
  import * as Fetch from './Fetch.js'
10
11
 
11
12
  const realm = 'api.example.com'
@@ -193,7 +193,7 @@ export function restore(): void {
193
193
  }
194
194
 
195
195
  /** @internal Normalizes headers to a plain object for spreading. */
196
- function normalizeHeaders(headers: unknown): Record<string, string> {
196
+ export function normalizeHeaders(headers: unknown): Record<string, string> {
197
197
  if (!headers) return {}
198
198
  if (headers instanceof Headers) {
199
199
  const result: Record<string, string> = {}
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from 'vitest'
2
+
2
3
  import { constantTimeEqual } from './constantTimeEqual.js'
3
4
 
4
5
  describe('constantTimeEqual', () => {