mppx 0.5.12 → 0.5.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/server/internal/html/config.d.ts.map +1 -1
  3. package/dist/server/internal/html/config.js +8 -1
  4. package/dist/server/internal/html/config.js.map +1 -1
  5. package/dist/tempo/Methods.d.ts +8 -0
  6. package/dist/tempo/Methods.d.ts.map +1 -1
  7. package/dist/tempo/Methods.js +6 -2
  8. package/dist/tempo/Methods.js.map +1 -1
  9. package/dist/tempo/client/Charge.d.ts +11 -1
  10. package/dist/tempo/client/Charge.d.ts.map +1 -1
  11. package/dist/tempo/client/Charge.js +14 -2
  12. package/dist/tempo/client/Charge.js.map +1 -1
  13. package/dist/tempo/client/Methods.d.ts +6 -0
  14. package/dist/tempo/client/Methods.d.ts.map +1 -1
  15. package/dist/tempo/internal/fee-payer.d.ts +8 -0
  16. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  17. package/dist/tempo/internal/fee-payer.js +31 -4
  18. package/dist/tempo/internal/fee-payer.js.map +1 -1
  19. package/dist/tempo/server/Charge.d.ts +17 -0
  20. package/dist/tempo/server/Charge.d.ts.map +1 -1
  21. package/dist/tempo/server/Charge.js +13 -1
  22. package/dist/tempo/server/Charge.js.map +1 -1
  23. package/dist/tempo/server/Methods.d.ts +6 -0
  24. package/dist/tempo/server/Methods.d.ts.map +1 -1
  25. package/dist/tempo/server/Session.d.ts +4 -0
  26. package/dist/tempo/server/Session.d.ts.map +1 -1
  27. package/dist/tempo/server/Session.js +36 -28
  28. package/dist/tempo/server/Session.js.map +1 -1
  29. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  30. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  31. package/dist/tempo/server/internal/html.gen.js +1 -1
  32. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  33. package/dist/tempo/session/Chain.d.ts +5 -0
  34. package/dist/tempo/session/Chain.d.ts.map +1 -1
  35. package/dist/tempo/session/Chain.js +202 -63
  36. package/dist/tempo/session/Chain.js.map +1 -1
  37. package/dist/tempo/session/ChannelStore.d.ts +1 -0
  38. package/dist/tempo/session/ChannelStore.d.ts.map +1 -1
  39. package/dist/tempo/session/ChannelStore.js +38 -15
  40. package/dist/tempo/session/ChannelStore.js.map +1 -1
  41. package/package.json +2 -2
  42. package/src/server/Transport.test.ts +20 -0
  43. package/src/server/internal/html/config.ts +9 -1
  44. package/src/tempo/Methods.test.ts +25 -0
  45. package/src/tempo/Methods.ts +30 -22
  46. package/src/tempo/client/Charge.ts +20 -6
  47. package/src/tempo/internal/fee-payer.test.ts +122 -12
  48. package/src/tempo/internal/fee-payer.ts +49 -4
  49. package/src/tempo/server/Charge.test.ts +259 -1
  50. package/src/tempo/server/Charge.ts +31 -0
  51. package/src/tempo/server/Session.test.ts +130 -1
  52. package/src/tempo/server/Session.ts +41 -35
  53. package/src/tempo/server/internal/html/main.ts +2 -2
  54. package/src/tempo/server/internal/html.gen.ts +1 -1
  55. package/src/tempo/session/Chain.test.ts +225 -2
  56. package/src/tempo/session/Chain.ts +250 -65
  57. package/src/tempo/session/ChannelStore.test.ts +23 -0
  58. package/src/tempo/session/ChannelStore.ts +46 -13
@@ -37,6 +37,7 @@ import * as Store from '../../Store.js'
37
37
  import * as Client from '../../viem/Client.js'
38
38
  import * as Account from '../internal/account.js'
39
39
  import * as defaults from '../internal/defaults.js'
40
+ import * as FeePayer from '../internal/fee-payer.js'
40
41
  import type * as types from '../internal/types.js'
41
42
  import * as Methods from '../Methods.js'
42
43
  import {
@@ -92,6 +93,7 @@ export function session<const parameters extends session.Parameters>(
92
93
  channelStateTtl = 5_000,
93
94
  currency = defaults.resolveCurrency(parameters),
94
95
  decimals = defaults.decimals,
96
+ feePayerPolicy,
95
97
  store: rawStore = Store.memory(),
96
98
  suggestedDeposit,
97
99
  unitType,
@@ -203,9 +205,10 @@ export function session<const parameters extends session.Parameters>(
203
205
  payload,
204
206
  methodDetails,
205
207
  resolvedFeePayer,
208
+ feePayerPolicy,
206
209
  waitForConfirmation,
207
210
  )
208
- lastOnChainVerified.set(payload.channelId, Date.now())
211
+ lastOnChainVerified.set(sessionReceipt.channelId, Date.now())
209
212
  break
210
213
 
211
214
  case 'topUp':
@@ -216,8 +219,9 @@ export function session<const parameters extends session.Parameters>(
216
219
  payload,
217
220
  methodDetails,
218
221
  resolvedFeePayer,
222
+ feePayerPolicy,
219
223
  )
220
- lastOnChainVerified.set(payload.channelId, Date.now())
224
+ lastOnChainVerified.set(sessionReceipt.channelId, Date.now())
221
225
  break
222
226
 
223
227
  case 'voucher':
@@ -293,9 +297,13 @@ export declare namespace session {
293
297
  'feePayer' | 'recipient'
294
298
  >
295
299
 
300
+ type FeePayerPolicy = Partial<FeePayer.Policy>
301
+
296
302
  type Parameters = {
297
303
  /** TTL in milliseconds for cached on-chain channel state. After this duration, the server re-queries on-chain state during voucher handling to detect forced close requests. @default 5_000 */
298
304
  channelStateTtl?: number | undefined
305
+ /** Override the fee-sponsor policy used for sponsored open/topUp transactions. */
306
+ feePayerPolicy?: FeePayerPolicy | undefined
299
307
  /** Minimum voucher delta to accept (numeric string, default: "0"). */
300
308
  minVoucherDelta?: string | undefined
301
309
  /**
@@ -561,13 +569,11 @@ async function handleOpen(
561
569
  payload: SessionCredentialPayload & { action: 'open' },
562
570
  methodDetails: SessionMethodDetails,
563
571
  feePayer: viem_Account | undefined,
572
+ feePayerPolicy: session.FeePayerPolicy | undefined,
564
573
  waitForConfirmation: boolean,
565
574
  ): Promise<SessionReceipt> {
566
- const voucher = parseVoucherFromPayload(
567
- payload.channelId,
568
- payload.cumulativeAmount,
569
- payload.signature,
570
- )
575
+ const channelId = ChannelStore.normalizeChannelId(payload.channelId)
576
+ const voucher = parseVoucherFromPayload(channelId, payload.cumulativeAmount, payload.signature)
571
577
 
572
578
  const recipient = challenge.request.recipient as Address
573
579
  const currency = challenge.request.currency as Address
@@ -577,9 +583,11 @@ async function handleOpen(
577
583
  client,
578
584
  serializedTransaction: payload.transaction,
579
585
  escrowContract: methodDetails.escrowContract,
580
- channelId: payload.channelId,
586
+ channelId,
581
587
  recipient,
582
588
  currency,
589
+ challengeExpires: challenge.expires,
590
+ feePayerPolicy,
583
591
  feePayer,
584
592
  waitForConfirmation,
585
593
  })
@@ -612,7 +620,7 @@ async function handleOpen(
612
620
  throw new InvalidSignatureError({ reason: 'invalid voucher signature' })
613
621
  }
614
622
 
615
- const updated = await store.updateChannel(payload.channelId, (existing) => {
623
+ const updated = await store.updateChannel(channelId, (existing) => {
616
624
  if (existing) {
617
625
  if (voucher.cumulativeAmount <= existing.settledOnChain) {
618
626
  throw new VerificationFailedError({
@@ -644,7 +652,7 @@ async function handleOpen(
644
652
  }
645
653
  }
646
654
  return {
647
- channelId: payload.channelId,
655
+ channelId,
648
656
  chainId: methodDetails.chainId,
649
657
  escrowContract: methodDetails.escrowContract,
650
658
  closeRequestedAt: onChain.closeRequestedAt,
@@ -667,7 +675,7 @@ async function handleOpen(
667
675
 
668
676
  return createSessionReceipt({
669
677
  challengeId: challenge.id,
670
- channelId: payload.channelId,
678
+ channelId: updated.channelId,
671
679
  acceptedCumulative: updated.highestVoucherAmount,
672
680
  spent: updated.spent,
673
681
  units: updated.units,
@@ -689,8 +697,10 @@ async function handleTopUp(
689
697
  payload: SessionCredentialPayload & { action: 'topUp' },
690
698
  methodDetails: SessionMethodDetails,
691
699
  feePayer: viem_Account | undefined,
700
+ feePayerPolicy: session.FeePayerPolicy | undefined,
692
701
  ): Promise<SessionReceipt> {
693
- const channel = await store.getChannel(payload.channelId)
702
+ const channelId = ChannelStore.normalizeChannelId(payload.channelId)
703
+ const channel = await store.getChannel(channelId)
694
704
  if (!channel) {
695
705
  throw new ChannelNotFoundError({ reason: 'channel not found' })
696
706
  }
@@ -701,21 +711,23 @@ async function handleTopUp(
701
711
  client,
702
712
  serializedTransaction: payload.transaction,
703
713
  escrowContract: methodDetails.escrowContract,
704
- channelId: payload.channelId,
714
+ channelId,
705
715
  currency: challenge.request.currency as Address,
706
716
  declaredDeposit,
707
717
  previousDeposit: channel.deposit,
718
+ challengeExpires: challenge.expires,
719
+ feePayerPolicy,
708
720
  feePayer,
709
721
  })
710
722
 
711
- const updated = await store.updateChannel(payload.channelId, (current) => {
723
+ const updated = await store.updateChannel(channelId, (current) => {
712
724
  if (!current) throw new ChannelNotFoundError({ reason: 'channel not found' })
713
725
  return { ...current, deposit: onChainDeposit }
714
726
  })
715
727
 
716
728
  return createSessionReceipt({
717
729
  challengeId: challenge.id,
718
- channelId: payload.channelId,
730
+ channelId: updated?.channelId ?? channel.channelId,
719
731
  acceptedCumulative: updated?.highestVoucherAmount ?? channel.highestVoucherAmount,
720
732
  spent: updated?.spent ?? channel.spent,
721
733
  units: updated?.units ?? channel.units,
@@ -735,7 +747,8 @@ async function handleVoucher(
735
747
  channelStateTtl: number,
736
748
  lastOnChainVerified: Map<Hex, number>,
737
749
  ): Promise<SessionReceipt> {
738
- const channel = await store.getChannel(payload.channelId)
750
+ const channelId = ChannelStore.normalizeChannelId(payload.channelId)
751
+ const channel = await store.getChannel(channelId)
739
752
  if (!channel) {
740
753
  throw new ChannelNotFoundError({ reason: 'channel not found' })
741
754
  }
@@ -743,11 +756,7 @@ async function handleVoucher(
743
756
  throw new ChannelClosedError({ reason: 'channel is finalized' })
744
757
  }
745
758
 
746
- const voucher = parseVoucherFromPayload(
747
- payload.channelId,
748
- payload.cumulativeAmount,
749
- payload.signature,
750
- )
759
+ const voucher = parseVoucherFromPayload(channelId, payload.cumulativeAmount, payload.signature)
751
760
 
752
761
  // Use locally-stored channel state as a trusted cache instead of
753
762
  // reading on-chain for every voucher. The on-chain state is verified
@@ -759,7 +768,7 @@ async function handleVoucher(
759
768
  // To guard against the payer initiating a forced close while vouchers
760
769
  // are still being accepted, re-query on-chain state when the cache
761
770
  // exceeds the configured staleness TTL (default: 5s).
762
- const lastVerified = lastOnChainVerified.get(payload.channelId) ?? 0
771
+ const lastVerified = lastOnChainVerified.get(channelId) ?? 0
763
772
  const isStale = Date.now() - lastVerified > channelStateTtl
764
773
 
765
774
  const onChain = await (async () => {
@@ -767,13 +776,13 @@ async function handleVoucher(
767
776
  const onChainChannel = await getOnChainChannel(
768
777
  client,
769
778
  methodDetails.escrowContract,
770
- payload.channelId,
779
+ channelId,
771
780
  )
772
- lastOnChainVerified.set(payload.channelId, Date.now())
781
+ lastOnChainVerified.set(channelId, Date.now())
773
782
  // Persist closeRequestedAt so the cached path detects force-close
774
783
  // between re-queries.
775
784
  if (onChainChannel.closeRequestedAt !== 0n) {
776
- await store.updateChannel(payload.channelId, (current) =>
785
+ await store.updateChannel(channelId, (current) =>
777
786
  current ? { ...current, closeRequestedAt: onChainChannel.closeRequestedAt } : current,
778
787
  )
779
788
  }
@@ -796,7 +805,7 @@ async function handleVoucher(
796
805
  minVoucherDelta,
797
806
  challenge,
798
807
  channel,
799
- channelId: payload.channelId,
808
+ channelId,
800
809
  voucher,
801
810
  onChain,
802
811
  methodDetails,
@@ -815,7 +824,8 @@ async function handleClose(
815
824
  account?: viem_Account,
816
825
  feePayer?: viem_Account,
817
826
  ): Promise<SessionReceipt> {
818
- const channel = await store.getChannel(payload.channelId)
827
+ const channelId = ChannelStore.normalizeChannelId(payload.channelId)
828
+ const channel = await store.getChannel(channelId)
819
829
  if (!channel) {
820
830
  throw new ChannelNotFoundError({ reason: 'channel not found' })
821
831
  }
@@ -823,13 +833,9 @@ async function handleClose(
823
833
  throw new ChannelClosedError({ reason: 'channel is already finalized' })
824
834
  }
825
835
 
826
- const voucher = parseVoucherFromPayload(
827
- payload.channelId,
828
- payload.cumulativeAmount,
829
- payload.signature,
830
- )
836
+ const voucher = parseVoucherFromPayload(channelId, payload.cumulativeAmount, payload.signature)
831
837
 
832
- const onChain = await getOnChainChannel(client, methodDetails.escrowContract, payload.channelId)
838
+ const onChain = await getOnChainChannel(client, methodDetails.escrowContract, channelId)
833
839
 
834
840
  if (onChain.finalized) {
835
841
  throw new ChannelClosedError({ reason: 'channel is finalized on-chain' })
@@ -867,7 +873,7 @@ async function handleClose(
867
873
  ...(feePayer && account ? { feePayer, account } : { account }),
868
874
  })
869
875
 
870
- const updated = await store.updateChannel(payload.channelId, (current) => {
876
+ const updated = await store.updateChannel(channelId, (current) => {
871
877
  if (!current) return null
872
878
  const updateVoucher = voucher.cumulativeAmount > current.highestVoucherAmount
873
879
  return {
@@ -883,7 +889,7 @@ async function handleClose(
883
889
 
884
890
  return createSessionReceipt({
885
891
  challengeId: challenge.id,
886
- channelId: payload.channelId,
892
+ channelId: updated?.channelId ?? channel.channelId,
887
893
  acceptedCumulative: voucher.cumulativeAmount,
888
894
  spent: updated?.spent ?? channel.spent,
889
895
  units: updated?.units ?? channel.units,
@@ -73,8 +73,8 @@ const provider = Provider.create({
73
73
  })
74
74
 
75
75
  const button = document.createElement('button')
76
- button.innerHTML =
77
- 'Continue with <svg aria-label="Tempo" viewBox="0 0 107 25" role="img"><path d="M8.10464 23.7163H1.82475L7.64513 5.79356H0.201172L1.82475 0.540352H22.5637L20.9401 5.79356H13.8944L8.10464 23.7163Z"></path><path d="M31.474 23.7163H16.5861L24.0607 0.540352H38.8873L37.4782 4.95923H28.8701L27.3078 9.93433H35.6402L34.231 14.2914H25.8681L24.3057 19.2974H32.8525L31.474 23.7163Z"></path><path d="M38.2124 23.7163H33.2192L40.7244 0.540352H49.0567L48.781 13.0245L56.8989 0.540352H66.0277L58.5531 23.7163H52.3039L57.3584 7.86395L46.9736 23.7163H43.267L43.4201 7.80214L38.2124 23.7163Z"></path><path d="M73.057 4.83563L70.6369 12.3137H71.3108C72.8425 12.3137 74.1189 11.9532 75.14 11.2322C76.1612 10.4906 76.8249 9.43991 77.1312 8.08025C77.3967 6.90601 77.2538 6.07167 76.7023 5.57725C76.1509 5.08284 75.2319 4.83563 73.9453 4.83563H73.057ZM66.9915 23.7163H60.7116L68.1862 0.540352H75.814C77.5703 0.540352 79.0816 0.828764 80.3478 1.40559C81.6344 1.96181 82.5738 2.76524 83.166 3.81588C83.7787 4.84592 83.9829 6.05107 83.7787 7.43133C83.5132 9.2442 82.8189 10.8408 81.6956 12.221C80.5724 13.6013 79.1122 14.6725 77.315 15.4347C75.5383 16.1764 73.5471 16.5472 71.3415 16.5472H69.289L66.9915 23.7163Z"></path><path d="M98.747 22.233C96.664 23.4691 94.4481 24.0871 92.0996 24.0871H92.0383C89.9552 24.0871 88.1989 23.6236 86.7693 22.6965C85.3602 21.7489 84.3493 20.4717 83.7366 18.8648C83.1443 17.2579 83.0014 15.4966 83.3077 13.5807C83.6957 11.1704 84.5841 8.94549 85.9728 6.90601C87.3616 4.86653 89.0975 3.23906 91.1805 2.02361C93.2636 0.808164 95.4897 0.200439 97.8587 0.200439H97.9199C100.085 0.200439 101.872 0.663958 103.281 1.591C104.71 2.51803 105.701 3.78498 106.252 5.39185C106.824 6.97811 106.947 8.76008 106.62 10.7378C106.232 13.0657 105.343 15.2596 103.955 17.3197C102.566 19.3592 100.83 20.997 98.747 22.233ZM90.0777 18.2468C90.6292 19.2974 91.589 19.8227 92.9573 19.8227H93.0186C94.1418 19.8227 95.1833 19.4004 96.1432 18.5558C97.1235 17.6905 97.9506 16.5369 98.6245 15.0948C99.3189 13.6528 99.8294 12.0459 100.156 10.2742C100.463 8.54377 100.34 7.15322 99.7886 6.10257C99.2372 5.03133 98.2875 4.49571 96.9397 4.49571H96.8784C95.8369 4.49571 94.826 4.92833 93.8457 5.79356C92.8858 6.6588 92.0485 7.82274 91.3337 9.2854C90.6189 10.7481 90.0982 12.3343 89.7714 14.0442C89.4446 15.7747 89.5468 17.1755 90.0777 18.2468Z"></path></svg>'
76
+ const buttonLabel = c.text.pay === 'Pay' ? 'Continue with' : c.text.pay
77
+ button.innerHTML = `${buttonLabel} <svg aria-label="Tempo" viewBox="0 0 107 25" role="img"><path d="M8.10464 23.7163H1.82475L7.64513 5.79356H0.201172L1.82475 0.540352H22.5637L20.9401 5.79356H13.8944L8.10464 23.7163Z"></path><path d="M31.474 23.7163H16.5861L24.0607 0.540352H38.8873L37.4782 4.95923H28.8701L27.3078 9.93433H35.6402L34.231 14.2914H25.8681L24.3057 19.2974H32.8525L31.474 23.7163Z"></path><path d="M38.2124 23.7163H33.2192L40.7244 0.540352H49.0567L48.781 13.0245L56.8989 0.540352H66.0277L58.5531 23.7163H52.3039L57.3584 7.86395L46.9736 23.7163H43.267L43.4201 7.80214L38.2124 23.7163Z"></path><path d="M73.057 4.83563L70.6369 12.3137H71.3108C72.8425 12.3137 74.1189 11.9532 75.14 11.2322C76.1612 10.4906 76.8249 9.43991 77.1312 8.08025C77.3967 6.90601 77.2538 6.07167 76.7023 5.57725C76.1509 5.08284 75.2319 4.83563 73.9453 4.83563H73.057ZM66.9915 23.7163H60.7116L68.1862 0.540352H75.814C77.5703 0.540352 79.0816 0.828764 80.3478 1.40559C81.6344 1.96181 82.5738 2.76524 83.166 3.81588C83.7787 4.84592 83.9829 6.05107 83.7787 7.43133C83.5132 9.2442 82.8189 10.8408 81.6956 12.221C80.5724 13.6013 79.1122 14.6725 77.315 15.4347C75.5383 16.1764 73.5471 16.5472 71.3415 16.5472H69.289L66.9915 23.7163Z"></path><path d="M98.747 22.233C96.664 23.4691 94.4481 24.0871 92.0996 24.0871H92.0383C89.9552 24.0871 88.1989 23.6236 86.7693 22.6965C85.3602 21.7489 84.3493 20.4717 83.7366 18.8648C83.1443 17.2579 83.0014 15.4966 83.3077 13.5807C83.6957 11.1704 84.5841 8.94549 85.9728 6.90601C87.3616 4.86653 89.0975 3.23906 91.1805 2.02361C93.2636 0.808164 95.4897 0.200439 97.8587 0.200439H97.9199C100.085 0.200439 101.872 0.663958 103.281 1.591C104.71 2.51803 105.701 3.78498 106.252 5.39185C106.824 6.97811 106.947 8.76008 106.62 10.7378C106.232 13.0657 105.343 15.2596 103.955 17.3197C102.566 19.3592 100.83 20.997 98.747 22.233ZM90.0777 18.2468C90.6292 19.2974 91.589 19.8227 92.9573 19.8227H93.0186C94.1418 19.8227 95.1833 19.4004 96.1432 18.5558C97.1235 17.6905 97.9506 16.5369 98.6245 15.0948C99.3189 13.6528 99.8294 12.0459 100.156 10.2742C100.463 8.54377 100.34 7.15322 99.7886 6.10257C99.2372 5.03133 98.2875 4.49571 96.9397 4.49571H96.8784C95.8369 4.49571 94.826 4.92833 93.8457 5.79356C92.8858 6.6588 92.0485 7.82274 91.3337 9.2854C90.6189 10.7481 90.0982 12.3343 89.7714 14.0442C89.4446 15.7747 89.5468 17.1755 90.0777 18.2468Z"></path></svg>`
78
78
  button.onclick = async () => {
79
79
  try {
80
80
  c.error()