mppx 0.8.12 → 0.8.14
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 +34 -0
- package/README.md +16 -1
- package/dist/Errors.d.ts +10 -0
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js +11 -2
- package/dist/Errors.js.map +1 -1
- package/dist/Method.d.ts +105 -3
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +102 -2
- package/dist/Method.js.map +1 -1
- package/dist/cli/account.d.ts +88 -0
- package/dist/cli/account.d.ts.map +1 -1
- package/dist/cli/account.js +39 -9
- package/dist/cli/account.js.map +1 -1
- package/dist/cli/cli.d.ts +2 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +59 -2
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/sessions/Manager.d.ts +31 -0
- package/dist/cli/sessions/Manager.d.ts.map +1 -0
- package/dist/cli/sessions/Manager.js +56 -0
- package/dist/cli/sessions/Manager.js.map +1 -0
- package/dist/cli/sessions/commands.d.ts +36 -0
- package/dist/cli/sessions/commands.d.ts.map +1 -0
- package/dist/cli/sessions/commands.js +407 -0
- package/dist/cli/sessions/commands.js.map +1 -0
- package/dist/cli/sessions/request.d.ts +35 -0
- package/dist/cli/sessions/request.d.ts.map +1 -0
- package/dist/cli/sessions/request.js +271 -0
- package/dist/cli/sessions/request.js.map +1 -0
- package/dist/cli/sessions/store.d.ts +134 -0
- package/dist/cli/sessions/store.d.ts.map +1 -0
- package/dist/cli/sessions/store.js +723 -0
- package/dist/cli/sessions/store.js.map +1 -0
- package/dist/cli/utils.d.ts +2 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +12 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/validate/index.d.ts.map +1 -1
- package/dist/cli/validate/index.js +12 -6
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/cli/validate/messages.d.ts +2 -0
- package/dist/cli/validate/messages.d.ts.map +1 -0
- package/dist/cli/validate/messages.js +8 -0
- package/dist/cli/validate/messages.js.map +1 -0
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +12 -2
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/client/internal/MethodChallenge.d.ts +17 -0
- package/dist/client/internal/MethodChallenge.d.ts.map +1 -0
- package/dist/client/internal/MethodChallenge.js +11 -0
- package/dist/client/internal/MethodChallenge.js.map +1 -0
- package/dist/client/node.d.ts +29 -0
- package/dist/client/node.d.ts.map +1 -0
- package/dist/client/node.js +177 -0
- package/dist/client/node.js.map +1 -0
- package/dist/internal/types.d.ts +24 -0
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/server/Mppx.d.ts +23 -4
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +91 -82
- package/dist/server/Mppx.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +8 -4
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.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/client/Methods.d.ts +2 -1
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +1 -0
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +7 -2
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/internal/types.d.ts +10 -1
- package/dist/tempo/internal/types.d.ts.map +1 -1
- package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/legacy/client/ChannelOps.js +2 -1
- package/dist/tempo/legacy/client/ChannelOps.js.map +1 -1
- package/dist/tempo/legacy/client/Session.d.ts +2 -2
- package/dist/tempo/legacy/server/Session.d.ts +3 -3
- package/dist/tempo/legacy/server/Session.d.ts.map +1 -1
- package/dist/tempo/legacy/server/Session.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +40 -78
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +289 -209
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +13 -23
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +6 -2
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Relay.d.ts +48 -0
- package/dist/tempo/server/Relay.d.ts.map +1 -0
- package/dist/tempo/server/Relay.js +177 -0
- package/dist/tempo/server/Relay.js.map +1 -0
- package/dist/tempo/server/SponsorBudget.d.ts +59 -0
- package/dist/tempo/server/SponsorBudget.d.ts.map +1 -0
- package/dist/tempo/server/SponsorBudget.js +144 -0
- package/dist/tempo/server/SponsorBudget.js.map +1 -0
- package/dist/tempo/server/Subscription.d.ts +3 -2
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/Subscription.js.map +1 -1
- package/dist/tempo/server/index.d.ts +1 -1
- package/dist/tempo/server/index.d.ts.map +1 -1
- 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/session/Snapshot.d.ts +9 -0
- package/dist/tempo/session/Snapshot.d.ts.map +1 -1
- package/dist/tempo/session/Snapshot.js +6 -0
- package/dist/tempo/session/Snapshot.js.map +1 -1
- package/dist/tempo/session/client/ChannelOps.d.ts +7 -1
- package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/session/client/ChannelOps.js +17 -3
- package/dist/tempo/session/client/ChannelOps.js.map +1 -1
- package/dist/tempo/session/client/CredentialState.d.ts +26 -2
- package/dist/tempo/session/client/CredentialState.d.ts.map +1 -1
- package/dist/tempo/session/client/CredentialState.js +99 -16
- package/dist/tempo/session/client/CredentialState.js.map +1 -1
- package/dist/tempo/session/client/Runtime.d.ts +8 -0
- package/dist/tempo/session/client/Runtime.d.ts.map +1 -1
- package/dist/tempo/session/client/Runtime.js +17 -0
- package/dist/tempo/session/client/Runtime.js.map +1 -1
- package/dist/tempo/session/client/Session.d.ts +16 -6
- package/dist/tempo/session/client/Session.d.ts.map +1 -1
- package/dist/tempo/session/client/Session.js +93 -36
- package/dist/tempo/session/client/Session.js.map +1 -1
- package/dist/tempo/session/client/SessionManager.d.ts +10 -3
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/session/client/SessionManager.js +176 -50
- package/dist/tempo/session/client/SessionManager.js.map +1 -1
- package/dist/tempo/session/client/Transports.d.ts +18 -7
- package/dist/tempo/session/client/Transports.d.ts.map +1 -1
- package/dist/tempo/session/client/Transports.js +81 -33
- package/dist/tempo/session/client/Transports.js.map +1 -1
- package/dist/tempo/session/client/internal/SessionManager.d.ts +19 -0
- package/dist/tempo/session/client/internal/SessionManager.d.ts.map +1 -0
- package/dist/tempo/session/client/internal/SessionManager.js +13 -0
- package/dist/tempo/session/client/internal/SessionManager.js.map +1 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Chain.js +109 -12
- package/dist/tempo/session/precompile/Chain.js.map +1 -1
- package/dist/tempo/session/precompile/Channel.d.ts +2 -0
- package/dist/tempo/session/precompile/Channel.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Channel.js +4 -0
- package/dist/tempo/session/precompile/Channel.js.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.d.ts +3 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.js +14 -0
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
- package/dist/tempo/session/server/MeteredStream.d.ts +7 -1
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
- package/dist/tempo/session/server/MeteredStream.js +5 -4
- package/dist/tempo/session/server/MeteredStream.js.map +1 -1
- package/dist/tempo/session/server/RequestState.d.ts +5 -1
- package/dist/tempo/session/server/RequestState.d.ts.map +1 -1
- package/dist/tempo/session/server/RequestState.js +13 -5
- package/dist/tempo/session/server/RequestState.js.map +1 -1
- package/dist/tempo/session/server/Session.d.ts +21 -6
- package/dist/tempo/session/server/Session.d.ts.map +1 -1
- package/dist/tempo/session/server/Session.js +4 -1
- package/dist/tempo/session/server/Session.js.map +1 -1
- package/dist/tempo/session/server/Settlement.d.ts +20 -0
- package/dist/tempo/session/server/Settlement.d.ts.map +1 -1
- package/dist/tempo/session/server/Settlement.js +20 -0
- package/dist/tempo/session/server/Settlement.js.map +1 -1
- package/dist/tempo/session/server/Ws.d.ts +2 -0
- package/dist/tempo/session/server/Ws.d.ts.map +1 -1
- package/dist/tempo/session/server/Ws.js.map +1 -1
- package/dist/tempo/session/server/index.d.ts +1 -1
- package/dist/tempo/session/server/index.d.ts.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +21 -21
- package/dist/validation/core.d.ts.map +1 -1
- package/dist/validation/core.js +6 -2
- package/dist/validation/core.js.map +1 -1
- package/dist/viem/Client.d.ts.map +1 -1
- package/dist/viem/Client.js +24 -17
- package/dist/viem/Client.js.map +1 -1
- package/package.json +6 -1
- package/src/Errors.test.ts +23 -0
- package/src/Errors.ts +21 -2
- package/src/Method.test.ts +102 -1
- package/src/Method.ts +241 -5
- package/src/cli/account.ts +45 -10
- package/src/cli/cli.test.ts +165 -70
- package/src/cli/cli.ts +67 -2
- package/src/cli/mcp.test.ts +11 -0
- package/src/cli/sessions/Manager.test.ts +249 -0
- package/src/cli/sessions/Manager.ts +93 -0
- package/src/cli/sessions/commands.ts +444 -0
- package/src/cli/sessions/request.test.ts +51 -0
- package/src/cli/sessions/request.ts +353 -0
- package/src/cli/sessions/store.test.ts +581 -0
- package/src/cli/sessions/store.ts +940 -0
- package/src/cli/utils.test.ts +23 -0
- package/src/cli/utils.ts +10 -0
- package/src/cli/validate/index.ts +12 -14
- package/src/cli/validate/messages.ts +7 -0
- package/src/cli/validate.test.ts +38 -5
- package/src/client/Mppx.test-d.ts +3 -3
- package/src/client/internal/Fetch.ts +16 -7
- package/src/client/internal/MethodChallenge.ts +30 -0
- package/src/client/node.test.ts +115 -0
- package/src/client/node.ts +247 -0
- package/src/internal/types.test-d.ts +21 -0
- package/src/internal/types.ts +33 -0
- package/src/server/Mppx.test-d.ts +44 -0
- package/src/server/Mppx.test.ts +205 -0
- package/src/server/Mppx.ts +167 -103
- package/src/stripe/Methods.test.ts +10 -0
- package/src/stripe/server/Charge.test-d.ts +66 -0
- package/src/stripe/server/Charge.ts +8 -5
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/PublicExports.test-d.ts +20 -0
- package/src/tempo/internal/fee-payer.ts +7 -3
- package/src/tempo/internal/types.ts +13 -2
- package/src/tempo/legacy/client/ChannelOps.test.ts +7 -0
- package/src/tempo/legacy/client/ChannelOps.ts +2 -1
- package/src/tempo/legacy/server/Defaults.test-d.ts +9 -0
- package/src/tempo/legacy/server/Session.ts +6 -5
- package/src/tempo/server/Charge.test.ts +337 -63
- package/src/tempo/server/Charge.ts +440 -270
- package/src/tempo/server/Methods.ts +16 -4
- package/src/tempo/server/Relay.test.ts +523 -0
- package/src/tempo/server/Relay.ts +288 -0
- package/src/tempo/server/SponsorBudget.test.ts +125 -0
- package/src/tempo/server/SponsorBudget.ts +213 -0
- package/src/tempo/server/Subscription.ts +6 -4
- package/src/tempo/server/index.ts +5 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/session/README.md +201 -0
- package/src/tempo/session/Snapshot.ts +21 -0
- package/src/tempo/session/client/ChannelOps.test.ts +55 -0
- package/src/tempo/session/client/ChannelOps.ts +21 -3
- package/src/tempo/session/client/CredentialState.test.ts +2 -2
- package/src/tempo/session/client/CredentialState.ts +159 -16
- package/src/tempo/session/client/Runtime.test.ts +12 -0
- package/src/tempo/session/client/Runtime.ts +22 -0
- package/src/tempo/session/client/Session.test.ts +238 -5
- package/src/tempo/session/client/Session.ts +130 -41
- package/src/tempo/session/client/SessionManager.test.ts +239 -8
- package/src/tempo/session/client/SessionManager.ts +204 -54
- package/src/tempo/session/client/Transports.test.ts +181 -8
- package/src/tempo/session/client/Transports.ts +127 -45
- package/src/tempo/session/client/internal/SessionManager.ts +36 -0
- package/src/tempo/session/precompile/Chain.integration.test.ts +19 -1
- package/src/tempo/session/precompile/Chain.test.ts +223 -10
- package/src/tempo/session/precompile/Chain.ts +119 -12
- package/src/tempo/session/precompile/Channel.test.ts +9 -0
- package/src/tempo/session/precompile/Channel.ts +5 -0
- package/src/tempo/session/server/CredentialVerification.ts +18 -1
- package/src/tempo/session/server/MeteredStream.ts +12 -5
- package/src/tempo/session/server/RequestState.test.ts +47 -4
- package/src/tempo/session/server/RequestState.ts +15 -8
- package/src/tempo/session/server/Session.test.ts +461 -0
- package/src/tempo/session/server/Session.ts +31 -8
- package/src/tempo/session/server/Settlement.ts +45 -0
- package/src/tempo/session/server/Ws.test.ts +113 -0
- package/src/tempo/session/server/Ws.ts +2 -0
- package/src/tempo/session/server/index.ts +2 -0
- package/src/validation/core.ts +7 -1
- package/src/viem/Client.test.ts +44 -1
- package/src/viem/Client.ts +31 -17
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import type { Hex } from 'ox'
|
|
2
2
|
import { parseUnits, type Address } from 'viem'
|
|
3
|
+
import { tempo as tempo_chain } from 'viem/chains'
|
|
3
4
|
|
|
4
5
|
import * as Challenge from '../../../Challenge.js'
|
|
5
6
|
import * as Fetch from '../../../client/internal/Fetch.js'
|
|
7
|
+
import * as MethodChallenge from '../../../client/internal/MethodChallenge.js'
|
|
6
8
|
import * as MethodResponse from '../../../client/internal/MethodResponse.js'
|
|
7
9
|
import * as Constants from '../../../Constants.js'
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
+
import * as Account from '../../../viem/Account.js'
|
|
11
|
+
import * as Client from '../../../viem/Client.js'
|
|
10
12
|
import { charge as chargePlugin } from '../../client/Charge.js'
|
|
13
|
+
import * as defaults from '../../internal/defaults.js'
|
|
11
14
|
import type { ChannelEntry } from '../client/ChannelOps.js'
|
|
12
15
|
import { createChannelStore, entryKey, type ChannelStore } from '../client/ChannelStore.js'
|
|
13
|
-
import type
|
|
16
|
+
import { hydrateSessionSnapshot, type SessionContext } from '../client/CredentialState.js'
|
|
14
17
|
import { session as sessionPlugin } from '../client/Session.js'
|
|
18
|
+
import * as Channel from '../precompile/Channel.js'
|
|
15
19
|
import { deserializeSessionReceipt } from '../precompile/Protocol.js'
|
|
16
|
-
import {
|
|
20
|
+
import type { SessionReceipt } from '../precompile/Protocol.js'
|
|
17
21
|
import {
|
|
18
22
|
deserializeSnapshot as deserializeSessionSnapshot,
|
|
19
23
|
serializeSnapshot as serializeSessionSnapshot,
|
|
20
24
|
} from '../Snapshot.js'
|
|
25
|
+
import { registerSessionManagerInternals } from './internal/SessionManager.js'
|
|
21
26
|
import { createSessionReceiptCoordinator } from './ReceiptCoordinator.js'
|
|
22
27
|
import { resolveCloseTarget, type CloseTarget } from './Runtime.js'
|
|
23
28
|
import { assertVoucherWithinLocalLimit as assertVoucherWithinLocalAuthorization } from './Runtime.js'
|
|
@@ -30,13 +35,14 @@ import {
|
|
|
30
35
|
dispatchSessionEvent,
|
|
31
36
|
restoreCumulativeAuthorization,
|
|
32
37
|
restoreRuntimeSnapshot as restoreRuntimeStateSnapshot,
|
|
38
|
+
resolveAutomaticTopUp,
|
|
33
39
|
type RuntimeSnapshot,
|
|
34
40
|
} from './Runtime.js'
|
|
35
41
|
import { closeSocketSession } from './Runtime.js'
|
|
36
42
|
import {
|
|
37
43
|
closeHttpSession,
|
|
44
|
+
getSessionSnapshot,
|
|
38
45
|
isTempoSessionChallenge,
|
|
39
|
-
managementInput,
|
|
40
46
|
postTopUp,
|
|
41
47
|
retryHttpPaymentRequired,
|
|
42
48
|
type TempoSessionChallenge,
|
|
@@ -47,7 +53,7 @@ import {
|
|
|
47
53
|
type WebSocketConstructor,
|
|
48
54
|
WebSocketReadyState,
|
|
49
55
|
} from './Transports.js'
|
|
50
|
-
import { openSseSession, type SseDriverOptions } from './Transports.js'
|
|
56
|
+
import { consumeSseSessionResponse, openSseSession, type SseDriverOptions } from './Transports.js'
|
|
51
57
|
import { applyTopUpResult, resolveManualTopUp, type TopUpRequirement } from './Transports.js'
|
|
52
58
|
import {
|
|
53
59
|
openWebSocketSession,
|
|
@@ -106,6 +112,8 @@ type SessionManagerConfig = {
|
|
|
106
112
|
fetch: typeof globalThis.fetch
|
|
107
113
|
/** Local maximum cumulative voucher authorization, or null when uncapped. */
|
|
108
114
|
maxVoucherCumulative: bigint | null
|
|
115
|
+
/** Preferred top-up, or null to use a bounded server suggestion and then the exact shortfall. */
|
|
116
|
+
topUpAmount: bigint | null
|
|
109
117
|
/** WebSocket constructor available in the current runtime, when configured. */
|
|
110
118
|
WebSocket: WebSocketConstructor | undefined
|
|
111
119
|
}
|
|
@@ -126,19 +134,6 @@ function isZeroAmountChargeChallenge(challenge: Challenge.Challenge) {
|
|
|
126
134
|
}
|
|
127
135
|
}
|
|
128
136
|
|
|
129
|
-
/** Builds a reusable channel entry from a server session snapshot header. */
|
|
130
|
-
function entryFromSnapshot(snapshot: ReturnType<typeof deserializeSessionSnapshot>): ChannelEntry {
|
|
131
|
-
return {
|
|
132
|
-
channelId: snapshot.channelId,
|
|
133
|
-
cumulativeAmount: BigInt(snapshot.acceptedCumulative),
|
|
134
|
-
deposit: BigInt(snapshot.deposit),
|
|
135
|
-
descriptor: snapshot.descriptor,
|
|
136
|
-
escrow: snapshot.escrow,
|
|
137
|
-
chainId: snapshot.chainId,
|
|
138
|
-
opened: true,
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
137
|
function requestInitWithSessionHint(
|
|
143
138
|
input: RequestInfo | URL,
|
|
144
139
|
init: RequestInit | undefined,
|
|
@@ -176,6 +171,8 @@ function resolveSessionManagerConfig(parameters: sessionManager.Parameters): Ses
|
|
|
176
171
|
fetch: parameters.fetch ?? globalThis.fetch.bind(globalThis),
|
|
177
172
|
maxVoucherCumulative:
|
|
178
173
|
parameters.maxDeposit !== undefined ? parseUnits(parameters.maxDeposit, decimals) : null,
|
|
174
|
+
topUpAmount:
|
|
175
|
+
parameters.topUpAmount !== undefined ? parseUnits(parameters.topUpAmount, decimals) : null,
|
|
179
176
|
WebSocket,
|
|
180
177
|
}
|
|
181
178
|
}
|
|
@@ -192,6 +189,12 @@ function resolveSessionManagerConfig(parameters: sessionManager.Parameters): Ses
|
|
|
192
189
|
*/
|
|
193
190
|
export function sessionManager(parameters: sessionManager.Parameters): SessionManager {
|
|
194
191
|
const config = resolveSessionManagerConfig(parameters)
|
|
192
|
+
const getClient = Client.getResolver({
|
|
193
|
+
chain: tempo_chain,
|
|
194
|
+
getClient: parameters.client ? () => parameters.client! : parameters.getClient,
|
|
195
|
+
rpcUrl: defaults.rpcUrl,
|
|
196
|
+
})
|
|
197
|
+
const getAccount = Account.getResolver({ account: parameters.account })
|
|
195
198
|
const runtime = createSessionManagerRuntime()
|
|
196
199
|
const receipts = createSessionReceiptCoordinator({
|
|
197
200
|
getSocketSession: () => runtime.socketSession,
|
|
@@ -203,6 +206,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
203
206
|
// Tracks one fetch's channel reuse so stale stored entries can be evicted once.
|
|
204
207
|
type ChannelUse = {
|
|
205
208
|
challengesReceived: number
|
|
209
|
+
committed: RuntimeSnapshot | undefined
|
|
206
210
|
created: Map<string, ChannelEntry>
|
|
207
211
|
seenExisting: Set<string>
|
|
208
212
|
previous: RuntimeSnapshot
|
|
@@ -223,7 +227,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
223
227
|
const entry = await getReusable(key)
|
|
224
228
|
if (entry && channelUse) {
|
|
225
229
|
channelUse.seenExisting.add(key)
|
|
226
|
-
if (!channelUse.created.has(key)) channelUse.resumed ??= entry
|
|
230
|
+
if (!channelUse.committed && !channelUse.created.has(key)) channelUse.resumed ??= entry
|
|
227
231
|
}
|
|
228
232
|
return entry
|
|
229
233
|
},
|
|
@@ -272,13 +276,32 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
272
276
|
return dispatchSessionEvent(runtime, event)
|
|
273
277
|
}
|
|
274
278
|
|
|
279
|
+
function commitDurableTopUp(entry: ChannelEntry) {
|
|
280
|
+
const use = channelUse
|
|
281
|
+
const baseline = use?.committed?.channel?.entry ?? use?.resumed
|
|
282
|
+
if (
|
|
283
|
+
!use ||
|
|
284
|
+
baseline?.channelId.toLowerCase() !== entry.channelId.toLowerCase() ||
|
|
285
|
+
entry.deposit <= baseline.deposit
|
|
286
|
+
)
|
|
287
|
+
return
|
|
288
|
+
use.resumed = undefined
|
|
289
|
+
use.committed = captureRuntimeStateSnapshot({
|
|
290
|
+
channel: runtime.channel,
|
|
291
|
+
spent: runtime.spent,
|
|
292
|
+
state: runtime.state,
|
|
293
|
+
})
|
|
294
|
+
}
|
|
295
|
+
|
|
275
296
|
const method = sessionPlugin({
|
|
276
297
|
account: parameters.account,
|
|
298
|
+
autoSwap: parameters.autoSwap,
|
|
277
299
|
getClient: parameters.client ? () => parameters.client! : parameters.getClient,
|
|
278
300
|
resolveAccount: parameters.resolveAccount,
|
|
279
301
|
escrow: parameters.escrow,
|
|
280
302
|
decimals: config.decimals,
|
|
281
303
|
maxDeposit: parameters.maxDeposit,
|
|
304
|
+
topUpAmount: parameters.topUpAmount,
|
|
282
305
|
channelStore: store,
|
|
283
306
|
onChannelUpdate(entry) {
|
|
284
307
|
if (entry.channelId !== runtime.channel?.channelId) runtime.spent = 0n
|
|
@@ -292,6 +315,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
292
315
|
units: 0,
|
|
293
316
|
})
|
|
294
317
|
}
|
|
318
|
+
commitDurableTopUp(entry)
|
|
295
319
|
},
|
|
296
320
|
})
|
|
297
321
|
MethodResponse.unregister(method)
|
|
@@ -315,17 +339,6 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
315
339
|
if (use) use.challengesReceived++
|
|
316
340
|
runtime.lastChallenge = challenge
|
|
317
341
|
dispatch({ type: 'challengeReceived', challengeId: challenge.id })
|
|
318
|
-
if (runtime.channel?.opened && runtime.lastUrl) {
|
|
319
|
-
const requiredCumulative =
|
|
320
|
-
runtime.channel.cumulativeAmount + readSessionChallengeAmount(challenge)
|
|
321
|
-
await topUpIfNeeded({
|
|
322
|
-
challenge,
|
|
323
|
-
input: runtime.lastUrl,
|
|
324
|
-
channelId: runtime.channel.channelId,
|
|
325
|
-
deposit: runtime.channel.deposit,
|
|
326
|
-
requiredCumulative,
|
|
327
|
-
})
|
|
328
|
-
}
|
|
329
342
|
return undefined
|
|
330
343
|
},
|
|
331
344
|
})
|
|
@@ -365,8 +378,23 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
365
378
|
async function storeSnapshotHeader(response: Response): Promise<ChannelEntry | undefined> {
|
|
366
379
|
const header = response.headers.get(Constants.Headers.paymentSessionSnapshot)
|
|
367
380
|
if (!header) return undefined
|
|
368
|
-
const
|
|
381
|
+
const snapshot = deserializeSessionSnapshot(header)
|
|
382
|
+
const client = await getClient({ chainId: snapshot.chainId })
|
|
383
|
+
const defaultAccount = getAccount(client)
|
|
384
|
+
const account =
|
|
385
|
+
(await parameters.resolveAccount?.({
|
|
386
|
+
account: defaultAccount,
|
|
387
|
+
chainId: snapshot.chainId,
|
|
388
|
+
operation: {
|
|
389
|
+
authority: Channel.resolveAuthorizedSigner(snapshot.descriptor),
|
|
390
|
+
kind: 'authorizePaymentChannel',
|
|
391
|
+
},
|
|
392
|
+
})) ?? defaultAccount
|
|
393
|
+
const { entry, spent } = await hydrateSessionSnapshot({ account, client, snapshot })
|
|
394
|
+
assertVoucherWithinLocalLimit(entry.cumulativeAmount)
|
|
369
395
|
await Promise.resolve(store.set(entry)).catch(() => undefined)
|
|
396
|
+
runtime.channel = entry
|
|
397
|
+
runtime.spent = spent
|
|
370
398
|
return entry
|
|
371
399
|
}
|
|
372
400
|
|
|
@@ -430,8 +458,60 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
430
458
|
})
|
|
431
459
|
}
|
|
432
460
|
|
|
433
|
-
function
|
|
434
|
-
const
|
|
461
|
+
function validateCloseSnapshot(channel: ChannelEntry, challenge: TempoSessionChallenge) {
|
|
462
|
+
const snapshot = getSessionSnapshot(challenge)
|
|
463
|
+
if (!snapshot) return undefined
|
|
464
|
+
|
|
465
|
+
const computedSnapshotId = Channel.computeId({
|
|
466
|
+
...snapshot.descriptor,
|
|
467
|
+
chainId: snapshot.chainId,
|
|
468
|
+
escrow: snapshot.escrow,
|
|
469
|
+
})
|
|
470
|
+
if (computedSnapshotId.toLowerCase() !== snapshot.channelId.toLowerCase()) {
|
|
471
|
+
throw new Error('close snapshot descriptor does not match its channel ID')
|
|
472
|
+
}
|
|
473
|
+
if (snapshot.channelId.toLowerCase() !== channel.channelId.toLowerCase()) {
|
|
474
|
+
throw new Error('close snapshot channel ID does not match local session')
|
|
475
|
+
}
|
|
476
|
+
if (
|
|
477
|
+
snapshot.chainId !== channel.chainId ||
|
|
478
|
+
snapshot.escrow.toLowerCase() !== channel.escrow.toLowerCase()
|
|
479
|
+
) {
|
|
480
|
+
throw new Error('close snapshot payment scope does not match local session')
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const acceptedCumulative = BigInt(snapshot.acceptedCumulative)
|
|
484
|
+
const snapshotSpent = BigInt(snapshot.spent)
|
|
485
|
+
if (acceptedCumulative < 0n || snapshotSpent < 0n) {
|
|
486
|
+
throw new Error('close snapshot amounts must not be negative')
|
|
487
|
+
}
|
|
488
|
+
if (snapshotSpent > acceptedCumulative) {
|
|
489
|
+
throw new Error('close snapshot spent exceeds accepted cumulative amount')
|
|
490
|
+
}
|
|
491
|
+
if (acceptedCumulative > channel.cumulativeAmount) {
|
|
492
|
+
throw new Error('close snapshot accepted cumulative exceeds local voucher state')
|
|
493
|
+
}
|
|
494
|
+
return { acceptedCumulative, spent: snapshotSpent }
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function applyCloseSnapshot(target: CloseTarget, challenge: TempoSessionChallenge) {
|
|
498
|
+
const snapshot = validateCloseSnapshot(target.channel, challenge)
|
|
499
|
+
if (!snapshot) return
|
|
500
|
+
|
|
501
|
+
const { acceptedCumulative, spent } = snapshot
|
|
502
|
+
if (runtime.spent > acceptedCumulative) {
|
|
503
|
+
throw new Error('close snapshot accepted cumulative is below locally confirmed spend')
|
|
504
|
+
}
|
|
505
|
+
if (spent > runtime.spent) runtime.spent = spent
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function getValidatedFallbackCloseAmount(
|
|
509
|
+
target: CloseTarget,
|
|
510
|
+
challenge: TempoSessionChallenge = target.challenge,
|
|
511
|
+
applySnapshot = false,
|
|
512
|
+
) {
|
|
513
|
+
if (applySnapshot) applyCloseSnapshot(target, challenge)
|
|
514
|
+
const closeAmount = getFallbackCloseAmount(challenge, target.channelId)
|
|
435
515
|
if (closeAmount > target.channel.cumulativeAmount) {
|
|
436
516
|
throw new Error('fallback close amount exceeds local voucher state')
|
|
437
517
|
}
|
|
@@ -451,9 +531,11 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
451
531
|
challenge: TempoSessionChallenge
|
|
452
532
|
channelId: Hex.Hex
|
|
453
533
|
input: RequestInfo | URL
|
|
534
|
+
knownDeposit?: bigint | undefined
|
|
454
535
|
}) {
|
|
536
|
+
const { knownDeposit, ...topUp } = parameters
|
|
455
537
|
const receipt = await postTopUp({
|
|
456
|
-
...
|
|
538
|
+
...topUp,
|
|
457
539
|
channel: runtime.channel,
|
|
458
540
|
createSessionCredential,
|
|
459
541
|
fetch: config.fetch,
|
|
@@ -465,10 +547,12 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
465
547
|
channelId: parameters.channelId,
|
|
466
548
|
challengeId: runtime.lastChallenge?.id,
|
|
467
549
|
currentState: runtime.state,
|
|
550
|
+
knownDeposit,
|
|
468
551
|
receipt,
|
|
469
552
|
spent: runtime.spent,
|
|
470
553
|
})
|
|
471
554
|
if (applied?.channel && runtime.lastChallenge) {
|
|
555
|
+
await store.set(applied.channel)
|
|
472
556
|
dispatch({
|
|
473
557
|
type: 'activated',
|
|
474
558
|
challengeId: runtime.lastChallenge.id,
|
|
@@ -476,18 +560,32 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
476
560
|
spent: runtime.spent.toString(),
|
|
477
561
|
units: runtime.state.status === 'active' ? runtime.state.units : 0,
|
|
478
562
|
})
|
|
563
|
+
commitDurableTopUp(applied.channel)
|
|
479
564
|
}
|
|
480
565
|
return receipt
|
|
481
566
|
}
|
|
482
567
|
|
|
483
568
|
async function topUpIfNeeded(parameters: TopUpRequirement) {
|
|
484
|
-
|
|
485
|
-
|
|
569
|
+
const channelDeposit =
|
|
570
|
+
runtime.channel?.channelId === parameters.channelId ? runtime.channel.deposit : 0n
|
|
571
|
+
const deposit = channelDeposit > parameters.deposit ? channelDeposit : parameters.deposit
|
|
572
|
+
const additionalDeposit = resolveAutomaticTopUp({
|
|
573
|
+
deposit,
|
|
574
|
+
maxDeposit: config.maxVoucherCumulative,
|
|
575
|
+
requiredCumulative: parameters.requiredCumulative,
|
|
576
|
+
suggestedDeposit:
|
|
577
|
+
parameters.challenge.request.suggestedDeposit === undefined
|
|
578
|
+
? undefined
|
|
579
|
+
: BigInt(parameters.challenge.request.suggestedDeposit),
|
|
580
|
+
topUpAmount: config.topUpAmount,
|
|
581
|
+
})
|
|
582
|
+
if (additionalDeposit === 0n) return
|
|
486
583
|
await postTopUpAndApply({
|
|
487
584
|
challenge: parameters.challenge,
|
|
488
585
|
input: parameters.input,
|
|
489
586
|
channelId: parameters.channelId,
|
|
490
|
-
additionalDeposit
|
|
587
|
+
additionalDeposit,
|
|
588
|
+
knownDeposit: deposit,
|
|
491
589
|
})
|
|
492
590
|
}
|
|
493
591
|
|
|
@@ -547,6 +645,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
547
645
|
})
|
|
548
646
|
const use: ChannelUse = {
|
|
549
647
|
challengesReceived: 0,
|
|
648
|
+
committed: undefined,
|
|
550
649
|
created: new Map(),
|
|
551
650
|
previous,
|
|
552
651
|
seenExisting: new Set(),
|
|
@@ -580,7 +679,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
580
679
|
try {
|
|
581
680
|
response = await wrappedFetch(input, effectiveInit)
|
|
582
681
|
} catch (error) {
|
|
583
|
-
restoreRuntime(previous)
|
|
682
|
+
restoreRuntime(use.committed ?? previous)
|
|
584
683
|
if (await retryWithoutResumed()) continue
|
|
585
684
|
throw error
|
|
586
685
|
}
|
|
@@ -607,7 +706,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
607
706
|
}
|
|
608
707
|
}
|
|
609
708
|
if (!attemptedHttpManagement && !paymentResponse.ok && !paymentResponse.receipt) {
|
|
610
|
-
restoreRuntime(previous)
|
|
709
|
+
restoreRuntime(use.committed ?? previous)
|
|
611
710
|
if (await retryWithoutResumed()) continue
|
|
612
711
|
return paymentResponse
|
|
613
712
|
}
|
|
@@ -625,6 +724,8 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
625
724
|
createSessionCredential,
|
|
626
725
|
fetch: config.fetch,
|
|
627
726
|
lastUrl: runtime.lastUrl,
|
|
727
|
+
resolveSignedCloseAmount: (challenge) =>
|
|
728
|
+
getValidatedFallbackCloseAmount(target, challenge, true),
|
|
628
729
|
signedCloseAmount: getValidatedFallbackCloseAmount(target),
|
|
629
730
|
setChallenge(challenge) {
|
|
630
731
|
runtime.lastChallenge = challenge
|
|
@@ -640,6 +741,19 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
640
741
|
return receipt
|
|
641
742
|
}
|
|
642
743
|
|
|
744
|
+
const sseDriver = {
|
|
745
|
+
createSessionCredential,
|
|
746
|
+
doFetch,
|
|
747
|
+
fetch: config.fetch,
|
|
748
|
+
getChannel: () => runtime.channel,
|
|
749
|
+
getChallenge: () => runtime.lastChallenge,
|
|
750
|
+
assertVoucherWithinLocalLimit,
|
|
751
|
+
acceptReceipt(receipt: SessionReceipt) {
|
|
752
|
+
updateSpentFromReceipt(receipt)
|
|
753
|
+
},
|
|
754
|
+
topUpIfNeeded,
|
|
755
|
+
}
|
|
756
|
+
|
|
643
757
|
const self: SessionManager = {
|
|
644
758
|
get channelId() {
|
|
645
759
|
return runtime.channel?.channelId
|
|
@@ -675,19 +789,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
675
789
|
},
|
|
676
790
|
|
|
677
791
|
async sse(input, init) {
|
|
678
|
-
return openSseSession(input, init,
|
|
679
|
-
createSessionCredential,
|
|
680
|
-
doFetch,
|
|
681
|
-
fetch: config.fetch,
|
|
682
|
-
getChannel: () => runtime.channel,
|
|
683
|
-
getChallenge: () => runtime.lastChallenge,
|
|
684
|
-
assertVoucherWithinLocalLimit,
|
|
685
|
-
managementInput,
|
|
686
|
-
acceptReceipt(receipt) {
|
|
687
|
-
updateSpentFromReceipt(receipt)
|
|
688
|
-
},
|
|
689
|
-
topUpIfNeeded,
|
|
690
|
-
})
|
|
792
|
+
return openSseSession(input, init, sseDriver)
|
|
691
793
|
},
|
|
692
794
|
|
|
693
795
|
async ws(input, init) {
|
|
@@ -703,7 +805,16 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
703
805
|
const liveHint = runtime.channel?.opened ? runtime.channel.channelId : undefined
|
|
704
806
|
|
|
705
807
|
const prepared = await prepareWebSocketSession({
|
|
706
|
-
createSessionCredential,
|
|
808
|
+
async createSessionCredential(challenge, context) {
|
|
809
|
+
runtime.lastChallenge = challenge
|
|
810
|
+
await MethodChallenge.handle(method, {
|
|
811
|
+
challenge,
|
|
812
|
+
context,
|
|
813
|
+
fetch: config.fetch,
|
|
814
|
+
input: probeUrl,
|
|
815
|
+
})
|
|
816
|
+
return createSessionCredential(challenge, context)
|
|
817
|
+
},
|
|
707
818
|
fetch: config.fetch,
|
|
708
819
|
input,
|
|
709
820
|
onProbeUrl(httpUrl) {
|
|
@@ -768,6 +879,38 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
768
879
|
},
|
|
769
880
|
}
|
|
770
881
|
|
|
882
|
+
registerSessionManagerInternals(self, {
|
|
883
|
+
consumeSseResponse(input, response, options) {
|
|
884
|
+
return consumeSseSessionResponse(input, response, options, sseDriver)
|
|
885
|
+
},
|
|
886
|
+
rehydrate({ channel, challenge, input, spent }) {
|
|
887
|
+
if (!channel.opened) throw new Error('Cannot restore a closed session channel.')
|
|
888
|
+
if (!isTempoSessionChallenge(challenge)) {
|
|
889
|
+
throw new Error('Cannot restore session: challenge is not tempo/session.')
|
|
890
|
+
}
|
|
891
|
+
if (spent < 0n) throw new Error('Cannot restore session: spent must not be negative.')
|
|
892
|
+
if (spent > channel.cumulativeAmount) {
|
|
893
|
+
throw new Error('Cannot restore session: spent exceeds local voucher state.')
|
|
894
|
+
}
|
|
895
|
+
assertVoucherWithinLocalLimit(channel.cumulativeAmount)
|
|
896
|
+
const snapshot = validateCloseSnapshot(channel, challenge)
|
|
897
|
+
const restoredSpent = snapshot && snapshot.spent > spent ? snapshot.spent : spent
|
|
898
|
+
|
|
899
|
+
runtime.lastUrl = input
|
|
900
|
+
runtime.lastChallenge = challenge
|
|
901
|
+
runtime.channel = channel
|
|
902
|
+
runtime.spent = restoredSpent
|
|
903
|
+
dispatch({ type: 'challengeReceived', challengeId: challenge.id })
|
|
904
|
+
dispatch({
|
|
905
|
+
type: 'activated',
|
|
906
|
+
challengeId: challenge.id,
|
|
907
|
+
entry: channel,
|
|
908
|
+
spent: restoredSpent.toString(),
|
|
909
|
+
units: 0,
|
|
910
|
+
})
|
|
911
|
+
},
|
|
912
|
+
})
|
|
913
|
+
|
|
771
914
|
return self
|
|
772
915
|
}
|
|
773
916
|
|
|
@@ -778,6 +921,8 @@ export namespace sessionManager {
|
|
|
778
921
|
|
|
779
922
|
export type Parameters = Account.getResolver.Parameters &
|
|
780
923
|
Client.getResolver.Parameters & {
|
|
924
|
+
/** Automatically acquire the session currency from fallback stablecoins before open/top-up. */
|
|
925
|
+
autoSwap?: sessionPlugin.Parameters['autoSwap']
|
|
781
926
|
/** Enables same-route HEAD bootstrap from a server session snapshot before opening a new channel. */
|
|
782
927
|
bootstrap?: boolean | undefined
|
|
783
928
|
/** Viem client instance. Shorthand for `getClient: () => client`. */
|
|
@@ -790,6 +935,11 @@ export namespace sessionManager {
|
|
|
790
935
|
fetch?: typeof globalThis.fetch | undefined
|
|
791
936
|
/** Maximum deposit in human-readable units (e.g. `'10'` for 10 tokens). Converted to raw units via `decimals`. */
|
|
792
937
|
maxDeposit?: string | undefined
|
|
938
|
+
/**
|
|
939
|
+
* Preferred automatic top-up size in human-readable units. When omitted,
|
|
940
|
+
* a bounded server `suggestedDeposit` is preferred, then the exact shortfall.
|
|
941
|
+
*/
|
|
942
|
+
topUpAmount?: string | undefined
|
|
793
943
|
/** Selects the account that signs session credentials. */
|
|
794
944
|
resolveAccount?: sessionPlugin.ResolveAccount | undefined
|
|
795
945
|
/** Store for reusable session channels. Defaults to in-memory. */
|