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.
- package/CHANGELOG.md +19 -0
- package/dist/Credential.d.ts +12 -0
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Credential.js +22 -4
- package/dist/Credential.js.map +1 -1
- package/dist/Method.d.ts +4 -0
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +2 -1
- package/dist/Method.js.map +1 -1
- package/dist/cli/account.d.ts.map +1 -1
- package/dist/cli/account.js +12 -2
- package/dist/cli/account.js.map +1 -1
- package/dist/proxy/Proxy.d.ts.map +1 -1
- package/dist/proxy/Proxy.js +52 -8
- package/dist/proxy/Proxy.js.map +1 -1
- package/dist/proxy/internal/Route.d.ts.map +1 -1
- package/dist/proxy/internal/Route.js +7 -3
- package/dist/proxy/internal/Route.js.map +1 -1
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +90 -71
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Transport.d.ts +5 -1
- package/dist/server/Transport.d.ts.map +1 -1
- package/dist/server/Transport.js +52 -7
- package/dist/server/Transport.js.map +1 -1
- package/dist/server/internal/html/config.d.ts +7 -0
- package/dist/server/internal/html/config.d.ts.map +1 -0
- package/dist/server/internal/html/config.js +3 -0
- package/dist/server/internal/html/config.js.map +1 -0
- package/dist/server/internal/html/serviceWorker.gen.d.ts +2 -0
- package/dist/server/internal/html/serviceWorker.gen.d.ts.map +1 -0
- package/dist/server/internal/html/serviceWorker.gen.js +3 -0
- package/dist/server/internal/html/serviceWorker.gen.js.map +1 -0
- package/dist/stripe/server/Charge.d.ts +5 -0
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +14 -6
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +2 -0
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -0
- package/dist/stripe/server/internal/html.gen.js +3 -0
- package/dist/stripe/server/internal/html.gen.js.map +1 -0
- package/dist/tempo/internal/proof.d.ts +6 -0
- package/dist/tempo/internal/proof.d.ts.map +1 -1
- package/dist/tempo/internal/proof.js +15 -0
- package/dist/tempo/internal/proof.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +10 -3
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +38 -10
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js +3 -2
- package/dist/tempo/server/Session.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +2 -0
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -0
- package/dist/tempo/server/internal/html.gen.js +3 -0
- package/dist/tempo/server/internal/html.gen.js.map +1 -0
- package/dist/tempo/server/internal/transport.d.ts +1 -1
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +45 -58
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/package.json +2 -2
- package/src/Credential.ts +28 -4
- package/src/Method.ts +6 -1
- package/src/cli/account.ts +13 -2
- package/src/env.d.ts +1 -0
- package/src/mcp-sdk/server/Transport.test.ts +6 -0
- package/src/middlewares/elysia.test.ts +3 -5
- package/src/middlewares/express.test.ts +3 -5
- package/src/middlewares/hono.test.ts +8 -5
- package/src/middlewares/nextjs.test.ts +3 -5
- package/src/proxy/Proxy.test.ts +188 -1
- package/src/proxy/Proxy.ts +58 -9
- package/src/proxy/internal/Route.test.ts +9 -0
- package/src/proxy/internal/Route.ts +5 -2
- package/src/server/Mppx.test.ts +171 -18
- package/src/server/Mppx.ts +120 -79
- package/src/server/Transport.test.ts +16 -2
- package/src/server/Transport.ts +61 -7
- package/src/server/internal/html/config.ts +8 -0
- package/src/server/internal/html/serviceWorker.client.ts +28 -0
- package/src/server/internal/html/serviceWorker.gen.ts +2 -0
- package/src/server/internal/html/serviceWorker.ts +27 -0
- package/src/server/internal/html/tsconfig.worker.client.json +8 -0
- package/src/server/internal/html/tsconfig.worker.json +8 -0
- package/src/stripe/server/Charge.ts +19 -5
- package/src/stripe/server/internal/html/main.ts +106 -0
- package/src/stripe/server/internal/html/node_modules/.bin/mppx.src +21 -0
- package/src/stripe/server/internal/html/package.json +9 -0
- package/src/stripe/server/internal/html/stripe-js-pure.d.ts +7 -0
- package/src/stripe/server/internal/html/tsconfig.json +8 -0
- package/src/stripe/server/internal/html.gen.ts +2 -0
- package/src/tempo/internal/proof.test.ts +47 -0
- package/src/tempo/internal/proof.ts +16 -0
- package/src/tempo/server/Charge.test.ts +298 -0
- package/src/tempo/server/Charge.ts +61 -12
- package/src/tempo/server/Session.ts +3 -2
- package/src/tempo/server/internal/html/main.ts +71 -0
- package/src/tempo/server/internal/html/node_modules/.bin/mppx.src +21 -0
- package/src/tempo/server/internal/html/package.json +10 -0
- package/src/tempo/server/internal/html/tsconfig.json +8 -0
- package/src/tempo/server/internal/html.gen.ts +2 -0
- package/src/tempo/server/internal/transport.test.ts +37 -31
- package/src/tempo/server/internal/transport.ts +44 -58
- package/src/tsconfig.json +1 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { loadStripe } from '@stripe/stripe-js/pure'
|
|
2
|
+
|
|
3
|
+
import type * as Challenge from '../../../../Challenge.js'
|
|
4
|
+
import { stripe } from '../../../../client/index.js'
|
|
5
|
+
import * as Html from '../../../../server/internal/html/config.js'
|
|
6
|
+
import { submitCredential } from '../../../../server/internal/html/serviceWorker.client.js'
|
|
7
|
+
import type { charge as chargeClient } from '../../../../stripe/client/Charge.js'
|
|
8
|
+
import type { charge } from '../../../../stripe/server/Charge.js'
|
|
9
|
+
import type * as Methods from '../../../Methods.js'
|
|
10
|
+
|
|
11
|
+
const data = JSON.parse(document.getElementById(Html.dataId)!.textContent!) as {
|
|
12
|
+
config: NonNullable<charge.Parameters['html']>
|
|
13
|
+
challenge: Challenge.FromMethods<[typeof Methods.charge]>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const root = document.getElementById('root')!
|
|
17
|
+
|
|
18
|
+
const h2 = document.createElement('h2')
|
|
19
|
+
h2.textContent = 'stripe'
|
|
20
|
+
root.appendChild(h2)
|
|
21
|
+
|
|
22
|
+
;(async () => {
|
|
23
|
+
if (import.meta.env.MODE === 'test') {
|
|
24
|
+
const button = document.createElement('button')
|
|
25
|
+
button.textContent = 'Pay'
|
|
26
|
+
root.appendChild(button)
|
|
27
|
+
button.onclick = async () => {
|
|
28
|
+
try {
|
|
29
|
+
button.disabled = true
|
|
30
|
+
const method = stripe({ createToken })[0]
|
|
31
|
+
const credential = await method.createCredential({
|
|
32
|
+
challenge: data.challenge,
|
|
33
|
+
context: { paymentMethod: 'pm_card_visa' },
|
|
34
|
+
})
|
|
35
|
+
await submitCredential(credential)
|
|
36
|
+
} finally {
|
|
37
|
+
button.disabled = false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const stripeJs = await loadStripe(data.config.publishableKey)
|
|
44
|
+
if (!stripeJs) throw new Error('Failed to loadStripe')
|
|
45
|
+
|
|
46
|
+
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
47
|
+
const getAppearance = () => ({
|
|
48
|
+
theme: (darkQuery.matches ? 'night' : 'stripe') as 'night' | 'stripe',
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const elements = stripeJs.elements({
|
|
52
|
+
amount: Number(data.challenge.request.amount),
|
|
53
|
+
appearance: getAppearance(),
|
|
54
|
+
currency: data.challenge.request.currency as string,
|
|
55
|
+
mode: 'payment',
|
|
56
|
+
paymentMethodCreation: 'manual',
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
darkQuery.addEventListener('change', () => {
|
|
60
|
+
elements.update({ appearance: getAppearance() })
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const form = document.createElement('form')
|
|
64
|
+
elements.create('payment').mount(form)
|
|
65
|
+
root.appendChild(form)
|
|
66
|
+
|
|
67
|
+
const button = document.createElement('button')
|
|
68
|
+
button.textContent = 'Pay'
|
|
69
|
+
button.type = 'submit'
|
|
70
|
+
form.appendChild(button)
|
|
71
|
+
|
|
72
|
+
form.onsubmit = async (event) => {
|
|
73
|
+
event.preventDefault()
|
|
74
|
+
button.disabled = true
|
|
75
|
+
try {
|
|
76
|
+
await elements.submit()
|
|
77
|
+
const { paymentMethod, error } = await stripeJs.createPaymentMethod({ elements })
|
|
78
|
+
if (error || !paymentMethod) throw error ?? new Error('Failed to create payment method')
|
|
79
|
+
const method = stripe({ client: stripeJs, createToken })[0]
|
|
80
|
+
const credential = await method.createCredential({
|
|
81
|
+
challenge: data.challenge,
|
|
82
|
+
context: { paymentMethod: paymentMethod.id },
|
|
83
|
+
})
|
|
84
|
+
await submitCredential(credential)
|
|
85
|
+
} finally {
|
|
86
|
+
button.disabled = false
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
})()
|
|
90
|
+
|
|
91
|
+
async function createToken(opts: chargeClient.OnChallengeParameters) {
|
|
92
|
+
const createTokenUrl = new URL(data.config.createTokenUrl, location.origin)
|
|
93
|
+
if (createTokenUrl.origin !== location.origin)
|
|
94
|
+
throw new Error('createTokenUrl must be same-origin')
|
|
95
|
+
const res = await fetch(createTokenUrl, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
headers: { 'Content-Type': 'application/json' },
|
|
98
|
+
body: JSON.stringify(opts),
|
|
99
|
+
})
|
|
100
|
+
if (!res.ok) {
|
|
101
|
+
const text = await res.text().catch(() => '<response body unavailable>')
|
|
102
|
+
throw new Error(`Failed to create SPT (${res.status}): ${text}`)
|
|
103
|
+
}
|
|
104
|
+
const json = (await res.json()) as { spt: string }
|
|
105
|
+
return json.spt
|
|
106
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/runner/work/mppx/mppx/src/node_modules:/home/runner/work/mppx/mppx/node_modules:/home/runner/work/mppx/node_modules:/home/runner/work/node_modules:/home/runner/node_modules:/home/node_modules:/node_modules:/home/runner/work/mppx/mppx/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/runner/work/mppx/mppx/src/node_modules:/home/runner/work/mppx/mppx/node_modules:/home/runner/work/mppx/node_modules:/home/runner/work/node_modules:/home/runner/node_modules:/home/node_modules:/node_modules:/home/runner/work/mppx/mppx/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../mppx/src/bin.ts" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../mppx/src/bin.ts" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Generated — do not edit.
|
|
2
|
+
export const html = "<script>(function(){var e=(e,t)=>()=>(e&&(t=e(e=0)),t),t=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),n=t((e=>{Object.defineProperty(e,`__esModule`,{value:!0});function t(e){\"@babel/helpers - typeof\";return t=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},t(e)}var n=`clover`,r=function(e){return e===3?`v3`:e},i=`https://js.stripe.com`,a=`${i}/${n}/stripe.js`,o=/^https:\\/\\/js\\.stripe\\.com\\/v3\\/?(\\?.*)?$/,s=/^https:\\/\\/js\\.stripe\\.com\\/(v3|[a-z]+)\\/stripe\\.js(\\?.*)?$/,c=`loadStripe.setLoadParameters was called but an existing Stripe.js script already exists in the document; existing script parameters will be used`,l=function(e){return o.test(e)||s.test(e)},u=function(){for(var e=document.querySelectorAll(`script[src^=\"${i}\"]`),t=0;t<e.length;t++){var n=e[t];if(l(n.src))return n}return null},d=function(e){var t=e&&!e.advancedFraudSignals?`?advancedFraudSignals=false`:``,n=document.createElement(`script`);n.src=`${a}${t}`;var r=document.head||document.body;if(!r)throw Error(`Expected document.body not to be null. Stripe.js requires a <body> element.`);return r.appendChild(n),n},f=function(e,t){!e||!e._registerWrapper||e._registerWrapper({name:`stripe-js`,version:`8.9.0`,startTime:t})},p=null,m=null,h=null,g=function(e){return function(t){e(Error(`Failed to load Stripe.js`,{cause:t}))}},_=function(e,t){return function(){window.Stripe?e(window.Stripe):t(Error(`Stripe.js not available`))}},v=function(e){return p===null?(p=new Promise(function(t,n){if(typeof window>`u`||typeof document>`u`){t(null);return}if(window.Stripe&&e&&console.warn(c),window.Stripe){t(window.Stripe);return}try{var r=u();if(r&&e)console.warn(c);else if(!r)r=d(e);else if(r&&h!==null&&m!==null){var i;r.removeEventListener(`load`,h),r.removeEventListener(`error`,m),(i=r.parentNode)==null||i.removeChild(r),r=d(e)}h=_(t,n),m=g(n),r.addEventListener(`load`,h),r.addEventListener(`error`,m)}catch(e){n(e);return}}),p.catch(function(e){return p=null,Promise.reject(e)})):p},y=function(e,i,a){if(e===null)return null;var o=i[0];if(typeof o!=`string`)throw Error(`Expected publishable key to be of type string, got type ${t(o)} instead.`);var s=o.match(/^pk_test/),c=r(e.version),l=n;s&&c!==l&&console.warn(`Stripe.js@${c} was loaded on the page, but @stripe/stripe-js@8.9.0 expected Stripe.js@${l}. This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning`);var u=e.apply(void 0,i);return f(u,a),u},b=function(e){var n=`invalid load parameters; expected object of shape\n\n {advancedFraudSignals: boolean}\n\nbut received\n\n ${JSON.stringify(e)}\n`;if(e===null||t(e)!==`object`)throw Error(n);if(Object.keys(e).length===1&&typeof e.advancedFraudSignals==`boolean`)return e;throw Error(n)},x,S=!1,C=function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];S=!0;var r=Date.now();return v(x).then(function(e){return y(e,t,r)})};C.setLoadParameters=function(e){if(S&&x){var t=b(e);if(Object.keys(t).reduce(function(t,n){return t&&e[n]===x?.[n]},!0))return}if(S)throw Error(`You cannot change load parameters after calling loadStripe`);x=b(e)},e.loadStripe=C})),r=t(((e,t)=>{t.exports=n()})),i,a=e((()=>{i=`0.1.1`}));function o(){return i}var s=e((()=>{a()}));function c(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause?c(e.cause,t):t?null:e}var l,u=e((()=>{s(),l=class e extends Error{static setStaticOptions(t){e.prototype.docsOrigin=t.docsOrigin,e.prototype.showVersion=t.showVersion,e.prototype.version=t.version}constructor(t,n={}){let r=(()=>{if(n.cause instanceof e){if(n.cause.details)return n.cause.details;if(n.cause.shortMessage)return n.cause.shortMessage}return n.cause&&`details`in n.cause&&typeof n.cause.details==`string`?n.cause.details:n.cause?.message?n.cause.message:n.details})(),i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=n.docsOrigin??e.prototype.docsOrigin,o=`${a}${i??``}`,s=!!(n.version??e.prototype.showVersion),c=n.version??e.prototype.version,l=[t||`An error occurred.`,...n.metaMessages?[``,...n.metaMessages]:[],...r||i||s?[``,r?`Details: ${r}`:void 0,i?`See: ${o}`:void 0,s?`Version: ${c}`:void 0]:[]].filter(e=>typeof e==`string`).join(`\n`);super(l,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docs`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsOrigin`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`showVersion`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),this.cause=n.cause,this.details=r,this.docs=o,this.docsOrigin=a,this.docsPath=i,this.shortMessage=t,this.showVersion=s,this.version=c}walk(e){return c(this,e)}},Object.defineProperty(l,`defaultStaticOptions`,{enumerable:!0,configurable:!0,writable:!0,value:{docsOrigin:`https://oxlib.sh`,showVersion:!1,version:`ox@${o()}`}}),l.setStaticOptions(l.defaultStaticOptions)}));function d(e,t){if(v(e)>t)throw new b({givenSize:v(e),maxSize:t})}function f(e,t={}){let{dir:n,size:r=32}=t;if(r===0)return e;if(e.length>r)throw new x({size:e.length,targetSize:r,type:`Bytes`});let i=new Uint8Array(r);for(let t=0;t<r;t++){let a=n===`right`;i[a?t:r-t-1]=e[a?t:e.length-t-1]}return i}var p=e((()=>{S()}));function m(e){if(e===null||typeof e==`boolean`||typeof e==`string`)return JSON.stringify(e);if(typeof e==`number`){if(!Number.isFinite(e))throw TypeError(`Cannot canonicalize non-finite number`);return Object.is(e,-0)?`0`:JSON.stringify(e)}if(typeof e==`bigint`)throw TypeError(`Cannot canonicalize bigint`);if(Array.isArray(e))return`[${e.map(e=>m(e)).join(`,`)}]`;if(typeof e==`object`)return`{${Object.keys(e).sort().reduce((t,n)=>{let r=e[n];return r!==void 0&&t.push(`${JSON.stringify(n)}:${m(r)}`),t},[]).join(`,`)}}`}var h=e((()=>{}));function g(e,t={}){let{size:n}=t,r=y.encode(e);return typeof n==`number`?(d(r,n),_(r,n)):r}function _(e,t){return f(e,{dir:`right`,size:t})}function v(e){return e.length}var y,b,x,S=e((()=>{u(),p(),h(),y=new TextEncoder,b=class extends l{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed \\`${t}\\` bytes. Given size: \\`${e}\\` bytes.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeOverflowError`})}},x=class extends l{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (\\`${e}\\`) exceeds padding size (\\`${t}\\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeExceedsPaddingSizeError`})}}}));S();let C=new TextDecoder,w=Object.fromEntries(Array.from(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`).map((e,t)=>[t,e.charCodeAt(0)]));({...Object.fromEntries(Array.from(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`).map((e,t)=>[e.charCodeAt(0),t]))});function ee(e,t={}){let{pad:n=!0,url:r=!1}=t,i=new Uint8Array(Math.ceil(e.length/3)*4);for(let t=0,n=0;n<e.length;t+=4,n+=3){let r=(e[n]<<16)+(e[n+1]<<8)+(e[n+2]|0);i[t]=w[r>>18],i[t+1]=w[r>>12&63],i[t+2]=w[r>>6&63],i[t+3]=w[r&63]}let a=e.length%3,o=Math.floor(e.length/3)*4+(a&&a+1),s=C.decode(new Uint8Array(i.buffer,0,o));return n&&a===1&&(s+=`==`),n&&a===2&&(s+=`=`),r&&(s=s.replaceAll(`+`,`-`).replaceAll(`/`,`_`)),s}function te(e,t={}){return ee(g(e),t)}function ne(e){return te(m(e),{pad:!1,url:!0})}Object.freeze({status:`aborted`});function T(e,t,n){function r(n,r){if(n._zod||Object.defineProperty(n,`_zod`,{value:{def:r,constr:o,traits:new Set},enumerable:!1}),n._zod.traits.has(e))return;n._zod.traits.add(e),t(n,r);let i=o.prototype,a=Object.keys(i);for(let e=0;e<a.length;e++){let t=a[e];t in n||(n[t]=i[t].bind(n))}}let i=n?.Parent??Object;class a extends i{}Object.defineProperty(a,`name`,{value:e});function o(e){var t;let i=n?.Parent?new a:this;r(i,e),(t=i._zod).deferred??(t.deferred=[]);for(let e of i._zod.deferred)e();return i}return Object.defineProperty(o,`init`,{value:r}),Object.defineProperty(o,Symbol.hasInstance,{value:t=>n?.Parent&&t instanceof n.Parent?!0:t?._zod?.traits?.has(e)}),Object.defineProperty(o,`name`,{value:e}),o}var E=class extends Error{constructor(){super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`)}},re=class extends Error{constructor(e){super(`Encountered unidirectional transform during encode: ${e}`),this.name=`ZodEncodeError`}};let D={};function O(e){return e&&Object.assign(D,e),D}function ie(e,t){return typeof t==`bigint`?t.toString():t}function ae(e){return{get value(){{let t=e();return Object.defineProperty(this,`value`,{value:t}),t}throw Error(`cached value already set`)}}}function oe(e){return e==null}function se(e){let t=e.startsWith(`^`)?1:0,n=e.endsWith(`$`)?e.length-1:e.length;return e.slice(t,n)}let ce=Symbol(`evaluating`);function k(e,t,n){let r;Object.defineProperty(e,t,{get(){if(r!==ce)return r===void 0&&(r=ce,r=n()),r},set(n){Object.defineProperty(e,t,{value:n})},configurable:!0})}let le=`captureStackTrace`in Error?Error.captureStackTrace:(...e)=>{};function A(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ue(e){if(A(e)===!1)return!1;let t=e.constructor;if(t===void 0||typeof t!=`function`)return!0;let n=t.prototype;return!(A(n)===!1||Object.prototype.hasOwnProperty.call(n,`isPrototypeOf`)===!1)}function de(e,t,n){let r=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(r._zod.parent=e),r}function j(e){let t=e;if(!t)return{};if(typeof t==`string`)return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw Error(\"Cannot specify both `message` and `error` params\");t.error=t.message}return delete t.message,typeof t.error==`string`?{...t,error:()=>t.error}:t}function fe(e){return Object.keys(e).filter(t=>e[t]._zod.optin===`optional`&&e[t]._zod.optout===`optional`)}-Number.MAX_VALUE,Number.MAX_VALUE;function M(e,t=0){if(e.aborted===!0)return!0;for(let n=t;n<e.issues.length;n++)if(e.issues[n]?.continue!==!0)return!0;return!1}function N(e,t){return t.map(t=>{var n;return(n=t).path??(n.path=[]),t.path.unshift(e),t})}function P(e){return typeof e==`string`?e:e?.message}function F(e,t,n){let r={...e,path:e.path??[]};return e.message||(r.message=P(e.inst?._zod.def?.error?.(e))??P(t?.error?.(e))??P(n.customError?.(e))??P(n.localeError?.(e))??`Invalid input`),delete r.inst,delete r.continue,t?.reportInput||delete r.input,r}function pe(e){return Array.isArray(e)?`array`:typeof e==`string`?`string`:`unknown`}let I=(e,t)=>{e.name=`$ZodError`,Object.defineProperty(e,`_zod`,{value:e._zod,enumerable:!1}),Object.defineProperty(e,`issues`,{value:t,enumerable:!1}),e.message=JSON.stringify(t,ie,2),Object.defineProperty(e,`toString`,{value:()=>e.message,enumerable:!1})},me=T(`$ZodError`,I),L=T(`$ZodError`,I,{Parent:Error}),he=(e=>(t,n,r,i)=>{let a=r?Object.assign(r,{async:!1}):{async:!1},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise)throw new E;if(o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>F(e,a,O())));throw le(t,i?.callee),t}return o.value})(L),ge=(e=>async(t,n,r,i)=>{let a=r?Object.assign(r,{async:!0}):{async:!0},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise&&(o=await o),o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>F(e,a,O())));throw le(t,i?.callee),t}return o.value})(L),R=(e=>(t,n,r)=>{let i=r?{...r,async:!1}:{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new E;return a.issues.length?{success:!1,error:new(e??me)(a.issues.map(e=>F(e,i,O())))}:{success:!0,data:a.value}})(L),z=(e=>async(t,n,r)=>{let i=r?Object.assign(r,{async:!0}):{async:!0},a=t._zod.run({value:n,issues:[]},i);return a instanceof Promise&&(a=await a),a.issues.length?{success:!1,error:new e(a.issues.map(e=>F(e,i,O())))}:{success:!0,data:a.value}})(L),_e=e=>{let t=e?`[\\\\s\\\\S]{${e?.minimum??0},${e?.maximum??``}}`:`[\\\\s\\\\S]*`;return RegExp(`^${t}$`)},B=/^-?\\d+(?:\\.\\d+)?$/,V=T(`$ZodCheck`,(e,t)=>{var n;e._zod??={},e._zod.def=t,(n=e._zod).onattach??(n.onattach=[])}),ve=T(`$ZodCheckMinLength`,(e,t)=>{var n;V.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!oe(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.minimum??-1/0;t.minimum>n&&(e._zod.bag.minimum=t.minimum)}),e._zod.check=n=>{let r=n.value;if(r.length>=t.minimum)return;let i=pe(r);n.issues.push({origin:i,code:`too_small`,minimum:t.minimum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),ye=T(`$ZodCheckStringFormat`,(e,t)=>{var n,r;V.init(e,t),e._zod.onattach.push(e=>{let n=e._zod.bag;n.format=t.format,t.pattern&&(n.patterns??=new Set,n.patterns.add(t.pattern))}),t.pattern?(n=e._zod).check??(n.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:t.format,input:n.value,...t.pattern?{pattern:t.pattern.toString()}:{},inst:e,continue:!t.abort})}):(r=e._zod).check??(r.check=()=>{})}),be=T(`$ZodCheckRegex`,(e,t)=>{ye.init(e,t),e._zod.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:`regex`,input:n.value,pattern:t.pattern.toString(),inst:e,continue:!t.abort})}}),xe={major:4,minor:3,patch:6},H=T(`$ZodType`,(e,t)=>{var n;e??={},e._zod.def=t,e._zod.bag=e._zod.bag||{},e._zod.version=xe;let r=[...e._zod.def.checks??[]];e._zod.traits.has(`$ZodCheck`)&&r.unshift(e);for(let t of r)for(let n of t._zod.onattach)n(e);if(r.length===0)(n=e._zod).deferred??(n.deferred=[]),e._zod.deferred?.push(()=>{e._zod.run=e._zod.parse});else{let t=(e,t,n)=>{let r=M(e),i;for(let a of t){if(a._zod.def.when){if(!a._zod.def.when(e))continue}else if(r)continue;let t=e.issues.length,o=a._zod.check(e);if(o instanceof Promise&&n?.async===!1)throw new E;if(i||o instanceof Promise)i=(i??Promise.resolve()).then(async()=>{await o,e.issues.length!==t&&(r||=M(e,t))});else{if(e.issues.length===t)continue;r||=M(e,t)}}return i?i.then(()=>e):e},n=(n,i,a)=>{if(M(n))return n.aborted=!0,n;let o=t(i,r,a);if(o instanceof Promise){if(a.async===!1)throw new E;return o.then(t=>e._zod.parse(t,a))}return e._zod.parse(o,a)};e._zod.run=(i,a)=>{if(a.skipChecks)return e._zod.parse(i,a);if(a.direction===`backward`){let t=e._zod.parse({value:i.value,issues:[]},{...a,skipChecks:!0});return t instanceof Promise?t.then(e=>n(e,i,a)):n(t,i,a)}let o=e._zod.parse(i,a);if(o instanceof Promise){if(a.async===!1)throw new E;return o.then(e=>t(e,r,a))}return t(o,r,a)}}k(e,`~standard`,()=>({validate:t=>{try{let n=R(e,t);return n.success?{value:n.data}:{issues:n.error?.issues}}catch{return z(e,t).then(e=>e.success?{value:e.data}:{issues:e.error?.issues})}},vendor:`zod`,version:1}))}),Se=T(`$ZodString`,(e,t)=>{H.init(e,t),e._zod.pattern=[...e?._zod.bag?.patterns??[]].pop()??_e(e._zod.bag),e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=String(n.value)}catch{}return typeof n.value==`string`||n.issues.push({expected:`string`,code:`invalid_type`,input:n.value,inst:e}),n}}),Ce=T(`$ZodNumber`,(e,t)=>{H.init(e,t),e._zod.pattern=e._zod.bag.pattern??B,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=Number(n.value)}catch{}let i=n.value;if(typeof i==`number`&&!Number.isNaN(i)&&Number.isFinite(i))return n;let a=typeof i==`number`?Number.isNaN(i)?`NaN`:Number.isFinite(i)?void 0:`Infinity`:void 0;return n.issues.push({expected:`number`,code:`invalid_type`,input:i,inst:e,...a?{received:a}:{}}),n}});function U(e,t,n){e.issues.length&&t.issues.push(...N(n,e.issues)),t.value[n]=e.value}let we=T(`$ZodArray`,(e,t)=>{H.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!Array.isArray(i))return n.issues.push({expected:`array`,code:`invalid_type`,input:i,inst:e}),n;n.value=Array(i.length);let a=[];for(let e=0;e<i.length;e++){let o=i[e],s=t.element._zod.run({value:o,issues:[]},r);s instanceof Promise?a.push(s.then(t=>U(t,n,e))):U(s,n,e)}return a.length?Promise.all(a).then(()=>n):n}});function W(e,t,n,r,i){if(e.issues.length){if(i&&!(n in r))return;t.issues.push(...N(n,e.issues))}e.value===void 0?n in r&&(t.value[n]=void 0):t.value[n]=e.value}function Te(e){let t=Object.keys(e.shape);for(let n of t)if(!e.shape?.[n]?._zod?.traits?.has(`$ZodType`))throw Error(`Invalid element at key \"${n}\": expected a Zod schema`);let n=fe(e.shape);return{...e,keys:t,keySet:new Set(t),numKeys:t.length,optionalKeys:new Set(n)}}function Ee(e,t,n,r,i,a){let o=[],s=i.keySet,c=i.catchall._zod,l=c.def.type,u=c.optout===`optional`;for(let i in t){if(s.has(i))continue;if(l===`never`){o.push(i);continue}let a=c.run({value:t[i],issues:[]},r);a instanceof Promise?e.push(a.then(e=>W(e,n,i,t,u))):W(a,n,i,t,u)}return o.length&&n.issues.push({code:`unrecognized_keys`,keys:o,input:t,inst:a}),e.length?Promise.all(e).then(()=>n):n}let De=T(`$ZodObject`,(e,t)=>{if(H.init(e,t),!Object.getOwnPropertyDescriptor(t,`shape`)?.get){let e=t.shape;Object.defineProperty(t,`shape`,{get:()=>{let n={...e};return Object.defineProperty(t,`shape`,{value:n}),n}})}let n=ae(()=>Te(t));k(e._zod,`propValues`,()=>{let e=t.shape,n={};for(let t in e){let r=e[t]._zod;if(r.values){n[t]??(n[t]=new Set);for(let e of r.values)n[t].add(e)}}return n});let r=A,i=t.catchall,a;e._zod.parse=(t,o)=>{a??=n.value;let s=t.value;if(!r(s))return t.issues.push({expected:`object`,code:`invalid_type`,input:s,inst:e}),t;t.value={};let c=[],l=a.shape;for(let e of a.keys){let n=l[e],r=n._zod.optout===`optional`,i=n._zod.run({value:s[e],issues:[]},o);i instanceof Promise?c.push(i.then(n=>W(n,t,e,s,r))):W(i,t,e,s,r)}return i?Ee(c,s,t,o,n.value,e):c.length?Promise.all(c).then(()=>t):t}}),Oe=T(`$ZodRecord`,(e,t)=>{H.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!ue(i))return n.issues.push({expected:`record`,code:`invalid_type`,input:i,inst:e}),n;let a=[],o=t.keyType._zod.values;if(o){n.value={};let s=new Set;for(let e of o)if(typeof e==`string`||typeof e==`number`||typeof e==`symbol`){s.add(typeof e==`number`?e.toString():e);let o=t.valueType._zod.run({value:i[e],issues:[]},r);o instanceof Promise?a.push(o.then(t=>{t.issues.length&&n.issues.push(...N(e,t.issues)),n.value[e]=t.value})):(o.issues.length&&n.issues.push(...N(e,o.issues)),n.value[e]=o.value)}let c;for(let e in i)s.has(e)||(c??=[],c.push(e));c&&c.length>0&&n.issues.push({code:`unrecognized_keys`,input:i,inst:e,keys:c})}else{n.value={};for(let o of Reflect.ownKeys(i)){if(o===`__proto__`)continue;let s=t.keyType._zod.run({value:o,issues:[]},r);if(s instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(typeof o==`string`&&B.test(o)&&s.issues.length){let e=t.keyType._zod.run({value:Number(o),issues:[]},r);if(e instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);e.issues.length===0&&(s=e)}if(s.issues.length){t.mode===`loose`?n.value[o]=i[o]:n.issues.push({code:`invalid_key`,origin:`record`,issues:s.issues.map(e=>F(e,r,O())),input:o,path:[o],inst:e});continue}let c=t.valueType._zod.run({value:i[o],issues:[]},r);c instanceof Promise?a.push(c.then(e=>{e.issues.length&&n.issues.push(...N(o,e.issues)),n.value[s.value]=e.value})):(c.issues.length&&n.issues.push(...N(o,c.issues)),n.value[s.value]=c.value)}}return a.length?Promise.all(a).then(()=>n):n}}),ke=T(`$ZodTransform`,(e,t)=>{H.init(e,t),e._zod.parse=(n,r)=>{if(r.direction===`backward`)throw new re(e.constructor.name);let i=t.transform(n.value,n);if(r.async)return(i instanceof Promise?i:Promise.resolve(i)).then(e=>(n.value=e,n));if(i instanceof Promise)throw new E;return n.value=i,n}});function G(e,t){return e.issues.length&&t===void 0?{issues:[],value:void 0}:e}let Ae=T(`$ZodOptional`,(e,t)=>{H.init(e,t),e._zod.optin=`optional`,e._zod.optout=`optional`,k(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,void 0]):void 0),k(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${se(e.source)})?$`):void 0}),e._zod.parse=(e,n)=>{if(t.innerType._zod.optin===`optional`){let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(t=>G(t,e.value)):G(r,e.value)}return e.value===void 0?e:t.innerType._zod.run(e,n)}}),je=T(`$ZodPipe`,(e,t)=>{H.init(e,t),k(e._zod,`values`,()=>t.in._zod.values),k(e._zod,`optin`,()=>t.in._zod.optin),k(e._zod,`optout`,()=>t.out._zod.optout),k(e._zod,`propValues`,()=>t.in._zod.propValues),e._zod.parse=(e,n)=>{if(n.direction===`backward`){let r=t.out._zod.run(e,n);return r instanceof Promise?r.then(e=>K(e,t.in,n)):K(r,t.in,n)}let r=t.in._zod.run(e,n);return r instanceof Promise?r.then(e=>K(e,t.out,n)):K(r,t.out,n)}});function K(e,t,n){return e.issues.length?(e.aborted=!0,e):t._zod.run({value:e.value,issues:e.issues},n)}var Me,Ne=class{constructor(){this._map=new WeakMap,this._idmap=new Map}add(e,...t){let n=t[0];return this._map.set(e,n),n&&typeof n==`object`&&`id`in n&&this._idmap.set(n.id,e),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(e){let t=this._map.get(e);return t&&typeof t==`object`&&`id`in t&&this._idmap.delete(t.id),this._map.delete(e),this}get(e){let t=e._zod.parent;if(t){let n={...this.get(t)??{}};delete n.id;let r={...n,...this._map.get(e)};return Object.keys(r).length?r:void 0}return this._map.get(e)}has(e){return this._map.has(e)}};function Pe(){return new Ne}(Me=globalThis).__zod_globalRegistry??(Me.__zod_globalRegistry=Pe()),globalThis.__zod_globalRegistry;function Fe(e,t){return new e({type:`string`,...j(t)})}function Ie(e,t){return new e({type:`number`,checks:[],...j(t)})}function Le(e,t){return new ve({check:`min_length`,...j(t),minimum:e})}function Re(e,t){return new be({check:`string_format`,format:`regex`,...j(t),pattern:e})}let q=T(`ZodMiniType`,(e,t)=>{if(!e._zod)throw Error(`Uninitialized schema in ZodMiniType.`);H.init(e,t),e.def=t,e.type=t.type,e.parse=(t,n)=>he(e,t,n,{callee:e.parse}),e.safeParse=(t,n)=>R(e,t,n),e.parseAsync=async(t,n)=>ge(e,t,n,{callee:e.parseAsync}),e.safeParseAsync=async(t,n)=>z(e,t,n),e.check=(...n)=>e.clone({...t,checks:[...t.checks??[],...n.map(e=>typeof e==`function`?{_zod:{check:e,def:{check:`custom`},onattach:[]}}:e)]},{parent:!0}),e.with=e.check,e.clone=(t,n)=>de(e,t,n),e.brand=()=>e,e.register=((t,n)=>(t.add(e,n),e)),e.apply=t=>t(e)}),ze=T(`ZodMiniString`,(e,t)=>{Se.init(e,t),q.init(e,t)});function J(e){return Fe(ze,e)}let Be=T(`ZodMiniNumber`,(e,t)=>{Ce.init(e,t),q.init(e,t)});function Ve(e){return Ie(Be,e)}let He=T(`ZodMiniArray`,(e,t)=>{we.init(e,t),q.init(e,t)});function Ue(e,t){return new He({type:`array`,element:e,...j(t)})}let We=T(`ZodMiniObject`,(e,t)=>{De.init(e,t),q.init(e,t),k(e,`shape`,()=>t.shape)});function Y(e,t){return new We({type:`object`,shape:e??{},...j(t)})}let Ge=T(`ZodMiniRecord`,(e,t)=>{Oe.init(e,t),q.init(e,t)});function Ke(e,t,n){return new Ge({type:`record`,keyType:e,valueType:t,...j(n)})}let qe=T(`ZodMiniTransform`,(e,t)=>{ke.init(e,t),q.init(e,t)});function Je(e){return new qe({type:`transform`,transform:e})}let Ye=T(`ZodMiniOptional`,(e,t)=>{Ae.init(e,t),q.init(e,t)});function X(e){return new Ye({type:`optional`,innerType:e})}let Xe=T(`ZodMiniPipe`,(e,t)=>{je.init(e,t),q.init(e,t)});function Ze(e,t){return new Xe({type:`pipe`,in:e,out:t})}function Qe(){return J().check(Re(/^\\d+(\\.\\d+)?$/,`Invalid amount`))}function $e(e){let t={challenge:{...e.challenge,request:ne(e.challenge.request)},payload:e.payload,...e.source&&{source:e.source}};return`Payment ${te(JSON.stringify(t),{pad:!1,url:!0})}`}function et(e){return e}function tt(e,t){let{context:n,createCredential:r}=t;return{...e,context:n,createCredential:r}}var Z,nt=e((()=>{Z=`2.47.6`}));function rt(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause!==void 0?rt(e.cause,t):t?null:e}var Q,it;e((()=>{nt(),Q={getDocsUrl:({docsBaseUrl:e,docsPath:t=``,docsSlug:n})=>t?`${e??`https://viem.sh`}${t}${n?`#${n}`:``}`:void 0,version:`viem@${Z}`},it=class e extends Error{constructor(t,n={}){let r=n.cause instanceof e?n.cause.details:n.cause?.message?n.cause.message:n.details,i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=Q.getDocsUrl?.({...n,docsPath:i}),o=[t||`An error occurred.`,``,...n.metaMessages?[...n.metaMessages,``]:[],...a?[`Docs: ${a}`]:[],...r?[`Details: ${r}`]:[],...Q.version?[`Version: ${Q.version}`]:[]].join(`\n`);super(o,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`metaMessages`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),this.details=r,this.docsPath=i,this.metaMessages=n.metaMessages,this.name=n.name??this.name,this.shortMessage=t,this.version=Z}walk(e){return rt(this,e)}}}))();var at=class extends it{constructor({value:e}){super(`Number \\`${e}\\` is not a valid decimal number.`,{name:`InvalidDecimalNumberError`})}};function ot(e,t){if(!/^(-?)([0-9]*)\\.?([0-9]*)$/.test(e))throw new at({value:e});let[n,r=`0`]=e.split(`.`),i=n.startsWith(`-`);if(i&&(n=n.slice(1)),r=r.replace(/(0+)$/,``),t===0)Math.round(Number(`.${r}`))===1&&(n=`${BigInt(n)+1n}`),r=``;else if(r.length>t){let[e,i,a]=[r.slice(0,t-1),r.slice(t-1,t),r.slice(t)],o=Math.round(Number(`${i}.${a}`));r=o>9?`${BigInt(e)+BigInt(1)}0`.padStart(e.length+1,`0`):`${e}${o}`,r.length>t&&(r=r.slice(1),n=`${BigInt(n)+1n}`),r=r.slice(0,t)}else r=r.padEnd(t,`0`);return BigInt(`${i?`-`:``}${n}${r}`)}let st=et({name:`stripe`,intent:`charge`,schema:{credential:{payload:Y({externalId:X(J()),spt:J()})},request:Ze(Y({amount:Qe(),currency:J(),decimals:Ve(),description:X(J()),externalId:X(J()),metadata:X(Ke(J(),J())),networkId:J(),paymentMethodTypes:Ue(J()).check(Le(1)),recipient:X(J())}),Je(({amount:e,decimals:t,metadata:n,networkId:r,paymentMethodTypes:i,...a})=>({...a,amount:ot(e,t).toString(),methodDetails:{networkId:r,paymentMethodTypes:i,...n!==void 0&&{metadata:n}}})))}});function ct(e){let{client:t,createToken:n,externalId:r,paymentMethod:i}=e;return tt(st,{context:Y({paymentMethod:X(J())}),async createCredential({challenge:e,context:a}){let o=a?.paymentMethod??i;if(!o)throw Error(`paymentMethod is required (pass via context or parameters)`);let s=e.request.amount,c=e.request.currency,l=e.request.methodDetails?.networkId;if(!l)throw Error(`networkId is required in challenge.methodDetails`);let u=e.request.methodDetails?.metadata;if(u?.externalId)throw Error(`methodDetails.metadata.externalId is reserved; use credential externalId instead`);return $e({challenge:e,payload:{spt:await n({amount:s,challenge:e,client:t,currency:c,expiresAt:e.expires?Math.floor(new Date(e.expires).getTime()/1e3):Math.floor(Date.now()/1e3)+3600,metadata:u,networkId:l,paymentMethod:o}),...r?{externalId:r}:{}}})}})}function lt(e){return[ct(e)]}(function(e){e.charge=ct})(lt||={});var ut=r();async function dt(e){let t=new URL(location.href);t.searchParams.set(`__mppx_worker`,``);let n=await navigator.serviceWorker.register(t.pathname+t.search),r=await new Promise(e=>{let t=n.installing??n.waiting??n.active;if(t?.state===`activated`)return e(t);let r=t??n;r.addEventListener(`statechange`,function t(){let i=n.active;i?.state===`activated`&&(r.removeEventListener(`statechange`,t),e(i))})});await new Promise(t=>{let n=new MessageChannel;n.port1.onmessage=()=>t(),r.postMessage({credential:e},[n.port2])}),location.reload()}let $=JSON.parse(document.getElementById(`__MPPX_DATA__`).textContent),ft=document.getElementById(`root`),pt=document.createElement(`h2`);pt.textContent=`stripe`,ft.appendChild(pt),(async()=>{let e=await(0,ut.loadStripe)($.config.publishableKey);if(!e)throw Error(`Failed to loadStripe`);let t=window.matchMedia(`(prefers-color-scheme: dark)`),n=()=>({theme:t.matches?`night`:`stripe`}),r=e.elements({amount:Number($.challenge.request.amount),appearance:n(),currency:$.challenge.request.currency,mode:`payment`,paymentMethodCreation:`manual`});t.addEventListener(`change`,()=>{r.update({appearance:n()})});let i=document.createElement(`form`);r.create(`payment`).mount(i),ft.appendChild(i);let a=document.createElement(`button`);a.textContent=`Pay`,a.type=`submit`,i.appendChild(a),i.onsubmit=async t=>{t.preventDefault(),a.disabled=!0;try{await r.submit();let{paymentMethod:t,error:n}=await e.createPaymentMethod({elements:r});if(n||!t)throw n??Error(`Failed to create payment method`);await dt(await lt({client:e,createToken:mt})[0].createCredential({challenge:$.challenge,context:{paymentMethod:t.id}}))}finally{a.disabled=!1}}})();async function mt(e){let t=new URL($.config.createTokenUrl,location.origin);if(t.origin!==location.origin)throw Error(`createTokenUrl must be same-origin`);let n=await fetch(t,{method:`POST`,headers:{\"Content-Type\":`application/json`},body:JSON.stringify(e)});if(!n.ok){let e=await n.text().catch(()=>`<response body unavailable>`);throw Error(`Failed to create SPT (${n.status}): ${e}`)}return(await n.json()).spt}})();</script>"
|
|
@@ -2,6 +2,47 @@ import { describe, expect, test } from 'vp/test'
|
|
|
2
2
|
|
|
3
3
|
import * as Proof from './proof.js'
|
|
4
4
|
|
|
5
|
+
const parseProofSourceCases = [
|
|
6
|
+
{
|
|
7
|
+
expected: {
|
|
8
|
+
address: '0xa5cc3c03994db5b0d9ba5e4f6d2efbd9f213b141',
|
|
9
|
+
chainId: 42431,
|
|
10
|
+
},
|
|
11
|
+
name: 'parses a valid did:pkh:eip155 source',
|
|
12
|
+
source: 'did:pkh:eip155:42431:0xa5cc3c03994db5b0d9ba5e4f6d2efbd9f213b141',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
expected: null,
|
|
16
|
+
name: 'rejects non-numeric chain ids',
|
|
17
|
+
source: 'did:pkh:eip155:not-a-number:0x1234',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
expected: null,
|
|
21
|
+
name: 'rejects leading-zero chain ids',
|
|
22
|
+
source: 'did:pkh:eip155:01:0xa5cc3c03994db5b0d9ba5e4f6d2efbd9f213b141',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
expected: null,
|
|
26
|
+
name: 'rejects unsafe integer chain ids',
|
|
27
|
+
source: 'did:pkh:eip155:9007199254740992:0xa5cc3c03994db5b0d9ba5e4f6d2efbd9f213b141',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
expected: null,
|
|
31
|
+
name: 'rejects invalid addresses',
|
|
32
|
+
source: 'did:pkh:eip155:42431:not-an-address',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
expected: null,
|
|
36
|
+
name: 'rejects extra path segments',
|
|
37
|
+
source: 'did:pkh:eip155:42431:0xAbCdEf1234567890AbCdEf1234567890AbCdEf12:extra',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
expected: null,
|
|
41
|
+
name: 'rejects unsupported namespaces',
|
|
42
|
+
source: 'did:pkh:solana:42431:0xa5cc3c03994db5b0d9ba5e4f6d2efbd9f213b141',
|
|
43
|
+
},
|
|
44
|
+
] as const
|
|
45
|
+
|
|
5
46
|
describe('Proof', () => {
|
|
6
47
|
test('types has Proof with challengeId field', () => {
|
|
7
48
|
expect(Proof.types).toEqual({
|
|
@@ -33,4 +74,10 @@ describe('Proof', () => {
|
|
|
33
74
|
const address = '0xAbCdEf1234567890AbCdEf1234567890AbCdEf12'
|
|
34
75
|
expect(Proof.proofSource({ address, chainId: 1 })).toBe(`did:pkh:eip155:1:${address}`)
|
|
35
76
|
})
|
|
77
|
+
|
|
78
|
+
for (const { expected, name, source } of parseProofSourceCases) {
|
|
79
|
+
test(`parseProofSource ${name}`, () => {
|
|
80
|
+
expect(Proof.parseProofSource(source)).toEqual(expected)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
36
83
|
})
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isAddress, type Address } from 'viem'
|
|
2
|
+
|
|
1
3
|
/** EIP-712 typed data types for proof credentials. */
|
|
2
4
|
export const types = {
|
|
3
5
|
Proof: [{ name: 'challengeId', type: 'string' }],
|
|
@@ -17,3 +19,17 @@ export function message(challengeId: string) {
|
|
|
17
19
|
export function proofSource(parameters: { address: string; chainId: number }): string {
|
|
18
20
|
return `did:pkh:eip155:${parameters.chainId}:${parameters.address}`
|
|
19
21
|
}
|
|
22
|
+
|
|
23
|
+
/** Parses a proof credential `did:pkh:eip155` source DID. */
|
|
24
|
+
export function parseProofSource(source: string): { address: Address; chainId: number } | null {
|
|
25
|
+
const match = /^did:pkh:eip155:(0|[1-9]\d*):([^:]+)$/.exec(source)
|
|
26
|
+
if (!match) return null
|
|
27
|
+
|
|
28
|
+
const chainIdText = match[1]!
|
|
29
|
+
const address = match[2]!
|
|
30
|
+
const chainId = Number(chainIdText)
|
|
31
|
+
if (!Number.isSafeInteger(chainId)) return null
|
|
32
|
+
if (!isAddress(address)) return null
|
|
33
|
+
|
|
34
|
+
return { address: address as Address, chainId }
|
|
35
|
+
}
|
|
@@ -1995,6 +1995,268 @@ describe('tempo', () => {
|
|
|
1995
1995
|
httpServer.close()
|
|
1996
1996
|
})
|
|
1997
1997
|
|
|
1998
|
+
test('behavior: proof credential remains reusable until expiry without store', async () => {
|
|
1999
|
+
const httpServer = await Http.createServer(async (req, res) => {
|
|
2000
|
+
const result = await Mppx_server.toNodeListener(
|
|
2001
|
+
server.charge({ amount: '0', decimals: 6 }),
|
|
2002
|
+
)(req, res)
|
|
2003
|
+
if (result.status === 402) return
|
|
2004
|
+
res.end('OK')
|
|
2005
|
+
})
|
|
2006
|
+
|
|
2007
|
+
const response1 = await fetch(httpServer.url)
|
|
2008
|
+
expect(response1.status).toBe(402)
|
|
2009
|
+
|
|
2010
|
+
const challenge = Challenge.fromResponse(response1, {
|
|
2011
|
+
methods: [tempo_client.charge()],
|
|
2012
|
+
})
|
|
2013
|
+
|
|
2014
|
+
const signature = await signTypedData(client, {
|
|
2015
|
+
account: accounts[1],
|
|
2016
|
+
domain: Proof.domain(chain.id),
|
|
2017
|
+
types: Proof.types,
|
|
2018
|
+
primaryType: 'Proof',
|
|
2019
|
+
message: Proof.message(challenge.id),
|
|
2020
|
+
})
|
|
2021
|
+
|
|
2022
|
+
const credential = Credential.from({
|
|
2023
|
+
challenge,
|
|
2024
|
+
payload: { signature, type: 'proof' as const },
|
|
2025
|
+
source: `did:pkh:eip155:${chain.id}:${accounts[1].address}`,
|
|
2026
|
+
})
|
|
2027
|
+
|
|
2028
|
+
const response2 = await fetch(httpServer.url, {
|
|
2029
|
+
headers: { Authorization: Credential.serialize(credential) },
|
|
2030
|
+
})
|
|
2031
|
+
expect(response2.status).toBe(200)
|
|
2032
|
+
|
|
2033
|
+
const replayResponse = await fetch(httpServer.url, {
|
|
2034
|
+
headers: { Authorization: Credential.serialize(credential) },
|
|
2035
|
+
})
|
|
2036
|
+
expect(replayResponse.status).toBe(200)
|
|
2037
|
+
|
|
2038
|
+
httpServer.close()
|
|
2039
|
+
})
|
|
2040
|
+
|
|
2041
|
+
test('behavior: rejects replayed proof credential when store is configured', async () => {
|
|
2042
|
+
const replayStore = Store.memory()
|
|
2043
|
+
const server_ = Mppx_server.create({
|
|
2044
|
+
methods: [
|
|
2045
|
+
tempo_server.charge({
|
|
2046
|
+
getClient() {
|
|
2047
|
+
return client
|
|
2048
|
+
},
|
|
2049
|
+
currency: asset,
|
|
2050
|
+
account: accounts[0],
|
|
2051
|
+
store: replayStore,
|
|
2052
|
+
}),
|
|
2053
|
+
],
|
|
2054
|
+
realm,
|
|
2055
|
+
secretKey,
|
|
2056
|
+
})
|
|
2057
|
+
|
|
2058
|
+
const httpServer = await Http.createServer(async (req, res) => {
|
|
2059
|
+
const result = await Mppx_server.toNodeListener(
|
|
2060
|
+
server_.charge({ amount: '0', decimals: 6 }),
|
|
2061
|
+
)(req, res)
|
|
2062
|
+
if (result.status === 402) return
|
|
2063
|
+
res.end('OK')
|
|
2064
|
+
})
|
|
2065
|
+
|
|
2066
|
+
const response1 = await fetch(httpServer.url)
|
|
2067
|
+
expect(response1.status).toBe(402)
|
|
2068
|
+
|
|
2069
|
+
const challenge = Challenge.fromResponse(response1, {
|
|
2070
|
+
methods: [tempo_client.charge()],
|
|
2071
|
+
})
|
|
2072
|
+
|
|
2073
|
+
const signature = await signTypedData(client, {
|
|
2074
|
+
account: accounts[1],
|
|
2075
|
+
domain: Proof.domain(chain.id),
|
|
2076
|
+
types: Proof.types,
|
|
2077
|
+
primaryType: 'Proof',
|
|
2078
|
+
message: Proof.message(challenge.id),
|
|
2079
|
+
})
|
|
2080
|
+
|
|
2081
|
+
const credential = Credential.from({
|
|
2082
|
+
challenge,
|
|
2083
|
+
payload: { signature, type: 'proof' as const },
|
|
2084
|
+
source: `did:pkh:eip155:${chain.id}:${accounts[1].address}`,
|
|
2085
|
+
})
|
|
2086
|
+
|
|
2087
|
+
const response2 = await fetch(httpServer.url, {
|
|
2088
|
+
headers: { Authorization: Credential.serialize(credential) },
|
|
2089
|
+
})
|
|
2090
|
+
expect(response2.status).toBe(200)
|
|
2091
|
+
|
|
2092
|
+
const replayResponse = await fetch(httpServer.url, {
|
|
2093
|
+
headers: { Authorization: Credential.serialize(credential) },
|
|
2094
|
+
})
|
|
2095
|
+
expect(replayResponse.status).toBe(402)
|
|
2096
|
+
const replayBody = (await replayResponse.json()) as { detail: string }
|
|
2097
|
+
expect(replayBody.detail).toContain('Proof credential has already been used.')
|
|
2098
|
+
|
|
2099
|
+
httpServer.close()
|
|
2100
|
+
})
|
|
2101
|
+
|
|
2102
|
+
test('behavior: shared store rejects proof replay across server instances', async () => {
|
|
2103
|
+
const replayStore = Store.memory()
|
|
2104
|
+
const serverA = Mppx_server.create({
|
|
2105
|
+
methods: [
|
|
2106
|
+
tempo_server.charge({
|
|
2107
|
+
getClient() {
|
|
2108
|
+
return client
|
|
2109
|
+
},
|
|
2110
|
+
currency: asset,
|
|
2111
|
+
account: accounts[0],
|
|
2112
|
+
store: replayStore,
|
|
2113
|
+
}),
|
|
2114
|
+
],
|
|
2115
|
+
realm,
|
|
2116
|
+
secretKey,
|
|
2117
|
+
})
|
|
2118
|
+
const serverB = Mppx_server.create({
|
|
2119
|
+
methods: [
|
|
2120
|
+
tempo_server.charge({
|
|
2121
|
+
getClient() {
|
|
2122
|
+
return client
|
|
2123
|
+
},
|
|
2124
|
+
currency: asset,
|
|
2125
|
+
account: accounts[0],
|
|
2126
|
+
store: replayStore,
|
|
2127
|
+
}),
|
|
2128
|
+
],
|
|
2129
|
+
realm,
|
|
2130
|
+
secretKey,
|
|
2131
|
+
})
|
|
2132
|
+
|
|
2133
|
+
const httpServer = await Http.createServer(async (req, res) => {
|
|
2134
|
+
const route = new URL(req.url!, 'https://example.com').pathname
|
|
2135
|
+
const handler = route === '/a' ? serverA : serverB
|
|
2136
|
+
const result = await Mppx_server.toNodeListener(
|
|
2137
|
+
handler.charge({ amount: '0', decimals: 6 }),
|
|
2138
|
+
)(req, res)
|
|
2139
|
+
if (result.status === 402) return
|
|
2140
|
+
res.end('OK')
|
|
2141
|
+
})
|
|
2142
|
+
|
|
2143
|
+
const response1 = await fetch(`${httpServer.url}/a`)
|
|
2144
|
+
expect(response1.status).toBe(402)
|
|
2145
|
+
|
|
2146
|
+
const challenge = Challenge.fromResponse(response1, {
|
|
2147
|
+
methods: [tempo_client.charge()],
|
|
2148
|
+
})
|
|
2149
|
+
|
|
2150
|
+
const signature = await signTypedData(client, {
|
|
2151
|
+
account: accounts[1],
|
|
2152
|
+
domain: Proof.domain(chain.id),
|
|
2153
|
+
types: Proof.types,
|
|
2154
|
+
primaryType: 'Proof',
|
|
2155
|
+
message: Proof.message(challenge.id),
|
|
2156
|
+
})
|
|
2157
|
+
|
|
2158
|
+
const credential = Credential.from({
|
|
2159
|
+
challenge,
|
|
2160
|
+
payload: { signature, type: 'proof' as const },
|
|
2161
|
+
source: `did:pkh:eip155:${chain.id}:${accounts[1].address}`,
|
|
2162
|
+
})
|
|
2163
|
+
|
|
2164
|
+
const response2 = await fetch(`${httpServer.url}/a`, {
|
|
2165
|
+
headers: { Authorization: Credential.serialize(credential) },
|
|
2166
|
+
})
|
|
2167
|
+
expect(response2.status).toBe(200)
|
|
2168
|
+
|
|
2169
|
+
const replayResponse = await fetch(`${httpServer.url}/b`, {
|
|
2170
|
+
headers: { Authorization: Credential.serialize(credential) },
|
|
2171
|
+
})
|
|
2172
|
+
expect(replayResponse.status).toBe(402)
|
|
2173
|
+
const replayBody = (await replayResponse.json()) as { detail: string }
|
|
2174
|
+
expect(replayBody.detail).toContain('Proof credential has already been used.')
|
|
2175
|
+
|
|
2176
|
+
httpServer.close()
|
|
2177
|
+
})
|
|
2178
|
+
|
|
2179
|
+
test('behavior: store keys proof replay protection by challenge ID', async () => {
|
|
2180
|
+
const replayStore = Store.memory()
|
|
2181
|
+
const server_ = Mppx_server.create({
|
|
2182
|
+
methods: [
|
|
2183
|
+
tempo_server.charge({
|
|
2184
|
+
getClient() {
|
|
2185
|
+
return client
|
|
2186
|
+
},
|
|
2187
|
+
currency: asset,
|
|
2188
|
+
account: accounts[0],
|
|
2189
|
+
store: replayStore,
|
|
2190
|
+
}),
|
|
2191
|
+
],
|
|
2192
|
+
realm,
|
|
2193
|
+
secretKey,
|
|
2194
|
+
})
|
|
2195
|
+
|
|
2196
|
+
const httpServer = await Http.createServer(async (req, res) => {
|
|
2197
|
+
const result = await Mppx_server.toNodeListener(
|
|
2198
|
+
server_.charge({ amount: '0', decimals: 6 }),
|
|
2199
|
+
)(req, res)
|
|
2200
|
+
if (result.status === 402) return
|
|
2201
|
+
res.end('OK')
|
|
2202
|
+
})
|
|
2203
|
+
|
|
2204
|
+
const response1 = await fetch(httpServer.url)
|
|
2205
|
+
expect(response1.status).toBe(402)
|
|
2206
|
+
|
|
2207
|
+
const challenge1 = Challenge.fromResponse(response1, {
|
|
2208
|
+
methods: [tempo_client.charge()],
|
|
2209
|
+
})
|
|
2210
|
+
|
|
2211
|
+
const signature1 = await signTypedData(client, {
|
|
2212
|
+
account: accounts[1],
|
|
2213
|
+
domain: Proof.domain(chain.id),
|
|
2214
|
+
types: Proof.types,
|
|
2215
|
+
primaryType: 'Proof',
|
|
2216
|
+
message: Proof.message(challenge1.id),
|
|
2217
|
+
})
|
|
2218
|
+
|
|
2219
|
+
const credential1 = Credential.from({
|
|
2220
|
+
challenge: challenge1,
|
|
2221
|
+
payload: { signature: signature1, type: 'proof' as const },
|
|
2222
|
+
source: `did:pkh:eip155:${chain.id}:${accounts[1].address}`,
|
|
2223
|
+
})
|
|
2224
|
+
|
|
2225
|
+
const response2 = await fetch(httpServer.url, {
|
|
2226
|
+
headers: { Authorization: Credential.serialize(credential1) },
|
|
2227
|
+
})
|
|
2228
|
+
expect(response2.status).toBe(200)
|
|
2229
|
+
|
|
2230
|
+
const response3 = await fetch(httpServer.url)
|
|
2231
|
+
expect(response3.status).toBe(402)
|
|
2232
|
+
|
|
2233
|
+
const challenge2 = Challenge.fromResponse(response3, {
|
|
2234
|
+
methods: [tempo_client.charge()],
|
|
2235
|
+
})
|
|
2236
|
+
expect(challenge2.id).not.toBe(challenge1.id)
|
|
2237
|
+
|
|
2238
|
+
const signature2 = await signTypedData(client, {
|
|
2239
|
+
account: accounts[1],
|
|
2240
|
+
domain: Proof.domain(chain.id),
|
|
2241
|
+
types: Proof.types,
|
|
2242
|
+
primaryType: 'Proof',
|
|
2243
|
+
message: Proof.message(challenge2.id),
|
|
2244
|
+
})
|
|
2245
|
+
|
|
2246
|
+
const credential2 = Credential.from({
|
|
2247
|
+
challenge: challenge2,
|
|
2248
|
+
payload: { signature: signature2, type: 'proof' as const },
|
|
2249
|
+
source: `did:pkh:eip155:${chain.id}:${accounts[1].address}`,
|
|
2250
|
+
})
|
|
2251
|
+
|
|
2252
|
+
const response4 = await fetch(httpServer.url, {
|
|
2253
|
+
headers: { Authorization: Credential.serialize(credential2) },
|
|
2254
|
+
})
|
|
2255
|
+
expect(response4.status).toBe(200)
|
|
2256
|
+
|
|
2257
|
+
httpServer.close()
|
|
2258
|
+
})
|
|
2259
|
+
|
|
1998
2260
|
test('behavior: rejects proof with wrong signer', async () => {
|
|
1999
2261
|
const httpServer = await Http.createServer(async (req, res) => {
|
|
2000
2262
|
const result = await Mppx_server.toNodeListener(
|
|
@@ -2244,6 +2506,42 @@ describe('tempo', () => {
|
|
|
2244
2506
|
httpServer.close()
|
|
2245
2507
|
})
|
|
2246
2508
|
|
|
2509
|
+
test('behavior: rejects proof with mismatched source DID chainId', async () => {
|
|
2510
|
+
const httpServer = await Http.createServer(async (req, res) => {
|
|
2511
|
+
const result = await Mppx_server.toNodeListener(
|
|
2512
|
+
server.charge({ amount: '0', decimals: 6 }),
|
|
2513
|
+
)(req, res)
|
|
2514
|
+
if (result.status === 402) return
|
|
2515
|
+
res.end('OK')
|
|
2516
|
+
})
|
|
2517
|
+
|
|
2518
|
+
const response1 = await fetch(httpServer.url)
|
|
2519
|
+
const challenge = Challenge.fromResponse(response1, {
|
|
2520
|
+
methods: [tempo_client.charge()],
|
|
2521
|
+
})
|
|
2522
|
+
|
|
2523
|
+
const signature = await signTypedData(client, {
|
|
2524
|
+
account: accounts[1],
|
|
2525
|
+
domain: Proof.domain(chain.id),
|
|
2526
|
+
types: Proof.types,
|
|
2527
|
+
primaryType: 'Proof',
|
|
2528
|
+
message: Proof.message(challenge.id),
|
|
2529
|
+
})
|
|
2530
|
+
|
|
2531
|
+
const credential = Credential.from({
|
|
2532
|
+
challenge,
|
|
2533
|
+
payload: { signature, type: 'proof' as const },
|
|
2534
|
+
source: `did:pkh:eip155:1:${accounts[1].address}`,
|
|
2535
|
+
})
|
|
2536
|
+
|
|
2537
|
+
const response2 = await fetch(httpServer.url, {
|
|
2538
|
+
headers: { Authorization: Credential.serialize(credential) },
|
|
2539
|
+
})
|
|
2540
|
+
expect(response2.status).toBe(402)
|
|
2541
|
+
|
|
2542
|
+
httpServer.close()
|
|
2543
|
+
})
|
|
2544
|
+
|
|
2247
2545
|
test('behavior: rejects proof with malformed source DID', async () => {
|
|
2248
2546
|
const httpServer = await Http.createServer(async (req, res) => {
|
|
2249
2547
|
const result = await Mppx_server.toNodeListener(
|