mppx 0.5.7 → 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.
Files changed (102) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/Challenge.d.ts +3 -2
  3. package/dist/Challenge.d.ts.map +1 -1
  4. package/dist/Challenge.js +27 -9
  5. package/dist/Challenge.js.map +1 -1
  6. package/dist/Method.d.ts +32 -14
  7. package/dist/Method.d.ts.map +1 -1
  8. package/dist/Method.js.map +1 -1
  9. package/dist/Store.d.ts +68 -2
  10. package/dist/Store.d.ts.map +1 -1
  11. package/dist/Store.js +41 -4
  12. package/dist/Store.js.map +1 -1
  13. package/dist/mcp-sdk/server/Transport.d.ts.map +1 -1
  14. package/dist/mcp-sdk/server/Transport.js +7 -0
  15. package/dist/mcp-sdk/server/Transport.js.map +1 -1
  16. package/dist/server/Mppx.d.ts +1 -1
  17. package/dist/server/Mppx.d.ts.map +1 -1
  18. package/dist/server/Mppx.js +133 -70
  19. package/dist/server/Mppx.js.map +1 -1
  20. package/dist/server/Transport.d.ts +8 -2
  21. package/dist/server/Transport.d.ts.map +1 -1
  22. package/dist/server/Transport.js +26 -1
  23. package/dist/server/Transport.js.map +1 -1
  24. package/dist/tempo/client/SessionManager.d.ts +13 -2
  25. package/dist/tempo/client/SessionManager.d.ts.map +1 -1
  26. package/dist/tempo/client/SessionManager.js +429 -4
  27. package/dist/tempo/client/SessionManager.js.map +1 -1
  28. package/dist/tempo/internal/fee-payer.d.ts +28 -0
  29. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  30. package/dist/tempo/internal/fee-payer.js +89 -0
  31. package/dist/tempo/internal/fee-payer.js.map +1 -1
  32. package/dist/tempo/server/Charge.d.ts +4 -1
  33. package/dist/tempo/server/Charge.d.ts.map +1 -1
  34. package/dist/tempo/server/Charge.js +90 -66
  35. package/dist/tempo/server/Charge.js.map +1 -1
  36. package/dist/tempo/server/Methods.d.ts +3 -0
  37. package/dist/tempo/server/Methods.d.ts.map +1 -1
  38. package/dist/tempo/server/Methods.js +3 -0
  39. package/dist/tempo/server/Methods.js.map +1 -1
  40. package/dist/tempo/server/Session.d.ts +8 -2
  41. package/dist/tempo/server/Session.d.ts.map +1 -1
  42. package/dist/tempo/server/Session.js.map +1 -1
  43. package/dist/tempo/server/index.d.ts +1 -0
  44. package/dist/tempo/server/index.d.ts.map +1 -1
  45. package/dist/tempo/server/index.js +1 -0
  46. package/dist/tempo/server/index.js.map +1 -1
  47. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  48. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  49. package/dist/tempo/server/internal/html.gen.js +1 -1
  50. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  51. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  52. package/dist/tempo/server/internal/transport.js +16 -6
  53. package/dist/tempo/server/internal/transport.js.map +1 -1
  54. package/dist/tempo/session/ChannelStore.d.ts +12 -1
  55. package/dist/tempo/session/ChannelStore.d.ts.map +1 -1
  56. package/dist/tempo/session/ChannelStore.js +55 -14
  57. package/dist/tempo/session/ChannelStore.js.map +1 -1
  58. package/dist/tempo/session/Sse.d.ts +11 -2
  59. package/dist/tempo/session/Sse.d.ts.map +1 -1
  60. package/dist/tempo/session/Sse.js +66 -25
  61. package/dist/tempo/session/Sse.js.map +1 -1
  62. package/dist/tempo/session/Ws.d.ts +87 -0
  63. package/dist/tempo/session/Ws.d.ts.map +1 -0
  64. package/dist/tempo/session/Ws.js +428 -0
  65. package/dist/tempo/session/Ws.js.map +1 -0
  66. package/dist/tempo/session/index.d.ts +1 -0
  67. package/dist/tempo/session/index.d.ts.map +1 -1
  68. package/dist/tempo/session/index.js +1 -0
  69. package/dist/tempo/session/index.js.map +1 -1
  70. package/package.json +1 -1
  71. package/src/Challenge.test.ts +1 -1
  72. package/src/Challenge.ts +28 -9
  73. package/src/Method.ts +61 -20
  74. package/src/Store.test-d.ts +80 -2
  75. package/src/Store.test.ts +150 -13
  76. package/src/Store.ts +140 -3
  77. package/src/mcp-sdk/server/Transport.test.ts +12 -0
  78. package/src/mcp-sdk/server/Transport.ts +8 -0
  79. package/src/server/Mppx.test.ts +105 -0
  80. package/src/server/Mppx.ts +178 -88
  81. package/src/server/Transport.test.ts +31 -0
  82. package/src/server/Transport.ts +31 -2
  83. package/src/tempo/client/SessionManager.ts +510 -7
  84. package/src/tempo/internal/fee-payer.test.ts +115 -1
  85. package/src/tempo/internal/fee-payer.ts +138 -1
  86. package/src/tempo/server/AtomicStore.test-d.ts +34 -0
  87. package/src/tempo/server/Charge.test.ts +128 -0
  88. package/src/tempo/server/Charge.ts +118 -93
  89. package/src/tempo/server/Methods.ts +3 -0
  90. package/src/tempo/server/Session.test.ts +1044 -47
  91. package/src/tempo/server/Session.ts +8 -2
  92. package/src/tempo/server/Sse.test.ts +29 -0
  93. package/src/tempo/server/index.ts +1 -0
  94. package/src/tempo/server/internal/html/main.ts +9 -10
  95. package/src/tempo/server/internal/html.gen.ts +1 -1
  96. package/src/tempo/server/internal/transport.ts +19 -6
  97. package/src/tempo/session/ChannelStore.test.ts +20 -1
  98. package/src/tempo/session/ChannelStore.ts +77 -14
  99. package/src/tempo/session/Sse.ts +77 -24
  100. package/src/tempo/session/Ws.test.ts +410 -0
  101. package/src/tempo/session/Ws.ts +563 -0
  102. 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":"AAAA,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAoCnD,MAAM,UAAU,0BAA0B,CAAC,aAAqB;IAC9D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,aAAa,EAAoB,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAoB,CAAC,CAAA;AACnE,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAoB,CAAC,CAAA;AAC3E,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAuB;IAC7D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,qBAAqB,EAAE,IAAI,EAAE,OAAO,EAAoB,CAAC,CAAA;AACxF,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAwB;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,EAAoB,CAAC,CAAA;AACxF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAuB;IAC1D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,OAAO,EAAoB,CAAC,CAAA;AACpF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,UAA+C;IAChF,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,UAAU,EAAoB,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAA;QACzD,IAAI,MAAM,CAAC,GAAG,KAAK,eAAe,IAAI,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;YAC/E,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAA;QACtE,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAA;QAC9C,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,KAAK,uBAAuB,EAAE,CAAC;YAC3C,OAAO,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAA;QACzC,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,KAAK,qBAAqB,IAAI,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1E,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAA;QAC1D,CAAC;QACD,IACE,MAAM,CAAC,GAAG,KAAK,eAAe;YAC9B,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;YACjC,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAClC,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAA;QACjF,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,KAAK,sBAAsB,IAAI,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7E,OAAO,EAAE,GAAG,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAA;QAC3D,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,KAAK,iBAAiB,IAAI,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACtE,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAA;QACtD,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAsB;IAChD,MAAM,EACJ,MAAM,EAAE,cAAc,EACtB,QAAQ,EACR,cAAc,GAAG,GAAG,EACpB,KAAK,EACL,MAAM,EACN,KAAK,EAAE,QAAQ,EACf,GAAG,GACJ,GAAG,OAAO,CAAA;IACX,MAAM,KAAK,GAAG,YAAY,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACpF,MAAM,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAA;IACxC,MAAM,wBAAwB,GAAG,EAAE,CAAA;IAEnC,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;IAC7C,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,IAAI,cAAc,GAAG,KAAK,CAAA;IAC1B,IAAI,mBAAmB,GAAG,KAAK,CAAA;IAC/B,IAAI,cAAc,GAAG,KAAK,CAAA;IAC1B,IAAI,aAAa,GAAG,KAAK,CAAA;IACzB,IAAI,UAAU,GAAyB,IAAI,CAAA;IAC3C,IAAI,aAAa,GAIN,IAAI,CAAA;IACf,IAAI,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAA;IAC9B,IAAI,aAAa,GAAG,CAAC,CAAA;IAErB,MAAM,KAAK,GAAG,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,MAAe,EAAE,EAAE;QACnD,IAAI,MAAM;YAAE,OAAM;QAClB,MAAM,GAAG,IAAI,CAAA;QACb,eAAe,CAAC,KAAK,EAAE,CAAA;QACvB,WAAW,EAAE,CAAA;QACb,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,CAAC,CAAA;IAED,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;QAChC,IAAI,cAAc,IAAI,CAAC,aAAa,IAAI,MAAM;YAAE,OAAM;QACtD,cAAc,GAAG,IAAI,CAAA;QAErB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAA;QAC/D,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;QAElD,MAAM,OAAO,GAAG,oBAAoB,CAAC;YACnC,WAAW,EAAE,aAAa,CAAC,WAAW;YACtC,SAAS,EAAE,aAAa,CAAC,SAAS;YAClC,kBAAkB,EAAE,OAAO,CAAC,oBAAoB;YAChD,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAA;QACF,MAAM,IAAI,CAAC,MAAM,EAAE,uBAAuB,CAAC,OAAO,CAAC,CAAC,CAAA;IACtD,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,KAAK,EAAE,OAIxB,EAAE,EAAE;QACH,IAAI,cAAc,GAAG,EAAE,CAAA;QACvB,IAAI,aAAa,GAAG,CAAC,CAAA;QAErB,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,mBAAmB,CAAC;YAClB,MAAM,EAAE,OAAO,CAAC,QAAQ;YACxB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,cAAc;YACd,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;YACxC,cAAc;YACd,MAAM,EAAE,eAAe,CAAC,MAAM;YAC9B,KAAK;SACN,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YACX,cAAc,IAAI,OAAO,CAAC,QAAQ,CAAA;YAClC,aAAa,IAAI,CAAC,CAAA;QACpB,CAAC,CAAC,CAAA;QAEJ,MAAM,QAAQ,GACZ,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;QAElE,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;gBACnC,IAAI,eAAe,CAAC,MAAM,CAAC,OAAO;oBAAE,MAAK;gBACzC,IAAI,OAAO,QAAQ,KAAK,UAAU;oBAAE,MAAM,MAAM,EAAE,CAAA;gBAClD,MAAM,qBAAqB,CAAC;oBAC1B,KAAK;oBACL,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,MAAM,EAAE,cAAc;oBACtB,KAAK,EAAE,aAAa;iBACrB,CAAC,CAAA;gBACF,cAAc,GAAG,EAAE,CAAA;gBACnB,aAAa,GAAG,CAAC,CAAA;gBACjB,MAAM,IAAI,CAAC,MAAM,EAAE,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAA;YACrD,CAAC;YAED,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO;gBAAE,MAAM,cAAc,EAAE,CAAA;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,MAAM,IAAI,CACR,MAAM,EACN,kBAAkB,CAAC;oBACjB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B;oBAC5E,MAAM,EAAE,GAAG;iBACZ,CAAC,CACH,CAAA;gBACD,MAAM,KAAK,CAAC,IAAI,EAAE,0BAA0B,CAAC,CAAA;YAC/C,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,UAAU,GAAG,IAAI,CAAA;QACnB,CAAC;IACH,CAAC,CAAA;IAED,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE;QAC9B,IAAI,MAAM;YAAE,OAAM;QAClB,IAAI,mBAAmB;YAAE,OAAM;QAC/B,mBAAmB,GAAG,IAAI,CAAA;QAC1B,cAAc,GAAG,IAAI,CAAA;QACrB,eAAe,CAAC,KAAK,EAAE,CAAA;QACvB,MAAM,UAAU,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACjC,MAAM,cAAc,EAAE,CAAA;IACxB,CAAC,CAAA;IAED,MAAM,oBAAoB,GAAG,KAAK,EAAE,aAAqB,EAAE,EAAE;QAC3D,IAAI,MAAM;YAAE,OAAM;QAClB,MAAM,UAAU,GAAG,UAAU,CAAC,WAAW,CAA2B,aAAa,CAAC,CAAA;QAClF,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAClC,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO;YAAE,cAAc,GAAG,IAAI,CAAA;QAErD,IAAI,cAAc,IAAI,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;YAC7E,MAAM,IAAI,CACR,MAAM,EACN,kBAAkB,CAAC;gBACjB,OAAO,EAAE,gDAAgD;gBACzD,MAAM,EAAE,GAAG;aACZ,CAAC,CACH,CAAA;YACD,MAAM,KAAK,CAAC,IAAI,EAAE,gDAAgD,CAAC,CAAA;YACnE,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,KAAK,CACxB,IAAI,OAAO,CAAC,UAAU,EAAE;YACtB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,aAAa,EAAE;SAC1C,CAAC,CACH,CAAA;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAA;YACjC,MAAM,OAAO,GACX,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBACvC,QAAQ,CAAC,UAAU;gBACnB,6BAA6B,CAAA;YAC/B,MAAM,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;YAC5E,MAAM,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC1B,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;QACxE,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;QAC7D,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACvE,CAAC;QAED,MAAM,OAAO,GAAG,yBAAyB,CAAC,aAAa,CAAC,CAAA;QACxD,MAAM,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAA;QAEjD,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,KAAK,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAA;YAC3C,OAAM;QACR,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO;YAAE,OAAM;QACtC,IAAI,aAAa,IAAI,cAAc;YAAE,OAAM;QAC3C,aAAa,GAAG,IAAI,CAAA;QACpB,aAAa,GAAG;YACd,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE;YACpC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,MAAgB,CAAC;SAChE,CAAA;QACD,wEAAwE;QACxE,sEAAsE;QACtE,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,cAAc,IAAI,MAAM,IAAI,CAAC,aAAa;gBAAE,OAAM;YACtD,UAAU,GAAG,SAAS,CAAC,aAAa,CAAC,CAAA;QACvC,CAAC,EAAE,CAAC,CAAC,CAAA;IACP,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,CAAC,OAAgB,EAAE,EAAE;QACrC,IAAI,MAAM;YAAE,OAAM;QAClB,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;QAC3B,IAAI,CAAC,GAAG;YAAE,OAAM;QAChB,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;QACjC,IAAI,CAAC,OAAO;YAAE,OAAM;QAEpB,IAAI,OAAO,CAAC,GAAG,KAAK,uBAAuB,EAAE,CAAC;YAC5C,cAAc,GAAG,IAAI,CAAA;YACrB,eAAe,CAAC,KAAK,EAAE,CAAA;QACzB,CAAC;QAED,MAAM,IAAI,GACR,OAAO,CAAC,GAAG,KAAK,eAAe;YAC7B,CAAC,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,aAAa,CAAC;YACnD,CAAC,CAAC,OAAO,CAAC,GAAG,KAAK,uBAAuB;gBACvC,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE;gBACtB,CAAC,CAAC,IAAI,CAAA;QAEZ,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,IAAI,aAAa,IAAI,wBAAwB,EAAE,CAAC;YAC9C,KAAK,IAAI,CACP,MAAM,EACN,kBAAkB,CAAC;gBACjB,OAAO,EAAE,kCAAkC;gBAC3C,MAAM,EAAE,GAAG;aACZ,CAAC,CACH,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACjB,KAAK,KAAK,CAAC,IAAI,EAAE,kCAAkC,CAAC,CAAA;YACpD,OAAM;QACR,CAAC;QAED,aAAa,EAAE,CAAA;QACf,MAAM,GAAG,MAAM;aACZ,IAAI,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,IAAI,MAAM;oBAAE,OAAM;gBAClB,MAAM,IAAI,EAAE,CAAA;YACd,CAAC;oBAAS,CAAC;gBACT,aAAa,EAAE,CAAA;YACjB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACrB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,CACR,MAAM,EACN,kBAAkB,CAAC;oBACjB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB;oBAC3E,MAAM,EAAE,GAAG;iBACZ,CAAC,CACH,CAAA;gBACD,MAAM,KAAK,CAAC,IAAI,EAAE,yBAAyB,CAAC,CAAA;YAC9C,CAAC;QACH,CAAC,CAAC,CAAA;IACN,CAAC,CAAA;IAED,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,MAAM;YAAE,OAAM;QAClB,MAAM,GAAG,IAAI,CAAA;QACb,eAAe,CAAC,KAAK,EAAE,CAAA;QACvB,WAAW,EAAE,CAAA;IACf,CAAC,CAAA;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,EAAE;QACpC,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,SAAS;KACnB,CAAC,CAAA;AACJ,CAAC;AAqBD,SAAS,gBAAgB,CAAC,KAAmB;IAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IACrC,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK;QAAE,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAA;IAClD,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM;QAAE,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAA;IACpD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvB,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,OAQlC;IACC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IAE1F,IAAI,OAAO,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;IAC/C,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;IAElD,MAAM,WAAW,GAAG,CAAC,KAAyB,EAAE,EAAE,CAChD,KAAK,CAAC,oBAAoB,GAAG,KAAK,CAAC,KAAK,GAAG,cAAc,IAAI,MAAM,CAAA;IAErE,IAAI,WAAW,CAAC,OAAO,CAAC;QAAE,OAAM;IAEhC,MAAM,IAAI,CACR,wBAAwB,CAAC;QACvB,SAAS;QACT,kBAAkB,EAAE,CAAC,OAAO,CAAC,KAAK,GAAG,cAAc,GAAG,MAAM,CAAC,CAAC,QAAQ,EAAE;QACxE,kBAAkB,EAAE,OAAO,CAAC,oBAAoB,CAAC,QAAQ,EAAE;QAC3D,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE;KACpC,CAAC,CACH,CAAA;IAED,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,MAAM,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,CAAC,CAAA;QAC7D,OAAO,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAC3C,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;IACpD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,OAKpC;IACC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IACnD,IAAI,MAAM,KAAK,EAAE,IAAI,KAAK,KAAK,CAAC;QAAE,OAAM;IAExC,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;QAC/D,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QACzB,IAAI,OAAO,CAAC,SAAS;YAAE,OAAO,OAAO,CAAA;QACrC,IAAI,OAAO,CAAC,oBAAoB,GAAG,OAAO,CAAC,KAAK,GAAG,MAAM;YAAE,OAAO,OAAO,CAAA;QACzE,SAAS,GAAG,IAAI,CAAA;QAChB,OAAO;YACL,GAAG,OAAO;YACV,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,MAAM;YAC7B,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,KAAK;SAC7B,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;IAClD,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;AACrF,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,KAAgC,EAChC,SAAgD,EAChD,cAAsB,EACtB,MAAmB;IAEnB,cAAc,CAAC,MAAM,CAAC,CAAA;IAEtB,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;QACxB,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACzE,OAAM;IACR,CAAC;IAED,MAAM,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,CAAA;AACrC,CAAC;AAED,SAAS,SAAS,CAChB,MAAc,EACd,QAIC;IAED,IAAI,MAAM,CAAC,gBAAgB,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,CAAC,KAA2B,EAAE,EAAE;YAChD,MAAM,IAAI,GAAI,KAAsB,CAAC,IAAI,CAAA;YACzC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACxB,CAAC,CAAA;QACD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAC7C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QAChD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QAChD,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;YAClD,MAAM,CAAC,mBAAmB,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;YACrD,MAAM,CAAC,mBAAmB,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QACvD,CAAC,CAAA;IACH,CAAC;IAED,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,CAAC,IAAa,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC3D,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAC/B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QAClC,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;YAClC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;YACrC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QACvC,CAAC,CAAA;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;AACzD,CAAC;AAED,KAAK,UAAU,IAAI,CAAC,MAAc,EAAE,IAAY;IAC9C,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;AAC1C,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,KAAK,YAAY,WAAW;QAAE,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACxE,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,KAAK,CAAC,EAAU,EAAE,MAAmB;IAC5C,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAC5C,OAAO,EAAE,CAAA;QACX,CAAC,EAAE,EAAE,CAAC,CAAA;QACN,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,CAAC,OAAO,CAAC,CAAA;YACrB,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAA;QAC/C,CAAC,CAAA;QACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,MAAmB;IACtC,OAAO,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QACtC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAA;YAC7C,OAAM;QACR,CAAC;QACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;YACpF,IAAI,EAAE,IAAI;SACX,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,MAAmB;IACzC,IAAI,MAAM,CAAC,OAAO;QAAE,MAAM,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAC7D,MAAM,CAAC,GAAG,KAAgC,CAAA;IAC1C,OAAO,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAA;AAC7E,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAC7D,MAAM,CAAC,GAAG,KAAgC,CAAA;IAC1C,OAAO,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,kBAAkB,KAAK,QAAQ,CAAA;AACpF,CAAC"}
@@ -5,4 +5,5 @@ export * as Receipt from './Receipt.js';
5
5
  export * as Sse from './Sse.js';
6
6
  export * as Types from './Types.js';
7
7
  export * as Voucher from './Voucher.js';
8
+ export * as Ws from './Ws.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -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"}
@@ -5,4 +5,5 @@ export * as Receipt from './Receipt.js';
5
5
  export * as Sse from './Sse.js';
6
6
  export * as Types from './Types.js';
7
7
  export * as Voucher from './Voucher.js';
8
+ export * as Ws from './Ws.js';
8
9
  //# sourceMappingURL=index.js.map
@@ -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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mppx",
3
3
  "type": "module",
4
- "version": "0.5.7",
4
+ "version": "0.5.8",
5
5
  "main": "./dist/index.js",
6
6
  "license": "MIT",
7
7
  "files": [
@@ -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 parameters (realm|method|intent|request|expires|digest),
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 parameters, cryptographically binding the ID to its contents.
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
- /** @internal Computes HMAC-SHA256 challenge ID from parameters. */
612
- function computeId(challenge: Omit<Challenge, 'id'>, options: { secretKey: string }): string {
613
- // Each field occupies a fixed positional slot joined by '|'. Optional fields
614
- // use an empty string when absent so the slot count is stable — this avoids
615
- // ambiguity between e.g. (expires set, no digest) vs (no expires, digest set)
616
- // and means adding a new optional field changes all HMACs exactly once.
617
- const input = [
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/Method.ts CHANGED
@@ -67,6 +67,58 @@ export type Client<
67
67
  }
68
68
  export type AnyClient = Client<any, any>
69
69
 
70
+ /** Transport-captured request metadata used as the authoritative request snapshot. */
71
+ export type CapturedRequest = {
72
+ readonly headers: Headers
73
+ readonly method: string
74
+ readonly url: URL
75
+ }
76
+
77
+ /** Verified challenge + credential pair, bound to the captured request snapshot. */
78
+ export type VerifiedChallengeEnvelope<
79
+ request extends Record<string, unknown> = Record<string, unknown>,
80
+ payload = unknown,
81
+ intent extends string = string,
82
+ MethodName extends string = string,
83
+ > = {
84
+ readonly capturedRequest: CapturedRequest
85
+ readonly challenge: Challenge.Challenge<request, intent, MethodName>
86
+ readonly credential: Credential.Credential<
87
+ payload,
88
+ Challenge.Challenge<request, intent, MethodName>
89
+ >
90
+ }
91
+
92
+ /** Request hook parameters for a single method. */
93
+ export type RequestContext<method extends Method> = {
94
+ capturedRequest?: CapturedRequest
95
+ credential?: Credential.Credential | null
96
+ request: z.input<method['schema']['request']>
97
+ }
98
+
99
+ /** Verification hook parameters for a single method. */
100
+ export type VerifyContext<method extends Method> = {
101
+ credential: Credential.Credential<
102
+ z.output<method['schema']['credential']['payload']>,
103
+ Challenge.Challenge<z.output<method['schema']['request']>, method['intent'], method['name']>
104
+ >
105
+ envelope?:
106
+ | VerifiedChallengeEnvelope<
107
+ z.output<method['schema']['request']>,
108
+ z.output<method['schema']['credential']['payload']>,
109
+ method['intent'],
110
+ method['name']
111
+ >
112
+ | undefined
113
+ request: z.input<method['schema']['request']>
114
+ }
115
+
116
+ /** Response hook parameters for a single method. */
117
+ export type RespondContext<method extends Method> = VerifyContext<method> & {
118
+ input: globalThis.Request
119
+ receipt: Receipt.Receipt
120
+ }
121
+
70
122
  /**
71
123
  * A server-side configured method with verification logic.
72
124
  */
@@ -96,19 +148,14 @@ export type CreateCredentialFn<method extends Method, context = unknown> = (
96
148
  ) => Promise<string>
97
149
 
98
150
  /** Request transform function for a single method. */
99
- export type RequestFn<method extends Method> = (options: {
100
- credential?: Credential.Credential | null | undefined
101
- request: z.input<method['schema']['request']>
102
- }) => MaybePromise<z.input<method['schema']['request']>>
151
+ export type RequestFn<method extends Method> = (
152
+ options: RequestContext<method>,
153
+ ) => MaybePromise<z.input<method['schema']['request']>>
103
154
 
104
155
  /** Verification function for a single method. */
105
- export type VerifyFn<method extends Method> = (parameters: {
106
- credential: Credential.Credential<
107
- z.output<method['schema']['credential']['payload']>,
108
- Challenge.Challenge<z.output<method['schema']['request']>, method['intent'], method['name']>
109
- >
110
- request: z.input<method['schema']['request']>
111
- }) => Promise<Receipt.Receipt>
156
+ export type VerifyFn<method extends Method> = (
157
+ parameters: VerifyContext<method>,
158
+ ) => Promise<Receipt.Receipt>
112
159
 
113
160
  /**
114
161
  * Optional respond function for a server-side method.
@@ -123,15 +170,9 @@ export type VerifyFn<method extends Method> = (parameters: {
123
170
  * **HTTP-only.** The `input` parameter is a `Request` object; MCP transports
124
171
  * do not invoke this hook.
125
172
  */
126
- export type RespondFn<method extends Method> = (parameters: {
127
- credential: Credential.Credential<
128
- z.output<method['schema']['credential']['payload']>,
129
- Challenge.Challenge<z.output<method['schema']['request']>, method['intent'], method['name']>
130
- >
131
- input: globalThis.Request
132
- receipt: Receipt.Receipt
133
- request: z.input<method['schema']['request']>
134
- }) => MaybePromise<globalThis.Response | undefined>
173
+ export type RespondFn<method extends Method> = (
174
+ parameters: RespondContext<method>,
175
+ ) => MaybePromise<globalThis.Response | undefined>
135
176
 
136
177
  /** Partial request type for defaults. */
137
178
  export type RequestDefaults<method extends Method> = ExactPartial<