mppx 0.6.19 → 0.6.20
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 +7 -0
- package/dist/Challenge.d.ts +2 -2
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +1 -1
- package/dist/Challenge.js.map +1 -1
- package/dist/Method.d.ts +34 -0
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +3 -1
- package/dist/Method.js.map +1 -1
- package/dist/Receipt.d.ts +1 -0
- package/dist/Receipt.d.ts.map +1 -1
- package/dist/Receipt.js +2 -0
- package/dist/Receipt.js.map +1 -1
- package/dist/client/Methods.d.ts +1 -0
- package/dist/client/Methods.d.ts.map +1 -1
- package/dist/client/Methods.js +1 -0
- package/dist/client/Methods.js.map +1 -1
- package/dist/middlewares/elysia.d.ts.map +1 -1
- package/dist/middlewares/elysia.js +14 -0
- package/dist/middlewares/elysia.js.map +1 -1
- package/dist/middlewares/express.d.ts.map +1 -1
- package/dist/middlewares/express.js +1 -2
- package/dist/middlewares/express.js.map +1 -1
- package/dist/middlewares/hono.d.ts.map +1 -1
- package/dist/middlewares/hono.js +14 -0
- package/dist/middlewares/hono.js.map +1 -1
- package/dist/middlewares/nextjs.d.ts.map +1 -1
- package/dist/middlewares/nextjs.js +14 -0
- package/dist/middlewares/nextjs.js.map +1 -1
- package/dist/proxy/Proxy.d.ts.map +1 -1
- package/dist/proxy/Proxy.js +2 -2
- package/dist/proxy/Proxy.js.map +1 -1
- package/dist/proxy/Service.d.ts.map +1 -1
- package/dist/proxy/Service.js +1 -1
- package/dist/proxy/Service.js.map +1 -1
- package/dist/server/Mppx.d.ts +15 -3
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +190 -40
- package/dist/server/Mppx.js.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/Methods.d.ts +96 -0
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Methods.js +97 -0
- package/dist/tempo/Methods.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +3 -0
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/client/Methods.js +3 -0
- package/dist/tempo/client/Methods.js.map +1 -1
- package/dist/tempo/client/Subscription.d.ts +114 -0
- package/dist/tempo/client/Subscription.d.ts.map +1 -0
- package/dist/tempo/client/Subscription.js +100 -0
- package/dist/tempo/client/Subscription.js.map +1 -0
- package/dist/tempo/client/index.d.ts +1 -0
- package/dist/tempo/client/index.d.ts.map +1 -1
- package/dist/tempo/client/index.js +1 -0
- package/dist/tempo/client/index.js.map +1 -1
- package/dist/tempo/index.d.ts +1 -0
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +1 -0
- package/dist/tempo/index.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +5 -0
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +5 -0
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +221 -0
- package/dist/tempo/server/Subscription.d.ts.map +1 -0
- package/dist/tempo/server/Subscription.js +637 -0
- package/dist/tempo/server/Subscription.js.map +1 -0
- package/dist/tempo/server/index.d.ts +1 -0
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.js +1 -0
- package/dist/tempo/server/index.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +282 -0
- package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -0
- package/dist/tempo/subscription/KeyAuthorization.js +297 -0
- package/dist/tempo/subscription/KeyAuthorization.js.map +1 -0
- package/dist/tempo/subscription/Receipt.d.ts +10 -0
- package/dist/tempo/subscription/Receipt.d.ts.map +1 -0
- package/dist/tempo/subscription/Receipt.js +16 -0
- package/dist/tempo/subscription/Receipt.js.map +1 -0
- package/dist/tempo/subscription/Store.d.ts +99 -0
- package/dist/tempo/subscription/Store.d.ts.map +1 -0
- package/dist/tempo/subscription/Store.js +292 -0
- package/dist/tempo/subscription/Store.js.map +1 -0
- package/dist/tempo/subscription/Types.d.ts +65 -0
- package/dist/tempo/subscription/Types.d.ts.map +1 -0
- package/dist/tempo/subscription/Types.js +2 -0
- package/dist/tempo/subscription/Types.js.map +1 -0
- package/dist/tempo/subscription/index.d.ts +6 -0
- package/dist/tempo/subscription/index.d.ts.map +1 -0
- package/dist/tempo/subscription/index.js +4 -0
- package/dist/tempo/subscription/index.js.map +1 -0
- package/dist/zod.d.ts +7 -0
- package/dist/zod.d.ts.map +1 -1
- package/dist/zod.js +18 -0
- package/dist/zod.js.map +1 -1
- package/package.json +3 -3
- package/src/Challenge.test.ts +13 -0
- package/src/Challenge.ts +3 -3
- package/src/Method.ts +46 -1
- package/src/Receipt.ts +2 -0
- package/src/client/Methods.ts +1 -0
- package/src/middlewares/elysia.test.ts +31 -1
- package/src/middlewares/elysia.ts +13 -0
- package/src/middlewares/express.ts +1 -5
- package/src/middlewares/hono.test.ts +30 -1
- package/src/middlewares/hono.ts +13 -0
- package/src/middlewares/nextjs.test.ts +28 -1
- package/src/middlewares/nextjs.ts +13 -0
- package/src/proxy/Proxy.ts +2 -5
- package/src/proxy/Service.test.ts +34 -0
- package/src/proxy/Service.ts +7 -0
- package/src/server/Mppx.authorize.test.ts +210 -0
- package/src/server/Mppx.test-d.ts +23 -1
- package/src/server/Mppx.test.ts +73 -3
- package/src/server/Mppx.ts +291 -58
- package/src/stripe/server/internal/html/package.json +1 -1
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/Methods.test.ts +131 -0
- package/src/tempo/Methods.ts +136 -0
- package/src/tempo/Subscription.integration.test.ts +591 -0
- package/src/tempo/client/Methods.ts +3 -0
- package/src/tempo/client/Subscription.test.ts +131 -0
- package/src/tempo/client/Subscription.ts +155 -0
- package/src/tempo/client/index.ts +1 -0
- package/src/tempo/index.ts +1 -0
- package/src/tempo/server/Methods.ts +5 -0
- package/src/tempo/server/Subscription.test.ts +1410 -0
- package/src/tempo/server/Subscription.ts +1014 -0
- package/src/tempo/server/index.ts +1 -0
- package/src/tempo/server/internal/html/package.json +1 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/subscription/KeyAuthorization.test.ts +204 -0
- package/src/tempo/subscription/KeyAuthorization.ts +394 -0
- package/src/tempo/subscription/Receipt.ts +28 -0
- package/src/tempo/subscription/Store.test.ts +554 -0
- package/src/tempo/subscription/Store.ts +431 -0
- package/src/tempo/subscription/Types.ts +68 -0
- package/src/tempo/subscription/index.ts +23 -0
- package/src/zod.test.ts +23 -1
- package/src/zod.ts +24 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Challenge, Credential } from 'mppx'
|
|
2
|
+
import { KeyAuthorization } from 'ox/tempo'
|
|
3
|
+
import { privateKeyToAccount } from 'viem/accounts'
|
|
4
|
+
import { describe, expect, test } from 'vp/test'
|
|
5
|
+
|
|
6
|
+
import * as Methods from '../Methods.js'
|
|
7
|
+
import { signSubscriptionKeyAuthorization } from '../subscription/KeyAuthorization.js'
|
|
8
|
+
import type { SubscriptionAccessKey } from '../subscription/Types.js'
|
|
9
|
+
import { subscription } from './Subscription.js'
|
|
10
|
+
|
|
11
|
+
const chainId = 4217
|
|
12
|
+
const currency = '0x20c0000000000000000000000000000000000001'
|
|
13
|
+
const recipient = '0x1234567890abcdef1234567890abcdef12345678'
|
|
14
|
+
const selectedAccount = privateKeyToAccount(
|
|
15
|
+
'0x0000000000000000000000000000000000000000000000000000000000000001',
|
|
16
|
+
)
|
|
17
|
+
const accessAccount = privateKeyToAccount(
|
|
18
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002',
|
|
19
|
+
)
|
|
20
|
+
const otherRootAccount = privateKeyToAccount(
|
|
21
|
+
'0x0000000000000000000000000000000000000000000000000000000000000003',
|
|
22
|
+
)
|
|
23
|
+
const accessKey = {
|
|
24
|
+
accessKeyAddress: accessAccount.address,
|
|
25
|
+
keyType: 'secp256k1',
|
|
26
|
+
} as const satisfies SubscriptionAccessKey
|
|
27
|
+
|
|
28
|
+
type SubscriptionRequest = ReturnType<typeof Methods.subscription.schema.request.parse>
|
|
29
|
+
|
|
30
|
+
function secondsFromNow(milliseconds: number) {
|
|
31
|
+
return new Date(Math.ceil((Date.now() + milliseconds) / 1_000) * 1_000).toISOString()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function createChallenge(
|
|
35
|
+
overrides: Partial<Parameters<typeof Methods.subscription.schema.request.parse>[0]> = {},
|
|
36
|
+
): Challenge.Challenge<SubscriptionRequest, 'subscription', 'tempo'> {
|
|
37
|
+
const request = Methods.subscription.schema.request.parse({
|
|
38
|
+
accessKey,
|
|
39
|
+
amount: '1',
|
|
40
|
+
chainId,
|
|
41
|
+
currency,
|
|
42
|
+
decimals: 6,
|
|
43
|
+
periodCount: '1',
|
|
44
|
+
periodUnit: 'day',
|
|
45
|
+
recipient,
|
|
46
|
+
subscriptionExpires: secondsFromNow(86_400_000),
|
|
47
|
+
...overrides,
|
|
48
|
+
})
|
|
49
|
+
return Challenge.from({
|
|
50
|
+
id: 'test-challenge-id',
|
|
51
|
+
intent: 'subscription',
|
|
52
|
+
method: 'tempo',
|
|
53
|
+
realm: 'api.example.com',
|
|
54
|
+
request,
|
|
55
|
+
}) as Challenge.Challenge<SubscriptionRequest, 'subscription', 'tempo'>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('tempo.subscription client', () => {
|
|
59
|
+
test('uses Tempo testnet as the default subscription chain', async () => {
|
|
60
|
+
const challenge = createChallenge({ chainId: undefined })
|
|
61
|
+
const method = subscription({
|
|
62
|
+
account: selectedAccount,
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const credential = Credential.deserialize(
|
|
66
|
+
await method.createCredential({ challenge, context: {} }),
|
|
67
|
+
)
|
|
68
|
+
const payload = Methods.subscription.schema.credential.payload.parse(credential.payload)
|
|
69
|
+
const authorization = KeyAuthorization.deserialize(payload.signature as `0x${string}`)
|
|
70
|
+
|
|
71
|
+
expect(authorization.chainId).toBe(42431n)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('can reject subscription expiry from custom request validation', async () => {
|
|
75
|
+
const challenge = createChallenge({
|
|
76
|
+
subscriptionExpires: secondsFromNow(2 * 86_400_000),
|
|
77
|
+
})
|
|
78
|
+
const method = subscription({
|
|
79
|
+
account: selectedAccount,
|
|
80
|
+
validateRequest: (request) => {
|
|
81
|
+
const maxExpiry = Date.now() + 86_400_000
|
|
82
|
+
if (new Date(request.subscriptionExpires).getTime() > maxExpiry) {
|
|
83
|
+
throw new Error('subscription expiry too late')
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
await expect(method.createCredential({ challenge, context: {} })).rejects.toThrow(
|
|
89
|
+
'subscription expiry too late',
|
|
90
|
+
)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('runs custom request validation before authorizing the access key', async () => {
|
|
94
|
+
const challenge = createChallenge()
|
|
95
|
+
const method = subscription({
|
|
96
|
+
account: selectedAccount,
|
|
97
|
+
validateRequest: () => {
|
|
98
|
+
throw new Error('unexpected subscription request')
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
await expect(method.createCredential({ challenge, context: {} })).rejects.toThrow(
|
|
103
|
+
'unexpected subscription request',
|
|
104
|
+
)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('rejects key authorizations signed by a different account', async () => {
|
|
108
|
+
const challenge = createChallenge()
|
|
109
|
+
const keyAuthorization = await signSubscriptionKeyAuthorization({
|
|
110
|
+
accessKey,
|
|
111
|
+
account: otherRootAccount,
|
|
112
|
+
chainId,
|
|
113
|
+
request: challenge.request,
|
|
114
|
+
})
|
|
115
|
+
if (!keyAuthorization) throw new Error('expected key authorization')
|
|
116
|
+
|
|
117
|
+
const method = subscription({
|
|
118
|
+
account: selectedAccount.address,
|
|
119
|
+
getClient: async () =>
|
|
120
|
+
({
|
|
121
|
+
request: async () => ({
|
|
122
|
+
keyAuthorization: KeyAuthorization.toRpc(keyAuthorization),
|
|
123
|
+
}),
|
|
124
|
+
}) as never,
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
await expect(method.createCredential({ challenge, context: {} })).rejects.toThrow(
|
|
128
|
+
'keyAuthorization signer does not match the selected account',
|
|
129
|
+
)
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { KeyAuthorization } from 'ox/tempo'
|
|
2
|
+
import { isAddressEqual, type Address } from 'viem'
|
|
3
|
+
import { tempo as tempo_chain } from 'viem/chains'
|
|
4
|
+
|
|
5
|
+
import * as Credential from '../../Credential.js'
|
|
6
|
+
import type { MaybePromise } from '../../internal/types.js'
|
|
7
|
+
import * as Method from '../../Method.js'
|
|
8
|
+
import * as Account from '../../viem/Account.js'
|
|
9
|
+
import * as Client from '../../viem/Client.js'
|
|
10
|
+
import * as z from '../../zod.js'
|
|
11
|
+
import * as defaults from '../internal/defaults.js'
|
|
12
|
+
import * as Methods from '../Methods.js'
|
|
13
|
+
import {
|
|
14
|
+
getSubscriptionRpcAllowedCalls,
|
|
15
|
+
signSubscriptionKeyAuthorization,
|
|
16
|
+
toSubscriptionExpiryDate,
|
|
17
|
+
toSubscriptionExpirySeconds,
|
|
18
|
+
toSubscriptionPeriodSeconds,
|
|
19
|
+
verifySubscriptionKeyAuthorization,
|
|
20
|
+
} from '../subscription/KeyAuthorization.js'
|
|
21
|
+
import type { SubscriptionAccessKey } from '../subscription/Types.js'
|
|
22
|
+
|
|
23
|
+
type SubscriptionRequest = ReturnType<typeof Methods.subscription.schema.request.parse>
|
|
24
|
+
|
|
25
|
+
/** Context accepted by the Tempo subscription client method. */
|
|
26
|
+
export const subscriptionContextSchema = z.object({
|
|
27
|
+
accessKey: z.optional(z.custom<SubscriptionAccessKey>()),
|
|
28
|
+
account: z.optional(z.custom<Account.getResolver.Parameters['account']>()),
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
/** Runtime context for creating a Tempo subscription credential. */
|
|
32
|
+
export type SubscriptionContext = z.infer<typeof subscriptionContextSchema>
|
|
33
|
+
|
|
34
|
+
/** Creates a Tempo subscription client method. */
|
|
35
|
+
export function subscription(parameters: subscription.Parameters = {}) {
|
|
36
|
+
const getClient = Client.getResolver({
|
|
37
|
+
chain: tempo_chain,
|
|
38
|
+
getClient: parameters.getClient,
|
|
39
|
+
rpcUrl: defaults.rpcUrl,
|
|
40
|
+
})
|
|
41
|
+
const getAccount = Account.getResolver({ account: parameters.account })
|
|
42
|
+
|
|
43
|
+
return Method.toClient(Methods.subscription, {
|
|
44
|
+
context: subscriptionContextSchema,
|
|
45
|
+
|
|
46
|
+
async createCredential({ challenge, context }) {
|
|
47
|
+
const chainId = challenge.request.methodDetails?.chainId ?? defaults.chainId.testnet
|
|
48
|
+
const client = await getClient({ chainId })
|
|
49
|
+
const account = getAccount(client, context)
|
|
50
|
+
const accessKey =
|
|
51
|
+
context?.accessKey ?? parameters.accessKey ?? challenge.request.methodDetails?.accessKey
|
|
52
|
+
if (!accessKey) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
'No `accessKey` provided. The subscription challenge must include `accessKey`, or the client must pass one to parameters/context.',
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
assertSubscriptionRequestRepresentable(challenge.request)
|
|
59
|
+
await parameters.validateRequest?.(challenge.request)
|
|
60
|
+
|
|
61
|
+
const keyAuthorization = await authorizeAccessKey(client, {
|
|
62
|
+
accessKey,
|
|
63
|
+
account,
|
|
64
|
+
chainId,
|
|
65
|
+
request: challenge.request,
|
|
66
|
+
} as never)
|
|
67
|
+
|
|
68
|
+
const verified = verifySubscriptionKeyAuthorization({
|
|
69
|
+
accessKey,
|
|
70
|
+
chainId,
|
|
71
|
+
payload: {
|
|
72
|
+
signature: KeyAuthorization.serialize(keyAuthorization as never),
|
|
73
|
+
type: 'keyAuthorization',
|
|
74
|
+
},
|
|
75
|
+
request: challenge.request,
|
|
76
|
+
})
|
|
77
|
+
if (!isAddressEqual(verified.source.address, account.address)) {
|
|
78
|
+
throw new Error('keyAuthorization signer does not match the selected account')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return Credential.serialize({
|
|
82
|
+
challenge,
|
|
83
|
+
payload: {
|
|
84
|
+
signature: KeyAuthorization.serialize(keyAuthorization as never),
|
|
85
|
+
type: 'keyAuthorization',
|
|
86
|
+
},
|
|
87
|
+
source: `did:pkh:eip155:${chainId}:${account.address.toLowerCase()}`,
|
|
88
|
+
})
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function authorizeAccessKey(
|
|
94
|
+
client: Awaited<ReturnType<ReturnType<typeof Client.getResolver>>>,
|
|
95
|
+
parameters: {
|
|
96
|
+
accessKey: SubscriptionAccessKey
|
|
97
|
+
account: Account.Account
|
|
98
|
+
chainId: number
|
|
99
|
+
request: Pick<
|
|
100
|
+
SubscriptionRequest,
|
|
101
|
+
'amount' | 'currency' | 'periodCount' | 'periodUnit' | 'recipient' | 'subscriptionExpires'
|
|
102
|
+
>
|
|
103
|
+
},
|
|
104
|
+
) {
|
|
105
|
+
const { accessKey, account, chainId, request } = parameters
|
|
106
|
+
|
|
107
|
+
const local = await signSubscriptionKeyAuthorization({
|
|
108
|
+
accessKey,
|
|
109
|
+
account,
|
|
110
|
+
chainId,
|
|
111
|
+
request,
|
|
112
|
+
})
|
|
113
|
+
if (local) return local
|
|
114
|
+
|
|
115
|
+
const result = (await client.request({
|
|
116
|
+
method: 'wallet_authorizeAccessKey',
|
|
117
|
+
params: [
|
|
118
|
+
{
|
|
119
|
+
address: accessKey.accessKeyAddress,
|
|
120
|
+
allowedCalls: getSubscriptionRpcAllowedCalls(request),
|
|
121
|
+
expiry: toSubscriptionExpirySeconds(toSubscriptionExpiryDate(request.subscriptionExpires)),
|
|
122
|
+
keyType: accessKey.keyType,
|
|
123
|
+
limits: [
|
|
124
|
+
{
|
|
125
|
+
token: request.currency as Address,
|
|
126
|
+
limit: BigInt(request.amount),
|
|
127
|
+
period: toSubscriptionPeriodSeconds(request),
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
} as never)) as {
|
|
133
|
+
keyAuthorization: Parameters<typeof KeyAuthorization.fromRpc>[0]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return KeyAuthorization.fromRpc(result.keyAuthorization)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function assertSubscriptionRequestRepresentable(request: SubscriptionRequest) {
|
|
140
|
+
toSubscriptionPeriodSeconds(request)
|
|
141
|
+
toSubscriptionExpirySeconds(toSubscriptionExpiryDate(request.subscriptionExpires))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export declare namespace subscription {
|
|
145
|
+
/** Parameters for creating a Tempo subscription credential. */
|
|
146
|
+
type Parameters = Account.getResolver.Parameters &
|
|
147
|
+
Client.getResolver.Parameters & {
|
|
148
|
+
accessKey?: SubscriptionAccessKey | undefined
|
|
149
|
+
validateRequest?:
|
|
150
|
+
| ((
|
|
151
|
+
request: ReturnType<typeof Methods.subscription.schema.request.parse>,
|
|
152
|
+
) => MaybePromise<void>)
|
|
153
|
+
| undefined
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { charge } from './Charge.js'
|
|
2
2
|
export { tempo } from './Methods.js'
|
|
3
3
|
export { session } from './Session.js'
|
|
4
|
+
export { subscription } from './Subscription.js'
|
|
4
5
|
export type { PaymentResponse, SessionManager } from './SessionManager.js'
|
|
5
6
|
export { sessionManager } from './SessionManager.js'
|
package/src/tempo/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as Ws_ from '../session/Ws.js'
|
|
2
2
|
import { charge as charge_ } from './Charge.js'
|
|
3
3
|
import { session as session_, settle as settle_ } from './Session.js'
|
|
4
|
+
import { renew as renewSubscription_, subscription as subscription_ } from './Subscription.js'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Creates both Tempo `charge` and `session` methods from shared parameters.
|
|
@@ -28,6 +29,10 @@ export namespace tempo {
|
|
|
28
29
|
export const charge = charge_
|
|
29
30
|
/** Creates a Tempo `session` method for session-based TIP-20 token payments. */
|
|
30
31
|
export const session = session_
|
|
32
|
+
/** Creates a Tempo `subscription` method for recurring TIP-20 token payments. */
|
|
33
|
+
export const subscription = subscription_
|
|
34
|
+
/** Renews an overdue Tempo subscription outside of the HTTP request path. */
|
|
35
|
+
export const renewSubscription = renewSubscription_
|
|
31
36
|
/** One-shot settle: reads highest voucher from storage and submits on-chain. */
|
|
32
37
|
export const settle = settle_
|
|
33
38
|
/** Experimental websocket helpers for Tempo sessions. */
|