mppx 0.6.26 → 0.6.28

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 (78) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/Store.d.ts +32 -9
  3. package/dist/Store.d.ts.map +1 -1
  4. package/dist/Store.js +42 -10
  5. package/dist/Store.js.map +1 -1
  6. package/dist/cli/cli.js +1 -1
  7. package/dist/cli/cli.js.map +1 -1
  8. package/dist/cli/utils.js +2 -2
  9. package/dist/cli/utils.js.map +1 -1
  10. package/dist/proxy/internal/Headers.d.ts +13 -1
  11. package/dist/proxy/internal/Headers.d.ts.map +1 -1
  12. package/dist/proxy/internal/Headers.js +14 -1
  13. package/dist/proxy/internal/Headers.js.map +1 -1
  14. package/dist/stripe/server/Charge.d.ts +31 -1
  15. package/dist/stripe/server/Charge.d.ts.map +1 -1
  16. package/dist/stripe/server/Charge.js +88 -11
  17. package/dist/stripe/server/Charge.js.map +1 -1
  18. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  19. package/dist/stripe/server/internal/html.gen.js +1 -1
  20. package/dist/tempo/client/ChannelOps.d.ts.map +1 -1
  21. package/dist/tempo/client/ChannelOps.js +7 -2
  22. package/dist/tempo/client/ChannelOps.js.map +1 -1
  23. package/dist/tempo/client/Charge.d.ts.map +1 -1
  24. package/dist/tempo/client/Charge.js +6 -4
  25. package/dist/tempo/client/Charge.js.map +1 -1
  26. package/dist/tempo/client/Session.js +1 -1
  27. package/dist/tempo/client/Session.js.map +1 -1
  28. package/dist/tempo/client/Subscription.js +1 -1
  29. package/dist/tempo/client/Subscription.js.map +1 -1
  30. package/dist/tempo/server/Charge.d.ts +6 -0
  31. package/dist/tempo/server/Charge.d.ts.map +1 -1
  32. package/dist/tempo/server/Charge.js +8 -3
  33. package/dist/tempo/server/Charge.js.map +1 -1
  34. package/dist/tempo/server/Session.d.ts +6 -0
  35. package/dist/tempo/server/Session.d.ts.map +1 -1
  36. package/dist/tempo/server/Session.js +2 -2
  37. package/dist/tempo/server/Session.js.map +1 -1
  38. package/dist/tempo/server/Subscription.d.ts +6 -0
  39. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  40. package/dist/tempo/server/Subscription.js +2 -2
  41. package/dist/tempo/server/Subscription.js.map +1 -1
  42. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  43. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  44. package/dist/tempo/server/internal/html.gen.js +1 -1
  45. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  46. package/dist/tempo/session/Chain.d.ts.map +1 -1
  47. package/dist/tempo/session/Chain.js +6 -1
  48. package/dist/tempo/session/Chain.js.map +1 -1
  49. package/package.json +3 -3
  50. package/src/Store.test-d.ts +58 -0
  51. package/src/Store.test.ts +77 -0
  52. package/src/Store.ts +155 -74
  53. package/src/cli/cli.ts +1 -1
  54. package/src/cli/utils.test.ts +1 -1
  55. package/src/cli/utils.ts +2 -2
  56. package/src/proxy/internal/Headers.test.ts +18 -0
  57. package/src/proxy/internal/Headers.ts +14 -1
  58. package/src/stripe/server/Charge.test.ts +215 -1
  59. package/src/stripe/server/Charge.ts +150 -20
  60. package/src/stripe/server/internal/html.gen.ts +1 -1
  61. package/src/tempo/client/ChannelOps.ts +6 -2
  62. package/src/tempo/client/Charge.ts +5 -4
  63. package/src/tempo/client/Session.ts +1 -1
  64. package/src/tempo/client/Subscription.ts +1 -1
  65. package/src/tempo/server/Charge.test.ts +22 -1
  66. package/src/tempo/server/Charge.ts +17 -3
  67. package/src/tempo/server/Session.ts +10 -2
  68. package/src/tempo/server/Subscription.test.ts +1 -1
  69. package/src/tempo/server/Subscription.ts +8 -2
  70. package/src/tempo/server/internal/html/main.ts +1 -1
  71. package/src/tempo/server/internal/html/package.json +1 -1
  72. package/src/tempo/server/internal/html.gen.ts +1 -1
  73. package/src/tempo/session/Chain.test.ts +16 -8
  74. package/src/tempo/session/Chain.ts +6 -1
  75. package/src/tempo/session/ChannelStore.test.ts +21 -0
  76. package/src/tempo/subscription/Store.test.ts +55 -0
  77. package/src/viem/Account.test.ts +1 -1
  78. package/src/viem/Client.test.ts +1 -1
@@ -498,10 +498,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
498
498
  { to: currency, data: approveData },
499
499
  { to: escrowContract, data: openData },
500
500
  ],
501
- feePayer: true,
502
501
  feeToken: currency,
502
+ nonceKey: 'expiring',
503
+ validBefore: Math.floor(Date.now() / 1_000) + 25,
503
504
  } as never)
504
- prepared.gas = prepared.gas! + 5_000n
505
+ prepared.gas = (prepared.gas ?? 0n) + 5_000n
506
+ ;(prepared as Record<string, unknown>).feePayer = true
505
507
  const serializedTransaction = await signTransaction(client, prepared as never)
506
508
 
507
509
  await broadcastOpenTransaction({
@@ -561,10 +563,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
561
563
  { to: escrowContract, data: openData },
562
564
  { to: escrowContract, data: smuggledOpenData },
563
565
  ],
564
- feePayer: true,
565
566
  feeToken: currency,
567
+ nonceKey: 'expiring',
568
+ validBefore: Math.floor(Date.now() / 1_000) + 25,
566
569
  } as never)
567
- prepared.gas = prepared.gas! + 5_000n
570
+ prepared.gas = (prepared.gas ?? 0n) + 5_000n
571
+ ;(prepared as Record<string, unknown>).feePayer = true
568
572
 
569
573
  const serializedTransaction = await signTransaction(client, prepared as never)
570
574
 
@@ -1006,10 +1010,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
1006
1010
  { to: currency, data: approveData },
1007
1011
  { to: escrowContract, data: topUpData },
1008
1012
  ],
1009
- feePayer: true,
1010
1013
  feeToken: currency,
1014
+ nonceKey: 'expiring',
1015
+ validBefore: Math.floor(Date.now() / 1_000) + 25,
1011
1016
  } as never)
1012
- prepared.gas = prepared.gas! + 5_000n
1017
+ prepared.gas = (prepared.gas ?? 0n) + 5_000n
1018
+ ;(prepared as Record<string, unknown>).feePayer = true
1013
1019
  const serializedTransaction = await signTransaction(client, prepared as never)
1014
1020
 
1015
1021
  await broadcastTopUpTransaction({
@@ -1069,10 +1075,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
1069
1075
  { to: escrowContract, data: topUpData },
1070
1076
  { to: escrowContract, data: smuggledTopUpData },
1071
1077
  ],
1072
- feePayer: true,
1073
1078
  feeToken: currency,
1079
+ nonceKey: 'expiring',
1080
+ validBefore: Math.floor(Date.now() / 1_000) + 25,
1074
1081
  } as never)
1075
- prepared.gas = prepared.gas! + 5_000n
1082
+ prepared.gas = (prepared.gas ?? 0n) + 5_000n
1083
+ ;(prepared as Record<string, unknown>).feePayer = true
1076
1084
 
1077
1085
  const serializedTransaction = await signTransaction(client, prepared as never)
1078
1086
 
@@ -258,9 +258,14 @@ async function sendFeePayerTx(
258
258
  const prepared = await prepareTransactionRequest(client, {
259
259
  account,
260
260
  calls: [{ to, data }],
261
- feePayer: true,
262
261
  ...(feeToken ? { feeToken } : {}),
262
+ nonceKey: 'expiring',
263
+ validBefore: Math.floor(Date.now() / 1_000) + 25,
263
264
  } as never)
265
+ // Estimate before enabling fee-payer mode so Tempo includes sender
266
+ // signature verification costs in the gas budget.
267
+ prepared.gas = (prepared.gas ?? 0n) + 5_000n
268
+ ;(prepared as Record<string, unknown>).feePayer = true
264
269
 
265
270
  const serialized = (await signTransaction(client, {
266
271
  ...prepared,
@@ -117,6 +117,27 @@ describe('channelStore', () => {
117
117
  expect(typeof loaded!.createdAt).toBe('string')
118
118
  })
119
119
 
120
+ test('prefixes backing store keys when configured', async () => {
121
+ const rawStore = Store.memory()
122
+ const cs = ChannelStore.fromStore(Store.from(rawStore, { keyPrefix: 'tenant:' }))
123
+ await cs.updateChannel(channelId, () => makeChannel())
124
+
125
+ expect(await rawStore.get(`tenant:${channelId}`)).not.toBeNull()
126
+ expect(await rawStore.get(channelId)).toBeNull()
127
+ expect((await cs.getChannel(channelId))?.channelId).toBe(channelId)
128
+ })
129
+
130
+ test('isolates prefixed store wrappers', async () => {
131
+ const rawStore = Store.memory()
132
+ const first = ChannelStore.fromStore(Store.from(rawStore, { keyPrefix: 'tenant-a:' }))
133
+ const second = ChannelStore.fromStore(Store.from(rawStore, { keyPrefix: 'tenant-b:' }))
134
+ await first.updateChannel(channelId, () => makeChannel())
135
+
136
+ expect(await second.getChannel(channelId)).toBeNull()
137
+ expect(await rawStore.get(`tenant-a:${channelId}`)).not.toBeNull()
138
+ expect(await rawStore.get(`tenant-b:${channelId}`)).toBeNull()
139
+ })
140
+
120
141
  test('treats case-variant channelIds as the same record', async () => {
121
142
  const cs = ChannelStore.fromStore(Store.memory())
122
143
  await cs.updateChannel(mixedCaseAliasChannelId, () =>
@@ -26,6 +26,61 @@ function createRecord(overrides: Partial<SubscriptionRecord> = {}): Subscription
26
26
  }
27
27
 
28
28
  describe('tempo subscription store', () => {
29
+ test('prefixes all backing store keys when configured', async () => {
30
+ const rawStore = Store.memory()
31
+ const store = fromStore(Store.from(rawStore, { keyPrefix: 'tenant:' }))
32
+ let finishActivation!: () => void
33
+ const pendingActivation = new Promise<void>((resolve) => {
34
+ finishActivation = resolve
35
+ })
36
+ let activationStarted!: () => void
37
+ const activationStartedPromise = new Promise<void>((resolve) => {
38
+ activationStarted = resolve
39
+ })
40
+
41
+ const activation = store.activate({
42
+ challengeId: 'challenge-1',
43
+ create: async () => {
44
+ activationStarted()
45
+ await pendingActivation
46
+ return { subscription: createRecord() }
47
+ },
48
+ lookupKey: 'user-1:plan:pro',
49
+ })
50
+ await activationStartedPromise
51
+
52
+ expect(await rawStore.get('tenant:tempo:subscription:credential:challenge-1')).not.toBeNull()
53
+ expect(
54
+ await rawStore.get('tenant:tempo:subscription:activation:user-1:plan:pro'),
55
+ ).not.toBeNull()
56
+ expect(await rawStore.get('tempo:subscription:credential:challenge-1')).toBeNull()
57
+
58
+ finishActivation()
59
+ expect((await activation).status).toBe('activated')
60
+ await store.getOrCreateAccessKey('user-1:plan:pro')
61
+
62
+ expect(await rawStore.get(`tenant:tempo:subscription:record:${subscriptionId}`)).not.toBeNull()
63
+ expect(await rawStore.get('tenant:tempo:subscription:key:user-1:plan:pro')).toBe(subscriptionId)
64
+ expect(
65
+ await rawStore.get('tenant:tempo:subscription:access-key:user-1:plan:pro'),
66
+ ).not.toBeNull()
67
+ expect(await rawStore.get(`tempo:subscription:record:${subscriptionId}`)).toBeNull()
68
+ })
69
+
70
+ test('combines store prefix with custom key family prefixes', async () => {
71
+ const rawStore = Store.memory()
72
+ const store = fromStore(Store.from(rawStore, { keyPrefix: 'tenant:' }), {
73
+ keyPrefix: 'lookup:',
74
+ recordPrefix: 'record:',
75
+ })
76
+
77
+ await store.put(createRecord())
78
+
79
+ expect(await rawStore.get(`tenant:record:${subscriptionId}`)).not.toBeNull()
80
+ expect(await rawStore.get('tenant:lookup:user-1:plan:pro')).toBe(subscriptionId)
81
+ expect(await rawStore.get(`record:${subscriptionId}`)).toBeNull()
82
+ })
83
+
29
84
  test('rejects a replayed activation challenge', async () => {
30
85
  const store = fromStore(Store.memory())
31
86
 
@@ -1,6 +1,6 @@
1
1
  import { createClient, http } from 'viem'
2
2
  import { privateKeyToAccount } from 'viem/accounts'
3
- import { mainnet } from 'viem/chains'
3
+ import { tempo as mainnet } from 'viem/tempo/chains'
4
4
  import { describe, expect, test } from 'vp/test'
5
5
 
6
6
  import * as Account from './Account.js'
@@ -1,8 +1,8 @@
1
1
  import { createClient, custom, defineChain, type Hex } from 'viem'
2
2
  import { privateKeyToAccount } from 'viem/accounts'
3
3
  import { signTransaction } from 'viem/actions'
4
- import { tempoLocalnet } from 'viem/chains'
5
4
  import { Account as TempoAccount, Transaction } from 'viem/tempo'
5
+ import { tempoLocalnet } from 'viem/tempo/chains'
6
6
  import { describe, expect, test } from 'vp/test'
7
7
 
8
8
  import * as Client from './Client.js'