mppx 0.1.1 → 0.2.0
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/dist/Challenge.d.ts +16 -16
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +7 -7
- package/dist/Challenge.js.map +1 -1
- package/dist/Errors.d.ts +58 -8
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js +51 -9
- package/dist/Errors.js.map +1 -1
- package/dist/Method.d.ts +154 -0
- package/dist/Method.d.ts.map +1 -0
- package/dist/Method.js +81 -0
- package/dist/Method.js.map +1 -0
- package/dist/PaymentRequest.d.ts +5 -5
- package/dist/PaymentRequest.d.ts.map +1 -1
- package/dist/PaymentRequest.js +5 -5
- package/dist/cli.js +67 -18
- package/dist/cli.js.map +1 -1
- package/dist/client/Methods.d.ts +2 -2
- package/dist/client/Methods.d.ts.map +1 -1
- package/dist/client/Methods.js +2 -2
- package/dist/client/Methods.js.map +1 -1
- package/dist/client/Mppx.d.ts +7 -7
- package/dist/client/Mppx.d.ts.map +1 -1
- package/dist/client/Mppx.js +3 -3
- package/dist/client/Mppx.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts +10 -10
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +2 -2
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp-sdk/client/McpClient.d.ts +6 -6
- package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
- package/dist/mcp-sdk/client/McpClient.js +4 -4
- package/dist/mcp-sdk/client/McpClient.js.map +1 -1
- package/dist/middlewares/elysia.d.ts +1 -1
- package/dist/middlewares/express.d.ts +1 -1
- package/dist/middlewares/hono.d.ts +1 -1
- package/dist/middlewares/internal/mppx.d.ts +7 -7
- package/dist/middlewares/internal/mppx.d.ts.map +1 -1
- package/dist/middlewares/internal/mppx.js +5 -5
- package/dist/middlewares/internal/mppx.js.map +1 -1
- package/dist/middlewares/nextjs.d.ts +1 -1
- package/dist/proxy/Service.js +2 -2
- package/dist/proxy/Service.js.map +1 -1
- package/dist/server/Methods.d.ts +2 -2
- package/dist/server/Methods.d.ts.map +1 -1
- package/dist/server/Methods.js +2 -2
- package/dist/server/Methods.js.map +1 -1
- package/dist/server/Mppx.d.ts +17 -17
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +9 -9
- package/dist/server/Mppx.js.map +1 -1
- package/dist/stripe/{Intents.d.ts → Methods.d.ts} +22 -22
- package/dist/stripe/Methods.d.ts.map +1 -0
- package/dist/stripe/Methods.js +42 -0
- package/dist/stripe/Methods.js.map +1 -0
- package/dist/stripe/client/Charge.d.ts +40 -27
- package/dist/stripe/client/Charge.d.ts.map +1 -1
- package/dist/stripe/client/Charge.js +15 -7
- package/dist/stripe/client/Charge.js.map +1 -1
- package/dist/stripe/client/{MethodIntents.d.ts → Methods.d.ts} +24 -23
- package/dist/stripe/client/Methods.d.ts.map +1 -0
- package/dist/stripe/client/{MethodIntents.js → Methods.js} +3 -3
- package/dist/stripe/client/Methods.js.map +1 -0
- package/dist/stripe/client/index.d.ts +1 -1
- package/dist/stripe/client/index.d.ts.map +1 -1
- package/dist/stripe/client/index.js +1 -1
- package/dist/stripe/client/index.js.map +1 -1
- package/dist/stripe/index.d.ts +1 -1
- package/dist/stripe/index.d.ts.map +1 -1
- package/dist/stripe/index.js +1 -1
- package/dist/stripe/index.js.map +1 -1
- package/dist/stripe/internal/types.d.ts +25 -0
- package/dist/stripe/internal/types.d.ts.map +1 -0
- package/dist/stripe/internal/types.js +2 -0
- package/dist/stripe/internal/types.js.map +1 -0
- package/dist/stripe/server/Charge.d.ts +47 -28
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +90 -32
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/{MethodIntents.d.ts → Methods.d.ts} +24 -23
- package/dist/stripe/server/Methods.d.ts.map +1 -0
- package/dist/stripe/server/{MethodIntents.js → Methods.js} +3 -3
- package/dist/stripe/server/Methods.js.map +1 -0
- package/dist/stripe/server/index.d.ts +1 -1
- package/dist/stripe/server/index.d.ts.map +1 -1
- package/dist/stripe/server/index.js +1 -1
- package/dist/stripe/server/index.js.map +1 -1
- package/dist/tempo/{Intents.d.ts → Methods.d.ts} +72 -69
- package/dist/tempo/Methods.d.ts.map +1 -0
- package/dist/tempo/Methods.js +118 -0
- package/dist/tempo/Methods.js.map +1 -0
- package/dist/tempo/client/ChannelOps.d.ts +1 -1
- package/dist/tempo/client/ChannelOps.js +1 -1
- package/dist/tempo/client/Charge.d.ts +25 -25
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +3 -3
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/{MethodIntents.d.ts → Methods.d.ts} +74 -70
- package/dist/tempo/client/Methods.d.ts.map +1 -0
- package/dist/tempo/client/{MethodIntents.js → Methods.js} +3 -3
- package/dist/tempo/client/Methods.js.map +1 -0
- package/dist/tempo/client/Session.d.ts +49 -45
- package/dist/tempo/client/Session.d.ts.map +1 -1
- package/dist/tempo/client/Session.js +4 -4
- package/dist/tempo/client/Session.js.map +1 -1
- package/dist/tempo/client/SessionManager.d.ts +1 -1
- package/dist/tempo/client/SessionManager.js +1 -1
- package/dist/tempo/client/index.d.ts +1 -1
- package/dist/tempo/client/index.d.ts.map +1 -1
- package/dist/tempo/client/index.js +1 -1
- package/dist/tempo/client/index.js.map +1 -1
- package/dist/tempo/index.d.ts +1 -1
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +1 -1
- package/dist/tempo/index.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +27 -27
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +3 -3
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/{MethodIntents.d.ts → Methods.d.ts} +73 -69
- package/dist/tempo/server/Methods.d.ts.map +1 -0
- package/dist/tempo/server/{MethodIntents.js → Methods.js} +4 -4
- package/dist/tempo/server/Methods.js.map +1 -0
- package/dist/tempo/server/Session.d.ts +51 -47
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js +4 -4
- package/dist/tempo/server/Session.js.map +1 -1
- package/dist/tempo/server/index.d.ts +6 -0
- package/dist/tempo/server/index.d.ts.map +1 -0
- package/dist/tempo/server/index.js +6 -0
- package/dist/tempo/server/index.js.map +1 -0
- package/package.json +1 -1
- package/src/Challenge.test-d.ts +3 -3
- package/src/Challenge.test.ts +6 -6
- package/src/Challenge.ts +32 -32
- package/src/Errors.test.ts +75 -21
- package/src/Errors.ts +74 -9
- package/src/Method.test.ts +76 -0
- package/src/Method.ts +228 -0
- package/src/PaymentRequest.test.ts +4 -4
- package/src/PaymentRequest.ts +9 -9
- package/src/cli.test.ts +12 -22
- package/src/cli.ts +74 -21
- package/src/client/Methods.ts +2 -2
- package/src/client/Mppx.test-d.ts +6 -6
- package/src/client/Mppx.test.ts +26 -22
- package/src/client/Mppx.ts +10 -10
- package/src/client/Transport.test.ts +2 -2
- package/src/client/internal/Fetch.ts +21 -24
- package/src/index.ts +1 -2
- package/src/mcp-sdk/client/McpClient.ts +11 -13
- package/src/middlewares/elysia.ts +1 -1
- package/src/middlewares/express.ts +1 -1
- package/src/middlewares/hono.ts +1 -1
- package/src/middlewares/internal/mppx.ts +10 -10
- package/src/middlewares/nextjs.ts +1 -1
- package/src/proxy/Service.ts +2 -2
- package/src/server/Methods.ts +2 -2
- package/src/server/Mppx.test-d.ts +27 -29
- package/src/server/Mppx.test.ts +23 -19
- package/src/server/Mppx.ts +43 -43
- package/src/server/Transport.test.ts +3 -3
- package/src/stripe/{Intents.test.ts → Methods.test.ts} +12 -12
- package/src/stripe/Methods.ts +45 -0
- package/src/stripe/client/Charge.test.ts +189 -0
- package/src/stripe/client/Charge.ts +29 -16
- package/src/stripe/client/{MethodIntents.ts → Methods.ts} +2 -2
- package/src/stripe/client/index.ts +1 -1
- package/src/stripe/index.ts +1 -1
- package/src/stripe/internal/types.ts +22 -0
- package/src/stripe/server/Charge.test.ts +241 -0
- package/src/stripe/server/Charge.ts +124 -38
- package/src/stripe/server/{MethodIntents.ts → Methods.ts} +2 -2
- package/src/stripe/server/index.ts +1 -1
- package/src/tempo/{Intents.test.ts → Methods.test.ts} +15 -15
- package/src/tempo/{Intents.ts → Methods.ts} +77 -22
- package/src/tempo/client/ChannelOps.ts +1 -1
- package/src/tempo/client/Charge.ts +3 -3
- package/src/tempo/client/{MethodIntents.ts → Methods.ts} +2 -2
- package/src/tempo/client/Session.ts +4 -4
- package/src/tempo/client/SessionManager.ts +1 -1
- package/src/tempo/client/index.ts +1 -1
- package/src/tempo/index.ts +1 -1
- package/src/tempo/server/Charge.ts +4 -7
- package/src/tempo/server/{MethodIntents.ts → Methods.ts} +3 -3
- package/src/tempo/server/Session.test.ts +4 -7
- package/src/tempo/server/Session.ts +6 -6
- package/src/tempo/server/index.ts +1 -1
- package/dist/Intent.d.ts +0 -101
- package/dist/Intent.d.ts.map +0 -1
- package/dist/Intent.js +0 -83
- package/dist/Intent.js.map +0 -1
- package/dist/MethodIntent.d.ts +0 -225
- package/dist/MethodIntent.d.ts.map +0 -1
- package/dist/MethodIntent.js +0 -156
- package/dist/MethodIntent.js.map +0 -1
- package/dist/stripe/Intents.d.ts.map +0 -1
- package/dist/stripe/Intents.js +0 -27
- package/dist/stripe/Intents.js.map +0 -1
- package/dist/stripe/client/MethodIntents.d.ts.map +0 -1
- package/dist/stripe/client/MethodIntents.js.map +0 -1
- package/dist/stripe/server/MethodIntents.d.ts.map +0 -1
- package/dist/stripe/server/MethodIntents.js.map +0 -1
- package/dist/tempo/Intents.d.ts.map +0 -1
- package/dist/tempo/Intents.js +0 -81
- package/dist/tempo/Intents.js.map +0 -1
- package/dist/tempo/client/MethodIntents.d.ts.map +0 -1
- package/dist/tempo/client/MethodIntents.js.map +0 -1
- package/dist/tempo/server/MethodIntents.d.ts.map +0 -1
- package/dist/tempo/server/MethodIntents.js.map +0 -1
- package/src/Intent.test.ts +0 -180
- package/src/Intent.ts +0 -109
- package/src/MethodIntent.test.ts +0 -303
- package/src/MethodIntent.ts +0 -388
- package/src/stripe/Intents.ts +0 -27
|
@@ -1,22 +1,37 @@
|
|
|
1
|
+
import type * as Credential from '../../Credential.js'
|
|
1
2
|
import {
|
|
2
3
|
PaymentActionRequiredError,
|
|
3
4
|
PaymentExpiredError,
|
|
4
5
|
VerificationFailedError,
|
|
5
6
|
} from '../../Errors.js'
|
|
6
|
-
import type { LooseOmit } from '../../internal/types.js'
|
|
7
|
-
import * as
|
|
8
|
-
import
|
|
7
|
+
import type { LooseOmit, OneOf } from '../../internal/types.js'
|
|
8
|
+
import * as Method from '../../Method.js'
|
|
9
|
+
import type { StripeClient } from '../internal/types.js'
|
|
10
|
+
import * as Methods from '../Methods.js'
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Creates a Stripe charge method intent for usage on the server.
|
|
12
14
|
*
|
|
13
15
|
* Verifies payment by creating a Stripe PaymentIntent with the provided SPT.
|
|
14
16
|
*
|
|
17
|
+
* Accepts either a `client` (a pre-configured Stripe SDK instance) or a raw
|
|
18
|
+
* `secretKey`. Using `client` is recommended—it lets you configure retries,
|
|
19
|
+
* API version, and other options on the Stripe instance you control.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import Stripe from 'stripe'
|
|
24
|
+
* import { stripe } from 'mppx/server'
|
|
25
|
+
*
|
|
26
|
+
* const stripeClient = new Stripe(process.env.STRIPE_SECRET_KEY!)
|
|
27
|
+
* const charge = stripe.charge({ client: stripeClient, networkId: 'internal', paymentMethodTypes: ['card'] })
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
15
30
|
* @example
|
|
16
31
|
* ```ts
|
|
17
32
|
* import { stripe } from 'mppx/server'
|
|
18
33
|
*
|
|
19
|
-
* const charge = stripe.charge({ secretKey: 'sk_...' })
|
|
34
|
+
* const charge = stripe.charge({ secretKey: 'sk_...', networkId: 'internal', paymentMethodTypes: ['card'] })
|
|
20
35
|
* ```
|
|
21
36
|
*/
|
|
22
37
|
export function charge<const parameters extends charge.Parameters>(parameters: parameters) {
|
|
@@ -29,11 +44,13 @@ export function charge<const parameters extends charge.Parameters>(parameters: p
|
|
|
29
44
|
metadata,
|
|
30
45
|
networkId,
|
|
31
46
|
paymentMethodTypes,
|
|
32
|
-
secretKey,
|
|
33
47
|
} = parameters
|
|
34
48
|
|
|
49
|
+
const client = 'client' in parameters ? parameters.client : undefined
|
|
50
|
+
const secretKey = 'secretKey' in parameters ? parameters.secretKey : undefined
|
|
51
|
+
|
|
35
52
|
type Defaults = charge.DeriveDefaults<parameters>
|
|
36
|
-
return
|
|
53
|
+
return Method.toServer<typeof Methods.charge, Defaults>(Methods.charge, {
|
|
37
54
|
defaults: {
|
|
38
55
|
amount,
|
|
39
56
|
currency,
|
|
@@ -52,41 +69,25 @@ export function charge<const parameters extends charge.Parameters>(parameters: p
|
|
|
52
69
|
if (request.expires && new Date(request.expires) < new Date())
|
|
53
70
|
throw new PaymentExpiredError({ expires: request.expires })
|
|
54
71
|
|
|
55
|
-
const parsed =
|
|
72
|
+
const parsed = Methods.charge.schema.credential.payload.safeParse(credential.payload)
|
|
56
73
|
if (!parsed.success) throw new Error('Invalid credential payload: missing or malformed spt')
|
|
57
74
|
const { spt, externalId: credentialExternalId } = parsed.data as {
|
|
58
75
|
spt: string
|
|
59
76
|
externalId?: string
|
|
60
77
|
}
|
|
61
78
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
currency: request.currency as string,
|
|
65
|
-
shared_payment_granted_token: spt,
|
|
66
|
-
confirm: 'true',
|
|
67
|
-
'automatic_payment_methods[enabled]': 'true',
|
|
68
|
-
'automatic_payment_methods[allow_redirects]': 'never',
|
|
69
|
-
})
|
|
70
|
-
const resolvedMetadata = request.methodDetails?.metadata as Record<string, string> | undefined
|
|
71
|
-
if (resolvedMetadata) {
|
|
72
|
-
for (const [key, value] of Object.entries(resolvedMetadata)) {
|
|
73
|
-
body.set(`metadata[${key}]`, value)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
79
|
+
const userMetadata = request.methodDetails?.metadata as Record<string, string> | undefined
|
|
80
|
+
const resolvedMetadata = { ...buildAnalytics({ credential }), ...userMetadata }
|
|
76
81
|
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (!response.ok) throw new VerificationFailedError({ reason: 'Stripe PaymentIntent failed' })
|
|
88
|
-
|
|
89
|
-
const pi = (await response.json()) as { id: string; status: string }
|
|
82
|
+
const pi = client
|
|
83
|
+
? await createWithClient({ client, challenge, request, spt, metadata: resolvedMetadata })
|
|
84
|
+
: await createWithSecretKey({
|
|
85
|
+
secretKey: secretKey!,
|
|
86
|
+
challenge,
|
|
87
|
+
request,
|
|
88
|
+
spt,
|
|
89
|
+
metadata: resolvedMetadata,
|
|
90
|
+
})
|
|
90
91
|
|
|
91
92
|
if (pi.status === 'requires_action') {
|
|
92
93
|
throw new PaymentActionRequiredError({ reason: 'Stripe PaymentIntent requires action' })
|
|
@@ -105,17 +106,102 @@ export function charge<const parameters extends charge.Parameters>(parameters: p
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
export declare namespace charge {
|
|
108
|
-
type Defaults = LooseOmit<
|
|
109
|
+
type Defaults = LooseOmit<Method.RequestDefaults<typeof Methods.charge>, 'recipient'>
|
|
109
110
|
|
|
110
111
|
type Parameters = {
|
|
111
|
-
/** Stripe secret API key. */
|
|
112
|
-
secretKey: string
|
|
113
112
|
/** Optional metadata to include in SPT creation requests. */
|
|
114
113
|
metadata?: Record<string, string> | undefined
|
|
115
|
-
} & Defaults
|
|
114
|
+
} & Defaults &
|
|
115
|
+
OneOf<
|
|
116
|
+
| {
|
|
117
|
+
/** Pre-configured Stripe SDK instance. Any object matching the duck-typed `StripeClient` shape works. */
|
|
118
|
+
client: StripeClient
|
|
119
|
+
}
|
|
120
|
+
| {
|
|
121
|
+
/** Stripe secret API key. */
|
|
122
|
+
secretKey: string
|
|
123
|
+
}
|
|
124
|
+
>
|
|
116
125
|
|
|
117
126
|
type DeriveDefaults<parameters extends Parameters> = Pick<
|
|
118
127
|
parameters,
|
|
119
128
|
Extract<keyof parameters, keyof Defaults>
|
|
120
129
|
> & { decimals: number }
|
|
121
130
|
}
|
|
131
|
+
|
|
132
|
+
/** Creates a PaymentIntent using the Stripe SDK client. */
|
|
133
|
+
async function createWithClient(parameters: {
|
|
134
|
+
client: StripeClient
|
|
135
|
+
challenge: { id: string }
|
|
136
|
+
metadata: Record<string, string>
|
|
137
|
+
request: { amount: unknown; currency: unknown }
|
|
138
|
+
spt: string
|
|
139
|
+
}): Promise<{ id: string; status: string }> {
|
|
140
|
+
const { client, challenge, metadata, request, spt } = parameters
|
|
141
|
+
try {
|
|
142
|
+
const result = await client.paymentIntents.create(
|
|
143
|
+
{
|
|
144
|
+
amount: Number(request.amount),
|
|
145
|
+
automatic_payment_methods: { allow_redirects: 'never', enabled: true },
|
|
146
|
+
confirm: true,
|
|
147
|
+
currency: request.currency as string,
|
|
148
|
+
metadata,
|
|
149
|
+
payment_method: spt,
|
|
150
|
+
},
|
|
151
|
+
{ idempotencyKey: `mppx_${challenge.id}_${spt}` },
|
|
152
|
+
)
|
|
153
|
+
return { id: result.id, status: result.status }
|
|
154
|
+
} catch {
|
|
155
|
+
throw new VerificationFailedError({ reason: 'Stripe PaymentIntent failed' })
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Creates a PaymentIntent using a raw secret key and fetch. */
|
|
160
|
+
async function createWithSecretKey(parameters: {
|
|
161
|
+
secretKey: string
|
|
162
|
+
challenge: { id: string }
|
|
163
|
+
metadata: Record<string, string>
|
|
164
|
+
request: { amount: unknown; currency: unknown }
|
|
165
|
+
spt: string
|
|
166
|
+
}): Promise<{ id: string; status: string }> {
|
|
167
|
+
const { secretKey, challenge, metadata, request, spt } = parameters
|
|
168
|
+
|
|
169
|
+
const body = new URLSearchParams({
|
|
170
|
+
amount: request.amount as string,
|
|
171
|
+
'automatic_payment_methods[allow_redirects]': 'never',
|
|
172
|
+
'automatic_payment_methods[enabled]': 'true',
|
|
173
|
+
confirm: 'true',
|
|
174
|
+
currency: request.currency as string,
|
|
175
|
+
shared_payment_granted_token: spt,
|
|
176
|
+
})
|
|
177
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
178
|
+
body.set(`metadata[${key}]`, value)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const response = await fetch('https://api.stripe.com/v1/payment_intents', {
|
|
182
|
+
method: 'POST',
|
|
183
|
+
headers: {
|
|
184
|
+
Authorization: `Basic ${btoa(`${secretKey}:`)}`,
|
|
185
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
186
|
+
'Idempotency-Key': `mppx_${challenge.id}_${spt}`,
|
|
187
|
+
},
|
|
188
|
+
body,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
if (!response.ok) throw new VerificationFailedError({ reason: 'Stripe PaymentIntent failed' })
|
|
192
|
+
return (await response.json()) as { id: string; status: string }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** @internal */
|
|
196
|
+
function buildAnalytics(parameters: { credential: Credential.Credential }): Record<string, string> {
|
|
197
|
+
const { credential } = parameters
|
|
198
|
+
const { challenge } = credential
|
|
199
|
+
return {
|
|
200
|
+
mpp_version: '1',
|
|
201
|
+
mpp_is_mpp: 'true',
|
|
202
|
+
mpp_intent: challenge.intent,
|
|
203
|
+
mpp_challenge_id: challenge.id,
|
|
204
|
+
mpp_server_id: challenge.realm,
|
|
205
|
+
...(credential.source ? { mpp_client_id: credential.source } : {}),
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { charge as charge_ } from './Charge.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Creates a Stripe `charge` method
|
|
4
|
+
* Creates a Stripe `charge` method for usage on the server.
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
7
|
* ```ts
|
|
@@ -19,6 +19,6 @@ export function stripe<const parameters extends stripe.Parameters>(parameters: p
|
|
|
19
19
|
export namespace stripe {
|
|
20
20
|
export type Parameters = charge_.Parameters
|
|
21
21
|
|
|
22
|
-
/** Creates a Stripe `charge` method
|
|
22
|
+
/** Creates a Stripe `charge` method for SPT-based payments. */
|
|
23
23
|
export const charge = charge_
|
|
24
24
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { charge } from './Charge.js'
|
|
2
|
-
export { stripe } from './
|
|
2
|
+
export { stripe } from './Methods.js'
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Methods } from 'mppx/tempo'
|
|
2
2
|
import { describe, expect, expectTypeOf, test } from 'vitest'
|
|
3
3
|
|
|
4
4
|
describe('charge', () => {
|
|
5
|
-
test('has correct name and
|
|
6
|
-
expect(
|
|
7
|
-
expect(
|
|
5
|
+
test('has correct name and intent', () => {
|
|
6
|
+
expect(Methods.charge.intent).toBe('charge')
|
|
7
|
+
expect(Methods.charge.name).toBe('tempo')
|
|
8
8
|
})
|
|
9
9
|
|
|
10
|
-
test('types:
|
|
11
|
-
expectTypeOf(
|
|
10
|
+
test('types: intent is literal', () => {
|
|
11
|
+
expectTypeOf(Methods.charge.intent).toEqualTypeOf<'charge'>()
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
test('types:
|
|
15
|
-
expectTypeOf(
|
|
14
|
+
test('types: name is literal', () => {
|
|
15
|
+
expectTypeOf(Methods.charge.name).toEqualTypeOf<'tempo'>()
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
test('schema: validates valid request', () => {
|
|
19
|
-
const result =
|
|
19
|
+
const result = Methods.charge.schema.request.safeParse({
|
|
20
20
|
amount: '1',
|
|
21
21
|
currency: '0x20c0000000000000000000000000000000000001',
|
|
22
22
|
decimals: 6,
|
|
@@ -27,7 +27,7 @@ describe('charge', () => {
|
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
test('schema: validates request with methodDetails', () => {
|
|
30
|
-
const result =
|
|
30
|
+
const result = Methods.charge.schema.request.safeParse({
|
|
31
31
|
amount: '1',
|
|
32
32
|
currency: '0x20c0000000000000000000000000000000000001',
|
|
33
33
|
decimals: 6,
|
|
@@ -40,7 +40,7 @@ describe('charge', () => {
|
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
test('schema: validates request with memo', () => {
|
|
43
|
-
const result =
|
|
43
|
+
const result = Methods.charge.schema.request.safeParse({
|
|
44
44
|
amount: '1',
|
|
45
45
|
currency: '0x20c0000000000000000000000000000000000001',
|
|
46
46
|
decimals: 6,
|
|
@@ -52,14 +52,14 @@ describe('charge', () => {
|
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
test('schema: rejects invalid request', () => {
|
|
55
|
-
const result =
|
|
55
|
+
const result = Methods.charge.schema.request.safeParse({
|
|
56
56
|
amount: '1',
|
|
57
57
|
})
|
|
58
58
|
expect(result.success).toBe(false)
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
test('schema: validates transaction payload', () => {
|
|
62
|
-
const result =
|
|
62
|
+
const result = Methods.charge.schema.credential.payload.safeParse({
|
|
63
63
|
signature: '0x76f90100000000000000000000000000000000000000000000000000000000000000000000',
|
|
64
64
|
type: 'transaction',
|
|
65
65
|
})
|
|
@@ -67,7 +67,7 @@ describe('charge', () => {
|
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
test('schema: validates hash payload', () => {
|
|
70
|
-
const result =
|
|
70
|
+
const result = Methods.charge.schema.credential.payload.safeParse({
|
|
71
71
|
hash: '0x1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
72
72
|
type: 'hash',
|
|
73
73
|
})
|
|
@@ -75,7 +75,7 @@ describe('charge', () => {
|
|
|
75
75
|
})
|
|
76
76
|
|
|
77
77
|
test('schema: rejects invalid payload type', () => {
|
|
78
|
-
const result =
|
|
78
|
+
const result = Methods.charge.schema.credential.payload.safeParse({
|
|
79
79
|
signature: '0x...',
|
|
80
80
|
type: 'keyAuthorization',
|
|
81
81
|
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Account } from 'viem'
|
|
2
|
-
import
|
|
3
|
-
import * as
|
|
2
|
+
import { parseUnits } from 'viem'
|
|
3
|
+
import * as Expires from '../Expires.js'
|
|
4
|
+
import * as Method from '../Method.js'
|
|
4
5
|
import * as z from '../zod.js'
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -8,8 +9,9 @@ import * as z from '../zod.js'
|
|
|
8
9
|
*
|
|
9
10
|
* @see https://github.com/tempoxyz/payment-auth-spec/blob/main/specs/methods/tempo/draft-tempo-charge-00.md
|
|
10
11
|
*/
|
|
11
|
-
export const charge =
|
|
12
|
-
|
|
12
|
+
export const charge = Method.from({
|
|
13
|
+
name: 'tempo',
|
|
14
|
+
intent: 'charge',
|
|
13
15
|
schema: {
|
|
14
16
|
credential: {
|
|
15
17
|
payload: z.discriminatedUnion('type', [
|
|
@@ -17,9 +19,15 @@ export const charge = MethodIntent.fromIntent(Intent.charge, {
|
|
|
17
19
|
z.object({ signature: z.signature(), type: z.literal('transaction') }),
|
|
18
20
|
]),
|
|
19
21
|
},
|
|
20
|
-
request:
|
|
21
|
-
|
|
22
|
+
request: z.pipe(
|
|
23
|
+
z.object({
|
|
24
|
+
amount: z.amount(),
|
|
22
25
|
chainId: z.optional(z.number()),
|
|
26
|
+
currency: z.string(),
|
|
27
|
+
decimals: z.number(),
|
|
28
|
+
description: z.optional(z.string()),
|
|
29
|
+
expires: z._default(z.datetime(), () => Expires.minutes(5)),
|
|
30
|
+
externalId: z.optional(z.string()),
|
|
23
31
|
feePayer: z.optional(
|
|
24
32
|
z.pipe(
|
|
25
33
|
z.union([z.boolean(), z.custom<Account>()]),
|
|
@@ -27,9 +35,22 @@ export const charge = MethodIntent.fromIntent(Intent.charge, {
|
|
|
27
35
|
),
|
|
28
36
|
),
|
|
29
37
|
memo: z.optional(z.hash()),
|
|
38
|
+
recipient: z.optional(z.string()),
|
|
30
39
|
}),
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
z.transform(({ amount, chainId, decimals, feePayer, memo, ...rest }) => ({
|
|
41
|
+
...rest,
|
|
42
|
+
amount: parseUnits(amount, decimals).toString(),
|
|
43
|
+
...(chainId !== undefined || feePayer !== undefined || memo !== undefined
|
|
44
|
+
? {
|
|
45
|
+
methodDetails: {
|
|
46
|
+
...(chainId !== undefined && { chainId }),
|
|
47
|
+
...(feePayer !== undefined && { feePayer }),
|
|
48
|
+
...(memo !== undefined && { memo }),
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
: {}),
|
|
52
|
+
})),
|
|
53
|
+
),
|
|
33
54
|
},
|
|
34
55
|
})
|
|
35
56
|
|
|
@@ -39,26 +60,27 @@ export const charge = MethodIntent.fromIntent(Intent.charge, {
|
|
|
39
60
|
* Uses cumulative vouchers over a payment channel. Credential payloads
|
|
40
61
|
* are a discriminated union on `action`: open, topUp, voucher, close.
|
|
41
62
|
*/
|
|
42
|
-
export const session =
|
|
43
|
-
|
|
63
|
+
export const session = Method.from({
|
|
64
|
+
name: 'tempo',
|
|
65
|
+
intent: 'session',
|
|
44
66
|
schema: {
|
|
45
67
|
credential: {
|
|
46
68
|
payload: z.discriminatedUnion('action', [
|
|
47
69
|
z.object({
|
|
48
70
|
action: z.literal('open'),
|
|
49
|
-
type: z.literal('transaction'),
|
|
50
|
-
channelId: z.hash(),
|
|
51
|
-
transaction: z.signature(),
|
|
52
71
|
authorizedSigner: z.optional(z.string()),
|
|
72
|
+
channelId: z.hash(),
|
|
53
73
|
cumulativeAmount: z.amount(),
|
|
54
74
|
signature: z.signature(),
|
|
75
|
+
transaction: z.signature(),
|
|
76
|
+
type: z.literal('transaction'),
|
|
55
77
|
}),
|
|
56
78
|
z.object({
|
|
57
79
|
action: z.literal('topUp'),
|
|
58
|
-
|
|
80
|
+
additionalDeposit: z.amount(),
|
|
59
81
|
channelId: z.hash(),
|
|
60
82
|
transaction: z.signature(),
|
|
61
|
-
|
|
83
|
+
type: z.literal('transaction'),
|
|
62
84
|
}),
|
|
63
85
|
z.object({
|
|
64
86
|
action: z.literal('voucher'),
|
|
@@ -74,20 +96,53 @@ export const session = MethodIntent.fromIntent(Intent.session, {
|
|
|
74
96
|
}),
|
|
75
97
|
]),
|
|
76
98
|
},
|
|
77
|
-
request:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
channelId: z.optional(z.hash()),
|
|
81
|
-
minVoucherDelta: z.optional(z.amount()),
|
|
99
|
+
request: z.pipe(
|
|
100
|
+
z.object({
|
|
101
|
+
amount: z.amount(),
|
|
82
102
|
chainId: z.optional(z.number()),
|
|
103
|
+
channelId: z.optional(z.hash()),
|
|
104
|
+
currency: z.string(),
|
|
105
|
+
decimals: z.number(),
|
|
106
|
+
escrowContract: z.optional(z.string()),
|
|
83
107
|
feePayer: z.optional(
|
|
84
108
|
z.pipe(
|
|
85
109
|
z.union([z.boolean(), z.custom<Account>()]),
|
|
86
110
|
z.transform((v): boolean => (typeof v === 'object' ? true : v)),
|
|
87
111
|
),
|
|
88
112
|
),
|
|
113
|
+
minVoucherDelta: z.optional(z.amount()),
|
|
114
|
+
recipient: z.optional(z.string()),
|
|
115
|
+
suggestedDeposit: z.optional(z.amount()),
|
|
116
|
+
unitType: z.string(),
|
|
89
117
|
}),
|
|
90
|
-
|
|
91
|
-
|
|
118
|
+
z.transform(
|
|
119
|
+
({
|
|
120
|
+
amount,
|
|
121
|
+
chainId,
|
|
122
|
+
channelId,
|
|
123
|
+
decimals,
|
|
124
|
+
escrowContract,
|
|
125
|
+
feePayer,
|
|
126
|
+
minVoucherDelta,
|
|
127
|
+
suggestedDeposit,
|
|
128
|
+
...rest
|
|
129
|
+
}) => ({
|
|
130
|
+
...rest,
|
|
131
|
+
amount: parseUnits(amount, decimals).toString(),
|
|
132
|
+
...(suggestedDeposit
|
|
133
|
+
? {
|
|
134
|
+
suggestedDeposit: parseUnits(suggestedDeposit, decimals).toString(),
|
|
135
|
+
}
|
|
136
|
+
: {}),
|
|
137
|
+
methodDetails: {
|
|
138
|
+
escrowContract,
|
|
139
|
+
...(channelId !== undefined && { channelId }),
|
|
140
|
+
...(minVoucherDelta !== undefined && { minVoucherDelta }),
|
|
141
|
+
...(chainId !== undefined && { chainId }),
|
|
142
|
+
...(feePayer !== undefined && { feePayer }),
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
),
|
|
146
|
+
),
|
|
92
147
|
},
|
|
93
148
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared client-side channel operations.
|
|
3
3
|
*
|
|
4
|
-
* Provides the low-level helpers that both `session()`
|
|
4
|
+
* Provides the low-level helpers that both `session()`
|
|
5
5
|
* and `sessionManager()` (orchestrator) rely on: escrow resolution, channel
|
|
6
6
|
* ID computation, on-chain open/voucher/close payload construction, channel
|
|
7
7
|
* recovery from on-chain state, and credential serialization.
|
|
@@ -3,13 +3,13 @@ import { prepareTransactionRequest, signTransaction } from 'viem/actions'
|
|
|
3
3
|
import { tempo as tempo_chain } from 'viem/chains'
|
|
4
4
|
import { Actions } from 'viem/tempo'
|
|
5
5
|
import * as Credential from '../../Credential.js'
|
|
6
|
-
import * as
|
|
6
|
+
import * as Method from '../../Method.js'
|
|
7
7
|
import * as Account from '../../viem/Account.js'
|
|
8
8
|
import * as Client from '../../viem/Client.js'
|
|
9
9
|
import * as z from '../../zod.js'
|
|
10
10
|
import * as Attribution from '../Attribution.js'
|
|
11
|
-
import * as Intents from '../Intents.js'
|
|
12
11
|
import * as defaults from '../internal/defaults.js'
|
|
12
|
+
import * as Methods from '../Methods.js'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Creates a Tempo charge method intent for usage on the client.
|
|
@@ -33,7 +33,7 @@ export function charge(parameters: charge.Parameters = {}) {
|
|
|
33
33
|
})
|
|
34
34
|
const getAccount = Account.getResolver({ account: parameters.account })
|
|
35
35
|
|
|
36
|
-
return
|
|
36
|
+
return Method.toClient(Methods.charge, {
|
|
37
37
|
context: z.object({
|
|
38
38
|
account: z.optional(z.custom<Account.getResolver.Parameters['account']>()),
|
|
39
39
|
}),
|
|
@@ -3,7 +3,7 @@ import { session as sessionIntent_ } from './Session.js'
|
|
|
3
3
|
import { sessionManager as session_ } from './SessionManager.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Creates both Tempo `charge` and `session` client
|
|
6
|
+
* Creates both Tempo `charge` and `session` client methods from shared parameters.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
@@ -21,7 +21,7 @@ export function tempo(parameters: tempo.Parameters = {}) {
|
|
|
21
21
|
export namespace tempo {
|
|
22
22
|
export type Parameters = charge_.Parameters & sessionIntent_.Parameters
|
|
23
23
|
|
|
24
|
-
/** Creates a Tempo `charge` client method
|
|
24
|
+
/** Creates a Tempo `charge` client method for one-time TIP-20 token transfers. */
|
|
25
25
|
export const charge = charge_
|
|
26
26
|
/** Creates a client-side streaming session for managing payment channels. */
|
|
27
27
|
export const session = session_
|
|
@@ -2,12 +2,12 @@ import type { Hex } from 'ox'
|
|
|
2
2
|
import { type Address, parseUnits, type Account as viem_Account } from 'viem'
|
|
3
3
|
import { tempo as tempo_chain } from 'viem/chains'
|
|
4
4
|
import type * as Challenge from '../../Challenge.js'
|
|
5
|
-
import * as
|
|
5
|
+
import * as Method from '../../Method.js'
|
|
6
6
|
import * as Account from '../../viem/Account.js'
|
|
7
7
|
import * as Client from '../../viem/Client.js'
|
|
8
8
|
import * as z from '../../zod.js'
|
|
9
|
-
import * as Intents from '../Intents.js'
|
|
10
9
|
import * as defaults from '../internal/defaults.js'
|
|
10
|
+
import * as Methods from '../Methods.js'
|
|
11
11
|
import type { StreamCredentialPayload } from '../stream/Types.js'
|
|
12
12
|
import { signVoucher } from '../stream/Voucher.js'
|
|
13
13
|
import {
|
|
@@ -35,7 +35,7 @@ export const streamContextSchema = z.object({
|
|
|
35
35
|
export type StreamContext = z.infer<typeof streamContextSchema>
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Creates a session payment
|
|
38
|
+
* Creates a session payment method for use with `Mppx.create()`.
|
|
39
39
|
*
|
|
40
40
|
* Supports both auto mode (set `deposit` to manage channels automatically)
|
|
41
41
|
* and manual mode (pass `context.action` to control each step).
|
|
@@ -330,7 +330,7 @@ export function session(parameters: session.Parameters = {}) {
|
|
|
330
330
|
return serializeCredential(challenge, payload, chainId, account)
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
-
return
|
|
333
|
+
return Method.toClient(Methods.session, {
|
|
334
334
|
context: streamContextSchema,
|
|
335
335
|
|
|
336
336
|
async createCredential({ challenge, context }) {
|
|
@@ -38,7 +38,7 @@ export type PaymentResponse = Response & {
|
|
|
38
38
|
* Creates a session manager that handles the full client payment lifecycle:
|
|
39
39
|
* channel open, incremental vouchers, SSE streaming, and channel close.
|
|
40
40
|
*
|
|
41
|
-
* Internally delegates to the `session()`
|
|
41
|
+
* Internally delegates to the `session()` method for all
|
|
42
42
|
* channel state management and credential creation, and to `Fetch.from`
|
|
43
43
|
* for the 402 challenge/retry flow.
|
|
44
44
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { charge } from './Charge.js'
|
|
2
|
-
export { tempo } from './
|
|
2
|
+
export { tempo } from './Methods.js'
|
|
3
3
|
export { session } from './Session.js'
|
|
4
4
|
export type { PaymentResponse, SessionManager } from './SessionManager.js'
|
|
5
5
|
export { sessionManager } from './SessionManager.js'
|
package/src/tempo/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * as
|
|
1
|
+
export * as Methods from './Methods.js'
|
|
2
2
|
export * as Stream from './stream/index.js'
|
|
@@ -10,12 +10,12 @@ import { tempo as tempo_chain } from 'viem/chains'
|
|
|
10
10
|
import { Abis, Transaction } from 'viem/tempo'
|
|
11
11
|
import { PaymentExpiredError } from '../../Errors.js'
|
|
12
12
|
import type { LooseOmit } from '../../internal/types.js'
|
|
13
|
-
import * as
|
|
13
|
+
import * as Method from '../../Method.js'
|
|
14
14
|
import * as Client from '../../viem/Client.js'
|
|
15
|
-
import * as Intents from '../Intents.js'
|
|
16
15
|
import * as Account from '../internal/account.js'
|
|
17
16
|
import * as defaults from '../internal/defaults.js'
|
|
18
17
|
import type * as types from '../internal/types.js'
|
|
18
|
+
import * as Methods from '../Methods.js'
|
|
19
19
|
|
|
20
20
|
const transferSelector = /*#__PURE__*/ toFunctionSelector(
|
|
21
21
|
'function transfer(address to, uint256 amount)',
|
|
@@ -56,7 +56,7 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
56
56
|
})
|
|
57
57
|
|
|
58
58
|
type Defaults = charge.DeriveDefaults<parameters>
|
|
59
|
-
return
|
|
59
|
+
return Method.toServer<typeof Methods.charge, Defaults>(Methods.charge, {
|
|
60
60
|
defaults: {
|
|
61
61
|
amount,
|
|
62
62
|
currency,
|
|
@@ -265,10 +265,7 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
export declare namespace charge {
|
|
268
|
-
type Defaults = LooseOmit<
|
|
269
|
-
MethodIntent.RequestDefaults<typeof Intents.charge>,
|
|
270
|
-
'feePayer' | 'recipient'
|
|
271
|
-
>
|
|
268
|
+
type Defaults = LooseOmit<Method.RequestDefaults<typeof Methods.charge>, 'feePayer' | 'recipient'>
|
|
272
269
|
|
|
273
270
|
type Parameters = {
|
|
274
271
|
/** Testnet mode. */
|
|
@@ -2,7 +2,7 @@ import { charge as charge_ } from './Charge.js'
|
|
|
2
2
|
import { session as session_, settle as settle_ } from './Session.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Creates both Tempo `charge` and `session`
|
|
5
|
+
* Creates both Tempo `charge` and `session` methods from shared parameters.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* ```ts
|
|
@@ -20,9 +20,9 @@ export function tempo<const parameters extends tempo.Parameters>(parameters?: pa
|
|
|
20
20
|
export namespace tempo {
|
|
21
21
|
export type Parameters = charge_.Parameters & session_.Parameters
|
|
22
22
|
|
|
23
|
-
/** Creates a Tempo `charge` method
|
|
23
|
+
/** Creates a Tempo `charge` method for one-time TIP-20 token transfers. */
|
|
24
24
|
export const charge = charge_
|
|
25
|
-
/** Creates a Tempo `session` method
|
|
25
|
+
/** Creates a Tempo `session` method for session-based TIP-20 token payments. */
|
|
26
26
|
export const session = session_
|
|
27
27
|
/** One-shot settle: reads highest voucher from storage and submits on-chain. */
|
|
28
28
|
export const settle = settle_
|