mppx 0.5.6 → 0.5.8
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 +14 -0
- package/dist/Challenge.d.ts +3 -2
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +27 -9
- package/dist/Challenge.js.map +1 -1
- package/dist/Html.d.ts +2 -1
- package/dist/Html.d.ts.map +1 -1
- package/dist/Html.js +1 -1
- package/dist/Html.js.map +1 -1
- package/dist/Method.d.ts +32 -14
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js.map +1 -1
- package/dist/Store.d.ts +68 -2
- package/dist/Store.d.ts.map +1 -1
- package/dist/Store.js +41 -4
- package/dist/Store.js.map +1 -1
- package/dist/mcp-sdk/server/Transport.d.ts.map +1 -1
- package/dist/mcp-sdk/server/Transport.js +7 -0
- package/dist/mcp-sdk/server/Transport.js.map +1 -1
- package/dist/server/Mppx.d.ts +1 -1
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +133 -70
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Transport.d.ts +8 -2
- package/dist/server/Transport.d.ts.map +1 -1
- package/dist/server/Transport.js +26 -1
- package/dist/server/Transport.js.map +1 -1
- package/dist/server/internal/html/config.d.ts +4 -0
- package/dist/server/internal/html/config.d.ts.map +1 -1
- package/dist/server/internal/html/config.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +2 -4
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/tempo/client/SessionManager.d.ts +13 -2
- package/dist/tempo/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/client/SessionManager.js +429 -4
- package/dist/tempo/client/SessionManager.js.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +28 -0
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +89 -0
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +5 -5
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +90 -66
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +3 -0
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +3 -0
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Session.d.ts +8 -2
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js.map +1 -1
- 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/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +16 -6
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/dist/tempo/session/ChannelStore.d.ts +12 -1
- package/dist/tempo/session/ChannelStore.d.ts.map +1 -1
- package/dist/tempo/session/ChannelStore.js +55 -14
- package/dist/tempo/session/ChannelStore.js.map +1 -1
- package/dist/tempo/session/Sse.d.ts +11 -2
- package/dist/tempo/session/Sse.d.ts.map +1 -1
- package/dist/tempo/session/Sse.js +66 -25
- package/dist/tempo/session/Sse.js.map +1 -1
- package/dist/tempo/session/Ws.d.ts +87 -0
- package/dist/tempo/session/Ws.d.ts.map +1 -0
- package/dist/tempo/session/Ws.js +428 -0
- package/dist/tempo/session/Ws.js.map +1 -0
- package/dist/tempo/session/index.d.ts +1 -0
- package/dist/tempo/session/index.d.ts.map +1 -1
- package/dist/tempo/session/index.js +1 -0
- package/dist/tempo/session/index.js.map +1 -1
- package/package.json +1 -1
- package/src/Challenge.test.ts +1 -1
- package/src/Challenge.ts +28 -9
- package/src/Html.ts +11 -1
- package/src/Method.ts +61 -20
- package/src/Store.test-d.ts +80 -2
- package/src/Store.test.ts +150 -13
- package/src/Store.ts +140 -3
- package/src/mcp-sdk/server/Transport.test.ts +12 -0
- package/src/mcp-sdk/server/Transport.ts +8 -0
- package/src/server/Mppx.test.ts +105 -0
- package/src/server/Mppx.ts +179 -89
- package/src/server/Transport.test.ts +31 -0
- package/src/server/Transport.ts +31 -2
- package/src/server/internal/html/config.ts +5 -0
- package/src/stripe/server/Charge.ts +2 -4
- package/src/tempo/client/SessionManager.ts +510 -7
- package/src/tempo/internal/fee-payer.test.ts +115 -1
- package/src/tempo/internal/fee-payer.ts +138 -1
- package/src/tempo/server/AtomicStore.test-d.ts +34 -0
- package/src/tempo/server/Charge.test.ts +128 -0
- package/src/tempo/server/Charge.ts +119 -100
- package/src/tempo/server/Methods.ts +3 -0
- package/src/tempo/server/Session.test.ts +1044 -47
- package/src/tempo/server/Session.ts +8 -2
- package/src/tempo/server/Sse.test.ts +29 -0
- package/src/tempo/server/index.ts +1 -0
- package/src/tempo/server/internal/html/main.ts +9 -10
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/transport.ts +19 -6
- package/src/tempo/session/ChannelStore.test.ts +20 -1
- package/src/tempo/session/ChannelStore.ts +77 -14
- package/src/tempo/session/Sse.ts +77 -24
- package/src/tempo/session/Ws.test.ts +410 -0
- package/src/tempo/session/Ws.ts +563 -0
- package/src/tempo/session/index.ts +1 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import * as Credential from '../../Credential.js';
|
|
2
|
+
import * as ChannelStore from './ChannelStore.js';
|
|
3
|
+
import { deserializeSessionReceipt } from './Receipt.js';
|
|
4
|
+
import { createSessionReceipt } from './Receipt.js';
|
|
5
|
+
export function formatAuthorizationMessage(authorization) {
|
|
6
|
+
return JSON.stringify({ mpp: 'authorization', authorization });
|
|
7
|
+
}
|
|
8
|
+
export function formatApplicationMessage(data) {
|
|
9
|
+
return JSON.stringify({ mpp: 'message', data });
|
|
10
|
+
}
|
|
11
|
+
export function formatCloseRequestMessage() {
|
|
12
|
+
return JSON.stringify({ mpp: 'payment-close-request' });
|
|
13
|
+
}
|
|
14
|
+
export function formatCloseReadyMessage(receipt) {
|
|
15
|
+
return JSON.stringify({ mpp: 'payment-close-ready', data: receipt });
|
|
16
|
+
}
|
|
17
|
+
export function formatNeedVoucherMessage(params) {
|
|
18
|
+
return JSON.stringify({ mpp: 'payment-need-voucher', data: params });
|
|
19
|
+
}
|
|
20
|
+
export function formatReceiptMessage(receipt) {
|
|
21
|
+
return JSON.stringify({ mpp: 'payment-receipt', data: receipt });
|
|
22
|
+
}
|
|
23
|
+
export function formatErrorMessage(parameters) {
|
|
24
|
+
return JSON.stringify({ mpp: 'payment-error', ...parameters });
|
|
25
|
+
}
|
|
26
|
+
export function parseMessage(raw) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(raw);
|
|
29
|
+
if (parsed.mpp === 'authorization' && typeof parsed.authorization === 'string') {
|
|
30
|
+
return { mpp: 'authorization', authorization: parsed.authorization };
|
|
31
|
+
}
|
|
32
|
+
if (parsed.mpp === 'message' && typeof parsed.data === 'string') {
|
|
33
|
+
return { mpp: 'message', data: parsed.data };
|
|
34
|
+
}
|
|
35
|
+
if (parsed.mpp === 'payment-close-request') {
|
|
36
|
+
return { mpp: 'payment-close-request' };
|
|
37
|
+
}
|
|
38
|
+
if (parsed.mpp === 'payment-close-ready' && isSessionReceipt(parsed.data)) {
|
|
39
|
+
return { mpp: 'payment-close-ready', data: parsed.data };
|
|
40
|
+
}
|
|
41
|
+
if (parsed.mpp === 'payment-error' &&
|
|
42
|
+
typeof parsed.status === 'number' &&
|
|
43
|
+
typeof parsed.message === 'string') {
|
|
44
|
+
return { mpp: 'payment-error', status: parsed.status, message: parsed.message };
|
|
45
|
+
}
|
|
46
|
+
if (parsed.mpp === 'payment-need-voucher' && isNeedVoucherEvent(parsed.data)) {
|
|
47
|
+
return { mpp: 'payment-need-voucher', data: parsed.data };
|
|
48
|
+
}
|
|
49
|
+
if (parsed.mpp === 'payment-receipt' && isSessionReceipt(parsed.data)) {
|
|
50
|
+
return { mpp: 'payment-receipt', data: parsed.data };
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Bridge a WebSocket connection to a Tempo session payment flow.
|
|
60
|
+
*
|
|
61
|
+
* Credential verification is performed by routing each in-band authorization
|
|
62
|
+
* frame through `route` as a **synthetic `POST` request** that carries only
|
|
63
|
+
* the `Authorization` header. The synthetic request does not include cookies,
|
|
64
|
+
* bodies, query parameters, or other headers from the original WebSocket
|
|
65
|
+
* upgrade request. Do not wrap `route` with middleware that depends on
|
|
66
|
+
* HTTP-specific context beyond the `Authorization` header.
|
|
67
|
+
*/
|
|
68
|
+
export async function serve(options) {
|
|
69
|
+
const { amount: expectedAmount, generate, pollIntervalMs = 100, route, socket, store: rawStore, url, } = options;
|
|
70
|
+
const store = 'getChannel' in rawStore ? rawStore : ChannelStore.fromStore(rawStore);
|
|
71
|
+
const requestUrl = normalizeHttpUrl(url);
|
|
72
|
+
const maxQueuedPaymentMessages = 32;
|
|
73
|
+
const abortController = new AbortController();
|
|
74
|
+
let closed = false;
|
|
75
|
+
let closeReadySent = false;
|
|
76
|
+
let closeRequestHandled = false;
|
|
77
|
+
let closeRequested = false;
|
|
78
|
+
let streamStarted = false;
|
|
79
|
+
let streamTask = null;
|
|
80
|
+
let streamContext = null;
|
|
81
|
+
let action = Promise.resolve();
|
|
82
|
+
let queuedActions = 0;
|
|
83
|
+
const close = async (code = 1000, reason) => {
|
|
84
|
+
if (closed)
|
|
85
|
+
return;
|
|
86
|
+
closed = true;
|
|
87
|
+
abortController.abort();
|
|
88
|
+
unsubscribe();
|
|
89
|
+
await Promise.resolve(socket.close(code, reason));
|
|
90
|
+
};
|
|
91
|
+
const sendCloseReady = async () => {
|
|
92
|
+
if (closeReadySent || !streamContext || closed)
|
|
93
|
+
return;
|
|
94
|
+
closeReadySent = true;
|
|
95
|
+
const channel = await store.getChannel(streamContext.channelId);
|
|
96
|
+
if (!channel)
|
|
97
|
+
throw new Error('channel not found');
|
|
98
|
+
const receipt = createSessionReceipt({
|
|
99
|
+
challengeId: streamContext.challengeId,
|
|
100
|
+
channelId: streamContext.channelId,
|
|
101
|
+
acceptedCumulative: channel.highestVoucherAmount,
|
|
102
|
+
spent: channel.spent,
|
|
103
|
+
units: channel.units,
|
|
104
|
+
});
|
|
105
|
+
await send(socket, formatCloseReadyMessage(receipt));
|
|
106
|
+
};
|
|
107
|
+
const runStream = async (context) => {
|
|
108
|
+
let reservedAmount = 0n;
|
|
109
|
+
let reservedUnits = 0;
|
|
110
|
+
const charge = () => reserveChargeOrWait({
|
|
111
|
+
amount: context.tickCost,
|
|
112
|
+
channelId: context.channelId,
|
|
113
|
+
reservedAmount,
|
|
114
|
+
emit: (message) => send(socket, message),
|
|
115
|
+
pollIntervalMs,
|
|
116
|
+
signal: abortController.signal,
|
|
117
|
+
store,
|
|
118
|
+
}).then(() => {
|
|
119
|
+
reservedAmount += context.tickCost;
|
|
120
|
+
reservedUnits += 1;
|
|
121
|
+
});
|
|
122
|
+
const iterable = typeof generate === 'function' ? generate({ charge }) : generate;
|
|
123
|
+
try {
|
|
124
|
+
for await (const value of iterable) {
|
|
125
|
+
if (abortController.signal.aborted)
|
|
126
|
+
break;
|
|
127
|
+
if (typeof generate !== 'function')
|
|
128
|
+
await charge();
|
|
129
|
+
await commitReservedCharges({
|
|
130
|
+
store,
|
|
131
|
+
channelId: context.channelId,
|
|
132
|
+
amount: reservedAmount,
|
|
133
|
+
units: reservedUnits,
|
|
134
|
+
});
|
|
135
|
+
reservedAmount = 0n;
|
|
136
|
+
reservedUnits = 0;
|
|
137
|
+
await send(socket, formatApplicationMessage(value));
|
|
138
|
+
}
|
|
139
|
+
if (!abortController.signal.aborted)
|
|
140
|
+
await sendCloseReady();
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (!abortController.signal.aborted) {
|
|
144
|
+
await send(socket, formatErrorMessage({
|
|
145
|
+
message: error instanceof Error ? error.message : 'websocket session failed',
|
|
146
|
+
status: 500,
|
|
147
|
+
}));
|
|
148
|
+
await close(1011, 'websocket session failed');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
streamTask = null;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const requestClose = async () => {
|
|
156
|
+
if (closed)
|
|
157
|
+
return;
|
|
158
|
+
if (closeRequestHandled)
|
|
159
|
+
return;
|
|
160
|
+
closeRequestHandled = true;
|
|
161
|
+
closeRequested = true;
|
|
162
|
+
abortController.abort();
|
|
163
|
+
await streamTask?.catch(() => { });
|
|
164
|
+
await sendCloseReady();
|
|
165
|
+
};
|
|
166
|
+
const processAuthorization = async (authorization) => {
|
|
167
|
+
if (closed)
|
|
168
|
+
return;
|
|
169
|
+
const credential = Credential.deserialize(authorization);
|
|
170
|
+
const payload = credential.payload;
|
|
171
|
+
if (payload.action === 'close')
|
|
172
|
+
closeRequested = true;
|
|
173
|
+
if (expectedAmount && credential.challenge.request.amount !== expectedAmount) {
|
|
174
|
+
await send(socket, formatErrorMessage({
|
|
175
|
+
message: 'credential amount does not match this endpoint',
|
|
176
|
+
status: 402,
|
|
177
|
+
}));
|
|
178
|
+
await close(1008, 'credential amount does not match this endpoint');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const result = await route(new Request(requestUrl, {
|
|
182
|
+
method: 'POST',
|
|
183
|
+
headers: { Authorization: authorization },
|
|
184
|
+
}));
|
|
185
|
+
if (result.status === 402) {
|
|
186
|
+
const response = result.challenge;
|
|
187
|
+
const message = (await response.text().catch(() => '')) ||
|
|
188
|
+
response.statusText ||
|
|
189
|
+
'payment verification failed';
|
|
190
|
+
await send(socket, formatErrorMessage({ message, status: response.status }));
|
|
191
|
+
await close(1008, message);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const response = result.withReceipt(new Response(null, { status: 204 }));
|
|
195
|
+
const receiptHeader = response.headers.get('Payment-Receipt');
|
|
196
|
+
if (!receiptHeader) {
|
|
197
|
+
throw new Error('management response missing Payment-Receipt header');
|
|
198
|
+
}
|
|
199
|
+
const receipt = deserializeSessionReceipt(receiptHeader);
|
|
200
|
+
await send(socket, formatReceiptMessage(receipt));
|
|
201
|
+
if (payload.action === 'close') {
|
|
202
|
+
await close(1000, 'payment session closed');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (payload.action === 'topUp')
|
|
206
|
+
return;
|
|
207
|
+
if (streamStarted || closeRequested)
|
|
208
|
+
return;
|
|
209
|
+
streamStarted = true;
|
|
210
|
+
streamContext = {
|
|
211
|
+
challengeId: credential.challenge.id,
|
|
212
|
+
channelId: payload.channelId,
|
|
213
|
+
tickCost: BigInt(credential.challenge.request.amount),
|
|
214
|
+
};
|
|
215
|
+
// Defer the first application frame until after the client receives the
|
|
216
|
+
// auth receipt and has a chance to install its own message listeners.
|
|
217
|
+
setTimeout(() => {
|
|
218
|
+
if (closeRequested || closed || !streamContext)
|
|
219
|
+
return;
|
|
220
|
+
streamTask = runStream(streamContext);
|
|
221
|
+
}, 0);
|
|
222
|
+
};
|
|
223
|
+
const onMessage = (payload) => {
|
|
224
|
+
if (closed)
|
|
225
|
+
return;
|
|
226
|
+
const raw = toText(payload);
|
|
227
|
+
if (!raw)
|
|
228
|
+
return;
|
|
229
|
+
const message = parseMessage(raw);
|
|
230
|
+
if (!message)
|
|
231
|
+
return;
|
|
232
|
+
if (message.mpp === 'payment-close-request') {
|
|
233
|
+
closeRequested = true;
|
|
234
|
+
abortController.abort();
|
|
235
|
+
}
|
|
236
|
+
const work = message.mpp === 'authorization'
|
|
237
|
+
? () => processAuthorization(message.authorization)
|
|
238
|
+
: message.mpp === 'payment-close-request'
|
|
239
|
+
? () => requestClose()
|
|
240
|
+
: null;
|
|
241
|
+
if (!work)
|
|
242
|
+
return;
|
|
243
|
+
if (queuedActions >= maxQueuedPaymentMessages) {
|
|
244
|
+
void send(socket, formatErrorMessage({
|
|
245
|
+
message: 'too many queued payment messages',
|
|
246
|
+
status: 429,
|
|
247
|
+
})).catch(() => { });
|
|
248
|
+
void close(1008, 'too many queued payment messages');
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
queuedActions++;
|
|
252
|
+
action = action
|
|
253
|
+
.then(async () => {
|
|
254
|
+
try {
|
|
255
|
+
if (closed)
|
|
256
|
+
return;
|
|
257
|
+
await work();
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
queuedActions--;
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
.catch(async (error) => {
|
|
264
|
+
if (!closed) {
|
|
265
|
+
await send(socket, formatErrorMessage({
|
|
266
|
+
message: error instanceof Error ? error.message : 'invalid payment message',
|
|
267
|
+
status: 400,
|
|
268
|
+
}));
|
|
269
|
+
await close(1008, 'invalid payment message');
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
const onClose = () => {
|
|
274
|
+
if (closed)
|
|
275
|
+
return;
|
|
276
|
+
closed = true;
|
|
277
|
+
abortController.abort();
|
|
278
|
+
unsubscribe();
|
|
279
|
+
};
|
|
280
|
+
const unsubscribe = subscribe(socket, {
|
|
281
|
+
close: onClose,
|
|
282
|
+
error: onClose,
|
|
283
|
+
message: onMessage,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
function normalizeHttpUrl(value) {
|
|
287
|
+
const url = new URL(value.toString());
|
|
288
|
+
if (url.protocol === 'ws:')
|
|
289
|
+
url.protocol = 'http:';
|
|
290
|
+
if (url.protocol === 'wss:')
|
|
291
|
+
url.protocol = 'https:';
|
|
292
|
+
return url.toString();
|
|
293
|
+
}
|
|
294
|
+
async function reserveChargeOrWait(options) {
|
|
295
|
+
const { amount, channelId, emit, pollIntervalMs, reservedAmount, signal, store } = options;
|
|
296
|
+
let channel = await store.getChannel(channelId);
|
|
297
|
+
if (!channel)
|
|
298
|
+
throw new Error('channel not found');
|
|
299
|
+
const hasHeadroom = (state) => state.highestVoucherAmount - state.spent - reservedAmount >= amount;
|
|
300
|
+
if (hasHeadroom(channel))
|
|
301
|
+
return;
|
|
302
|
+
await emit(formatNeedVoucherMessage({
|
|
303
|
+
channelId,
|
|
304
|
+
requiredCumulative: (channel.spent + reservedAmount + amount).toString(),
|
|
305
|
+
acceptedCumulative: channel.highestVoucherAmount.toString(),
|
|
306
|
+
deposit: channel.deposit.toString(),
|
|
307
|
+
}));
|
|
308
|
+
while (!hasHeadroom(channel)) {
|
|
309
|
+
await waitForUpdate(store, channelId, pollIntervalMs, signal);
|
|
310
|
+
channel = await store.getChannel(channelId);
|
|
311
|
+
if (!channel)
|
|
312
|
+
throw new Error('channel not found');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function commitReservedCharges(options) {
|
|
316
|
+
const { amount, channelId, units, store } = options;
|
|
317
|
+
if (amount === 0n || units === 0)
|
|
318
|
+
return;
|
|
319
|
+
let committed = false;
|
|
320
|
+
const channel = await store.updateChannel(channelId, (current) => {
|
|
321
|
+
if (!current)
|
|
322
|
+
return null;
|
|
323
|
+
if (current.finalized)
|
|
324
|
+
return current;
|
|
325
|
+
if (current.highestVoucherAmount - current.spent < amount)
|
|
326
|
+
return current;
|
|
327
|
+
committed = true;
|
|
328
|
+
return {
|
|
329
|
+
...current,
|
|
330
|
+
spent: current.spent + amount,
|
|
331
|
+
units: current.units + units,
|
|
332
|
+
};
|
|
333
|
+
});
|
|
334
|
+
if (!channel)
|
|
335
|
+
throw new Error('channel not found');
|
|
336
|
+
if (!committed)
|
|
337
|
+
throw new Error('reserved voucher coverage is no longer available');
|
|
338
|
+
}
|
|
339
|
+
async function waitForUpdate(store, channelId, pollIntervalMs, signal) {
|
|
340
|
+
throwIfAborted(signal);
|
|
341
|
+
if (store.waitForUpdate) {
|
|
342
|
+
await Promise.race([store.waitForUpdate(channelId), onceAborted(signal)]);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
await sleep(pollIntervalMs, signal);
|
|
346
|
+
}
|
|
347
|
+
function subscribe(socket, handlers) {
|
|
348
|
+
if (socket.addEventListener && socket.removeEventListener) {
|
|
349
|
+
const onMessage = (event) => {
|
|
350
|
+
const data = event.data;
|
|
351
|
+
handlers.message(data);
|
|
352
|
+
};
|
|
353
|
+
socket.addEventListener('message', onMessage);
|
|
354
|
+
socket.addEventListener('close', handlers.close);
|
|
355
|
+
socket.addEventListener('error', handlers.error);
|
|
356
|
+
return () => {
|
|
357
|
+
socket.removeEventListener?.('message', onMessage);
|
|
358
|
+
socket.removeEventListener?.('close', handlers.close);
|
|
359
|
+
socket.removeEventListener?.('error', handlers.error);
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (socket.on && socket.off) {
|
|
363
|
+
const onMessage = (data) => handlers.message(data);
|
|
364
|
+
socket.on('message', onMessage);
|
|
365
|
+
socket.on('close', handlers.close);
|
|
366
|
+
socket.on('error', handlers.error);
|
|
367
|
+
return () => {
|
|
368
|
+
socket.off?.('message', onMessage);
|
|
369
|
+
socket.off?.('close', handlers.close);
|
|
370
|
+
socket.off?.('error', handlers.error);
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
throw new Error('unsupported websocket implementation');
|
|
374
|
+
}
|
|
375
|
+
async function send(socket, data) {
|
|
376
|
+
await Promise.resolve(socket.send(data));
|
|
377
|
+
}
|
|
378
|
+
function toText(value) {
|
|
379
|
+
if (typeof value === 'string')
|
|
380
|
+
return value;
|
|
381
|
+
if (value instanceof ArrayBuffer)
|
|
382
|
+
return new TextDecoder().decode(value);
|
|
383
|
+
if (ArrayBuffer.isView(value)) {
|
|
384
|
+
return new TextDecoder().decode(value);
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
function sleep(ms, signal) {
|
|
389
|
+
return new Promise((resolve, reject) => {
|
|
390
|
+
const timeout = setTimeout(() => {
|
|
391
|
+
signal.removeEventListener('abort', onAbort);
|
|
392
|
+
resolve();
|
|
393
|
+
}, ms);
|
|
394
|
+
const onAbort = () => {
|
|
395
|
+
clearTimeout(timeout);
|
|
396
|
+
reject(signal.reason ?? new Error('aborted'));
|
|
397
|
+
};
|
|
398
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function onceAborted(signal) {
|
|
402
|
+
return new Promise((_, reject) => {
|
|
403
|
+
if (signal.aborted) {
|
|
404
|
+
reject(signal.reason ?? new Error('aborted'));
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
signal.addEventListener('abort', () => reject(signal.reason ?? new Error('aborted')), {
|
|
408
|
+
once: true,
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
function throwIfAborted(signal) {
|
|
413
|
+
if (signal.aborted)
|
|
414
|
+
throw signal.reason ?? new Error('aborted');
|
|
415
|
+
}
|
|
416
|
+
function isSessionReceipt(value) {
|
|
417
|
+
if (typeof value !== 'object' || value === null)
|
|
418
|
+
return false;
|
|
419
|
+
const v = value;
|
|
420
|
+
return typeof v.challengeId === 'string' && typeof v.channelId === 'string';
|
|
421
|
+
}
|
|
422
|
+
function isNeedVoucherEvent(value) {
|
|
423
|
+
if (typeof value !== 'object' || value === null)
|
|
424
|
+
return false;
|
|
425
|
+
const v = value;
|
|
426
|
+
return typeof v.channelId === 'string' && typeof v.requiredCumulative === 'string';
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=Ws.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Ws.js","sourceRoot":"","sources":["../../../src/tempo/session/Ws.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tempo/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tempo/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tempo/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tempo/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA"}
|
package/package.json
CHANGED
package/src/Challenge.test.ts
CHANGED
|
@@ -56,7 +56,7 @@ describe('from', () => {
|
|
|
56
56
|
// ---------------------------------------------------------------------------
|
|
57
57
|
// HMAC Challenge ID Test Vectors
|
|
58
58
|
//
|
|
59
|
-
// HMAC input: realm | method | intent | base64url(canonicalize(request)) | expires | digest
|
|
59
|
+
// HMAC input: realm | method | intent | base64url(canonicalize(request)) | expires | digest | opaque
|
|
60
60
|
// HMAC key: UTF-8 bytes of secretKey
|
|
61
61
|
// Output: base64url(HMAC-SHA256(key, input), no padding)
|
|
62
62
|
//
|
package/src/Challenge.ts
CHANGED
|
@@ -78,7 +78,8 @@ export type FromMethods<methods extends readonly Method.Method[]> = {
|
|
|
78
78
|
* Creates a challenge from the given parameters.
|
|
79
79
|
*
|
|
80
80
|
* If `secretKey` option is provided, the challenge ID is computed as HMAC-SHA256
|
|
81
|
-
* over the challenge
|
|
81
|
+
* over the canonical challenge ID input
|
|
82
|
+
* (`realm|method|intent|request|expires|digest|opaque`),
|
|
82
83
|
* cryptographically binding the ID to its contents.
|
|
83
84
|
*
|
|
84
85
|
* @param parameters - Challenge parameters.
|
|
@@ -189,7 +190,7 @@ export declare namespace from {
|
|
|
189
190
|
* Creates a validated challenge from a method intent.
|
|
190
191
|
*
|
|
191
192
|
* If `secretKey` option is provided, the challenge ID is computed as HMAC-SHA256
|
|
192
|
-
* over the challenge
|
|
193
|
+
* over the canonical challenge ID input, cryptographically binding the ID to its contents.
|
|
193
194
|
*
|
|
194
195
|
* @param intent - The method intent to validate against.
|
|
195
196
|
* @param parameters - Challenge parameters (realm, request, optional expires/digest, and id if no secretKey).
|
|
@@ -608,13 +609,22 @@ export function meta(challenge: Challenge): Record<string, string> | undefined {
|
|
|
608
609
|
return challenge.opaque
|
|
609
610
|
}
|
|
610
611
|
|
|
611
|
-
/**
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
612
|
+
/**
|
|
613
|
+
* Canonical HMAC input for challenge ID binding per §5.1.2.1.1 of the spec.
|
|
614
|
+
*
|
|
615
|
+
* Seven fixed positional slots, pipe-delimited. Optional fields use empty
|
|
616
|
+
* string when absent so the slot count is stable. This is the single source
|
|
617
|
+
* of truth for what the challenge ID binds to — used by both `computeId()`
|
|
618
|
+
* (challenge creation) and `verify()` (credential verification).
|
|
619
|
+
*
|
|
620
|
+
* Slots: realm | method | intent | request | expires | digest | opaque
|
|
621
|
+
*
|
|
622
|
+
* Because the HMAC covers ALL fields, the server does not need to separately
|
|
623
|
+
* pin opaque, digest, or expires during verification — any change to those
|
|
624
|
+
* fields produces a different HMAC and fails the ID comparison.
|
|
625
|
+
*/
|
|
626
|
+
function idBindingInput(challenge: Omit<Challenge, 'id'>): string {
|
|
627
|
+
return [
|
|
618
628
|
challenge.realm,
|
|
619
629
|
challenge.method,
|
|
620
630
|
challenge.intent,
|
|
@@ -623,6 +633,15 @@ function computeId(challenge: Omit<Challenge, 'id'>, options: { secretKey: strin
|
|
|
623
633
|
challenge.digest ?? '',
|
|
624
634
|
challenge.opaque ? PaymentRequest.serialize(challenge.opaque) : '',
|
|
625
635
|
].join('|')
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/** @internal Computes HMAC-SHA256 challenge ID from parameters. */
|
|
639
|
+
function computeId(challenge: Omit<Challenge, 'id'>, options: { secretKey: string }): string {
|
|
640
|
+
// Each field occupies a fixed positional slot joined by '|'. Optional fields
|
|
641
|
+
// use an empty string when absent so the slot count is stable — this avoids
|
|
642
|
+
// ambiguity between e.g. (expires set, no digest) vs (no expires, digest set)
|
|
643
|
+
// and means adding a new optional field changes all HMACs exactly once.
|
|
644
|
+
const input = idBindingInput(challenge)
|
|
626
645
|
|
|
627
646
|
const key = Bytes.fromString(options.secretKey)
|
|
628
647
|
const data = Bytes.fromString(input)
|
package/src/Html.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { Json } from 'ox'
|
|
2
2
|
|
|
3
3
|
import type * as Method from './Method.js'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
attrs,
|
|
6
|
+
type Config,
|
|
7
|
+
type Data,
|
|
8
|
+
ids,
|
|
9
|
+
type Text,
|
|
10
|
+
type Theme,
|
|
11
|
+
vars,
|
|
12
|
+
} from './server/internal/html/config.js'
|
|
5
13
|
import { submitCredential } from './server/internal/html/serviceWorker.client.js'
|
|
6
14
|
|
|
7
15
|
export function init<
|
|
@@ -55,3 +63,5 @@ export type Context<
|
|
|
55
63
|
submit: (credential: string) => Promise<void>
|
|
56
64
|
vars: typeof vars
|
|
57
65
|
}
|
|
66
|
+
|
|
67
|
+
export type { Config, Text, Theme }
|