mppx 0.14.1 → 0.15.0
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/README.md +1 -1
- package/dist/Expires.js +1 -1
- package/dist/Store.d.ts +2 -2
- package/dist/Store.js +13 -3
- package/dist/attestation/internal/HttpMessageSignature.js +2 -0
- package/dist/cli/cli.js +25 -25
- package/dist/cli/plugins/index.js +2 -2
- package/dist/integrations/x402/Evm.d.ts +1 -0
- package/dist/internal/version.d.ts +2 -2
- package/dist/internal/version.js +1 -1
- package/dist/middlewares/express.js +18 -6
- package/dist/server/Mppx.d.ts +5 -0
- package/dist/server/Mppx.js +8 -3
- package/dist/tempo/Methods.d.ts +5 -0
- package/dist/tempo/Methods.js +1 -0
- package/dist/tempo/client/Subscription.d.ts +5 -0
- package/dist/tempo/server/Charge.js +4 -0
- package/dist/tempo/server/Methods.d.ts +26 -0
- package/dist/tempo/server/Subscription.d.ts +5 -0
- package/dist/tempo/server/Subscription.js +8 -4
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/session/server/Ws.d.ts +5 -2
- package/dist/tempo/session/server/Ws.js +11 -2
- package/dist/tempo/subscription/Store.d.ts +7 -1
- package/dist/tempo/subscription/Store.js +56 -4
- package/dist/tempo/subscription/Types.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# mppx
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4f8790f: Fixed implicit TLS bypass for local hostnames, discarded Express payment responses, expiry-crossing replay claims, standalone realm validation, and WebSocket metering from stale challenge prices. Bounded anonymous subscription challenge keys and retained billing keys only after successful payment submission.
|
|
8
|
+
|
|
9
|
+
Standalone credential APIs now require a configured matching realm or trusted route context. Custom WebSocket routes must return the canonical challenge or set an explicit `amount`. The CLI no longer pays when `--insecure` is enabled. Anonymous subscription setup carries an authenticated encrypted key token in the challenge, using one persistent sealing key instead of per-request pending state. Challenge expiry remains enforced before activation. Previously persisted abandoned keys are not automatically removed.
|
|
10
|
+
|
|
11
|
+
Preserved successful charge receipts when a challenge expired during settlement, preventing a fresh payment challenge after funds moved.
|
|
12
|
+
|
|
13
|
+
Preserved Express JSON replacers, spacing, and escaping before payment response wrapping. Preserved HTTPS hostnames for certificate validation; local HTTPS names use the system resolver, while plain HTTP localhost subdomains retain the loopback shortcut.
|
|
14
|
+
|
|
15
|
+
Selected the key bound to a new subscription challenge before a previously retained billing key, allowing an expired subscription to be activated again for the same payer.
|
|
16
|
+
|
|
3
17
|
## 0.14.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -71,8 +71,8 @@ Generate `MPP_SECRET_KEY` with at least 32 bytes, for example: `openssl rand -ba
|
|
|
71
71
|
### Client
|
|
72
72
|
|
|
73
73
|
```ts
|
|
74
|
-
import { privateKeyToAccount } from 'viem/accounts'
|
|
75
74
|
import { Mppx, tempo } from 'mppx/client'
|
|
75
|
+
import { privateKeyToAccount } from 'viem/accounts'
|
|
76
76
|
|
|
77
77
|
Mppx.create({
|
|
78
78
|
methods: [tempo({ account: privateKeyToAccount('0x...') })],
|
package/dist/Expires.js
CHANGED
|
@@ -16,7 +16,7 @@ export function assert(expires, challengeId) {
|
|
|
16
16
|
...(challengeId && { id: challengeId }),
|
|
17
17
|
reason: 'malformed expires timestamp',
|
|
18
18
|
});
|
|
19
|
-
if (
|
|
19
|
+
if (Date.parse(expires) <= Date.now())
|
|
20
20
|
throw new PaymentExpiredError({ expires });
|
|
21
21
|
}
|
|
22
22
|
/** Returns an ISO 8601 datetime string `n` days from now. */
|
package/dist/Store.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type Change<value, result> = {
|
|
|
28
28
|
* must be synchronous and free of side effects.
|
|
29
29
|
*/
|
|
30
30
|
export type Update<itemMap extends StoreItemMap = StoreItemMap> = <key extends keyof itemMap & string, result>(key: key, fn: (current: itemMap[key] | null) => Change<itemMap[key], result>) => Promise<result>;
|
|
31
|
-
/** Attempts to atomically record first use of a replay key
|
|
31
|
+
/** Attempts to atomically record first use of a replay key. Must reject expires <= Date.now() inside the atomic operation. */
|
|
32
32
|
export type TryClaim<itemMap extends StoreItemMap = StoreItemMap> = <key extends keyof itemMap & string>(key: key, expires: number) => MaybePromise<boolean>;
|
|
33
33
|
/** Persisted marker used by the {@link tryClaim} fallback. */
|
|
34
34
|
export type ReplayMarker = {
|
|
@@ -68,7 +68,7 @@ export type AtomicStore<itemMap extends StoreItemMap = StoreItemMap> = Store<ite
|
|
|
68
68
|
* Attempts to atomically record first use of a replay key through its expiry.
|
|
69
69
|
*
|
|
70
70
|
* Returns `true` when this call recorded the key and `false` when it was already
|
|
71
|
-
* recorded and unexpired. `expires` is a Unix timestamp in milliseconds.
|
|
71
|
+
* recorded and unexpired, or the proposed expiry has passed. `expires` is a Unix timestamp in milliseconds.
|
|
72
72
|
* Uses the adapter's optimized primitive when available and otherwise falls
|
|
73
73
|
* back to {@link AtomicStore.update}.
|
|
74
74
|
*/
|
package/dist/Store.js
CHANGED
|
@@ -19,14 +19,22 @@ import { Json } from 'ox';
|
|
|
19
19
|
* Attempts to atomically record first use of a replay key through its expiry.
|
|
20
20
|
*
|
|
21
21
|
* Returns `true` when this call recorded the key and `false` when it was already
|
|
22
|
-
* recorded and unexpired. `expires` is a Unix timestamp in milliseconds.
|
|
22
|
+
* recorded and unexpired, or the proposed expiry has passed. `expires` is a Unix timestamp in milliseconds.
|
|
23
23
|
* Uses the adapter's optimized primitive when available and otherwise falls
|
|
24
24
|
* back to {@link AtomicStore.update}.
|
|
25
25
|
*/
|
|
26
26
|
export function tryClaim(store, key, expires) {
|
|
27
|
-
if (
|
|
28
|
-
return
|
|
27
|
+
if (!Number.isFinite(expires) || expires <= Date.now())
|
|
28
|
+
return false;
|
|
29
|
+
if (store.tryClaim) {
|
|
30
|
+
const result = store.tryClaim(key, expires);
|
|
31
|
+
return typeof result === 'boolean'
|
|
32
|
+
? result && expires > Date.now()
|
|
33
|
+
: result.then((claimed) => claimed && expires > Date.now());
|
|
34
|
+
}
|
|
29
35
|
return store.update(key, (current) => {
|
|
36
|
+
if (!Number.isFinite(expires) || expires <= Date.now())
|
|
37
|
+
return { op: 'noop', result: false };
|
|
30
38
|
if (current !== null && (!isReplayMarker(current) || current.expires > Date.now()))
|
|
31
39
|
return { op: 'noop', result: false };
|
|
32
40
|
return {
|
|
@@ -144,6 +152,8 @@ export function memory(options) {
|
|
|
144
152
|
return change.result;
|
|
145
153
|
},
|
|
146
154
|
tryClaim(key, expires) {
|
|
155
|
+
if (!Number.isFinite(expires) || expires <= Date.now())
|
|
156
|
+
return false;
|
|
147
157
|
const current = store.has(key) ? Json.parse(store.get(key)) : null;
|
|
148
158
|
if (current !== null && (!isReplayMarker(current) || current.expires > Date.now()))
|
|
149
159
|
return false;
|
|
@@ -132,6 +132,8 @@ export async function verify(request, options) {
|
|
|
132
132
|
catch {
|
|
133
133
|
return { status: 'unverified', reason: 'Replay protection is unavailable.' };
|
|
134
134
|
}
|
|
135
|
+
if (input.expires <= Math.floor(Date.now() / 1000))
|
|
136
|
+
return { status: 'invalid', reason: 'The signature has expired.' };
|
|
135
137
|
return { status: 'verified', input };
|
|
136
138
|
}
|
|
137
139
|
function parse(request, expectedTag) {
|