mppx 0.9.3 → 0.10.1

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.
@@ -113,6 +113,8 @@ export type ResolveChallengeContextParameters = {
113
113
  challenge: Challenge.Challenge;
114
114
  /** Optional local escrow override. */
115
115
  escrowOverride?: Address | undefined;
116
+ /** Permitted payment chains, checked before resolution when known and again before signing. */
117
+ allowedChainIds?: readonly number[] | undefined;
116
118
  /** Resolves the viem client for the challenge chain. */
117
119
  getClient(parameters: {
118
120
  chainId?: number | undefined;
@@ -1,5 +1,6 @@
1
1
  import { isAddress, parseUnits, } from 'viem';
2
2
  import * as Constants from '../../../Constants.js';
3
+ import { assertAllowedChainId, assertChainId } from '../../../viem/Client.js';
3
4
  import * as z from '../../../zod.js';
4
5
  import * as AutoSwap from '../../internal/auto-swap.js';
5
6
  import * as Chain from '../precompile/Chain.js';
@@ -126,10 +127,15 @@ function readSuggestedDeposit(value) {
126
127
  }
127
128
  /** Resolves raw challenge fields into the typed data required by client credential planning. */
128
129
  export async function resolveChallengeContext(parameters) {
129
- const { allowCustomEscrow, challenge, escrowOverride, getClient } = parameters;
130
+ const { allowCustomEscrow, challenge, escrowOverride, allowedChainIds, getClient } = parameters;
130
131
  const methodDetails = readMethodDetails(challenge);
131
- const client = await getClient({ chainId: methodDetails.chainId });
132
- const chainId = methodDetails.chainId ?? client.chain?.id;
132
+ if (methodDetails.chainId !== undefined || allowedChainIds?.length === 0)
133
+ assertAllowedChainId(allowedChainIds, methodDetails.chainId);
134
+ const requestedChainId = methodDetails.chainId ?? (allowedChainIds?.length === 1 ? allowedChainIds[0] : undefined);
135
+ const client = await getClient({ chainId: requestedChainId });
136
+ assertChainId(client, requestedChainId);
137
+ const chainId = requestedChainId ?? client.chain?.id;
138
+ assertAllowedChainId(allowedChainIds, chainId);
133
139
  if (!chainId)
134
140
  throw new Error('No chainId configured for TIP-1034 session challenge.');
135
141
  const escrow = resolveEscrow(challenge, escrowOverride, allowCustomEscrow);
@@ -137,6 +137,12 @@ export declare namespace session {
137
137
  decimals?: number | undefined;
138
138
  /** Exact TIP20EscrowChannel address pin. Takes precedence over `allowCustomEscrow`. */
139
139
  escrow?: Address | undefined;
140
+ /**
141
+ * Chains permitted for session credentials. Omitted allows any chain; empty rejects all.
142
+ * A single entry supplies the chain when omitted by the challenge. Otherwise the
143
+ * challenge or resolved client must select an allowed chain.
144
+ */
145
+ allowedChainIds?: readonly number[] | undefined;
140
146
  /** Maximum channel deposit in human-readable units. Caps server-suggested opens and automatic top-ups. */
141
147
  maxDeposit?: string | undefined;
142
148
  /**
@@ -77,7 +77,7 @@ function acknowledgesOpen(outcome, challenge, opened) {
77
77
  * channel descriptor).
78
78
  */
79
79
  export function session(parameters = {}) {
80
- const { account, allowCustomEscrow = false, autoSwap: autoSwapParameter, channelStore, decimals = defaults.decimals, escrow: escrowOverride, getClient: getClientParameter, maxDeposit: maxDepositParameter, topUpAmount: topUpAmountParameter, onChannelUpdate, resolveAccount, } = parameters;
80
+ const { account, allowCustomEscrow = false, autoSwap: autoSwapParameter, channelStore, decimals = defaults.decimals, escrow: escrowOverride, allowedChainIds, getClient: getClientParameter, maxDeposit: maxDepositParameter, topUpAmount: topUpAmountParameter, onChannelUpdate, resolveAccount, } = parameters;
81
81
  const getClient = Client.getResolver({
82
82
  chain: tempo_chain,
83
83
  getClient: getClientParameter,
@@ -120,6 +120,7 @@ export function session(parameters = {}) {
120
120
  allowCustomEscrow,
121
121
  challenge,
122
122
  escrowOverride,
123
+ allowedChainIds,
123
124
  getClient,
124
125
  });
125
126
  const attempt = MethodResponse.getAttempt(parameters);
@@ -237,6 +238,7 @@ export function session(parameters = {}) {
237
238
  allowCustomEscrow,
238
239
  challenge,
239
240
  escrowOverride,
241
+ allowedChainIds,
240
242
  getClient,
241
243
  });
242
244
  const channel = await store.get(resolved.key);
@@ -278,6 +280,7 @@ export function session(parameters = {}) {
278
280
  allowCustomEscrow,
279
281
  challenge,
280
282
  escrowOverride,
283
+ allowedChainIds,
281
284
  getClient,
282
285
  })).key;
283
286
  let channel = await store.get(channelKey);
@@ -79,6 +79,12 @@ export declare namespace sessionManager {
79
79
  decimals?: number | undefined;
80
80
  /** Exact TIP20EscrowChannel address pin. Takes precedence over `allowCustomEscrow`. */
81
81
  escrow?: Address | undefined;
82
+ /**
83
+ * Chains permitted for sessions, bootstrap proofs, and snapshots. Omitted allows any
84
+ * chain; empty rejects all. A single entry supplies an omitted challenge chain;
85
+ * otherwise the challenge or resolved client must select an allowed chain.
86
+ */
87
+ allowedChainIds?: readonly number[] | undefined;
82
88
  /** Fetch implementation used for HTTP probes, management posts, and paid retries. */
83
89
  fetch?: typeof globalThis.fetch | undefined;
84
90
  /** Base context supplied to every session credential created by the manager. */
@@ -89,6 +89,9 @@ function resolveSessionManagerConfig(parameters) {
89
89
  * `channelStore` can persist reusable channels between manager instances.
90
90
  */
91
91
  export function sessionManager(parameters) {
92
+ const clientChainId = parameters.client?.chain?.id;
93
+ if (clientChainId !== undefined || parameters.allowedChainIds?.length === 0)
94
+ Client.assertAllowedChainId(parameters.allowedChainIds, clientChainId);
92
95
  const allowCustomEscrow = parameters.allowCustomEscrow ?? false;
93
96
  const config = resolveSessionManagerConfig(parameters);
94
97
  const getClient = Client.getResolver({
@@ -206,6 +209,7 @@ export function sessionManager(parameters) {
206
209
  getClient: parameters.client ? () => parameters.client : parameters.getClient,
207
210
  resolveAccount: parameters.resolveAccount,
208
211
  escrow: parameters.escrow,
212
+ allowedChainIds: parameters.allowedChainIds,
209
213
  decimals: config.decimals,
210
214
  maxDeposit: parameters.maxDeposit,
211
215
  topUpAmount: parameters.topUpAmount,
@@ -228,6 +232,7 @@ export function sessionManager(parameters) {
228
232
  });
229
233
  MethodResponse.unregister(method);
230
234
  const chargeMethod = chargePlugin({
235
+ allowedChainIds: parameters.allowedChainIds,
231
236
  account: parameters.account,
232
237
  getClient: parameters.client ? () => parameters.client : parameters.getClient,
233
238
  });
@@ -290,7 +295,9 @@ export function sessionManager(parameters) {
290
295
  if (!header)
291
296
  return undefined;
292
297
  const snapshot = deserializeSessionSnapshot(header);
298
+ Client.assertAllowedChainId(parameters.allowedChainIds, snapshot.chainId);
293
299
  const client = await getClient({ chainId: snapshot.chainId });
300
+ Client.assertChainId(client, snapshot.chainId);
294
301
  const defaultAccount = getAccount(client);
295
302
  const account = (await parameters.resolveAccount?.({
296
303
  account: defaultAccount,
@@ -37,6 +37,7 @@ export type ValidateResult = {
37
37
  passed: number;
38
38
  failed: number;
39
39
  warnings: number;
40
+ suggested: number;
40
41
  skipped: number;
41
42
  };
42
43
  suggestions: string[];
@@ -1,6 +1,6 @@
1
1
  import * as viemChains from 'viem/chains';
2
2
  import { validateChallenge, validateErrorHandling } from '../cli/validate/challenge.js';
3
- import { buildUrl, extractEndpointsFromDiscovery, extractRequestBodyFromDiscovery, fetchDiscoveryDoc, } from '../cli/validate/discovery.js';
3
+ import { buildUrl, extractEndpointsFromDiscovery, extractRequestBodyFromDiscovery, fetchDiscoveryDoc, validateLlmsDoc, } from '../cli/validate/discovery.js';
4
4
  import { isValidIntegerAmount, parseEndpointArg, resolveBodyForEndpoint, } from '../cli/validate/helpers.js';
5
5
  import { missingDiscoverySuggestion } from '../cli/validate/messages.js';
6
6
  import { validatePaymentFlow } from '../cli/validate/payment.js';
@@ -123,7 +123,7 @@ export async function validate(options) {
123
123
  break;
124
124
  }
125
125
  }
126
- const summary = { passed: 0, failed: 0, warnings: 0, skipped: 0 };
126
+ const summary = { passed: 0, failed: 0, warnings: 0, suggested: 0, skipped: 0 };
127
127
  if (discovery) {
128
128
  for (const r of discovery.checks) {
129
129
  if (r.severity === 'pass')
@@ -132,6 +132,8 @@ export async function validate(options) {
132
132
  summary.failed++;
133
133
  else if (r.severity === 'warn')
134
134
  summary.warnings++;
135
+ else if (r.severity === 'suggested')
136
+ summary.suggested++;
135
137
  else if (r.severity === 'skip')
136
138
  summary.skipped++;
137
139
  }
@@ -144,6 +146,8 @@ export async function validate(options) {
144
146
  summary.failed++;
145
147
  else if (r.severity === 'warn')
146
148
  summary.warnings++;
149
+ else if (r.severity === 'suggested')
150
+ summary.suggested++;
147
151
  else if (r.severity === 'skip')
148
152
  summary.skipped++;
149
153
  }
@@ -189,6 +193,7 @@ async function runDiscovery(baseUrl, options) {
189
193
  let discoveryDoc = null;
190
194
  let found = false;
191
195
  let valid = false;
196
+ checks.push(await validateLlmsDoc(baseUrl));
192
197
  // Try the user's path first, then root, then /api.
193
198
  const origin = new URL(baseUrl).origin;
194
199
  let candidates;
@@ -25,4 +25,8 @@ export declare namespace getResolver {
25
25
  }) => MaybePromise<Client>) | undefined;
26
26
  };
27
27
  }
28
+ /** Rejects a resolved client whose known chain conflicts with the requested payment chain. */
29
+ export declare function assertChainId(client: Client, chainId: number | undefined): void;
30
+ /** Rejects disallowed or unknown payment chains when an allowlist is configured. */
31
+ export declare function assertAllowedChainId(allowedChainIds: readonly number[] | undefined, chainId: number | undefined): void;
28
32
  //# sourceMappingURL=Client.d.ts.map
@@ -50,6 +50,8 @@ export function getResolver(parameters) {
50
50
  return Object.assign({}, resolvedClient, {
51
51
  chain: {
52
52
  ...chain,
53
+ // Serializer defaults must not replace an explicitly requested network.
54
+ ...(params.chainId !== undefined ? { id: params.chainId } : {}),
53
55
  ...resolvedClient.chain,
54
56
  formatters: resolvedClient.chain?.formatters ?? chain.formatters,
55
57
  prepareTransactionRequest: resolvedClient.chain?.prepareTransactionRequest ?? chain.prepareTransactionRequest,
@@ -76,4 +78,15 @@ export function getResolver(parameters) {
76
78
  });
77
79
  };
78
80
  }
81
+ /** Rejects a resolved client whose known chain conflicts with the requested payment chain. */
82
+ export function assertChainId(client, chainId) {
83
+ if (chainId !== undefined && client.chain?.id !== undefined && client.chain.id !== chainId)
84
+ throw new Error(`Chain ID mismatch: expected ${chainId}, got ${client.chain.id}.`);
85
+ }
86
+ /** Rejects disallowed or unknown payment chains when an allowlist is configured. */
87
+ export function assertAllowedChainId(allowedChainIds, chainId) {
88
+ if (allowedChainIds !== undefined &&
89
+ (chainId === undefined || !allowedChainIds.includes(chainId)))
90
+ throw new Error(`Chain ID not allowed: ${chainId ?? 'unknown'}.`);
91
+ }
79
92
  //# sourceMappingURL=Client.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mppx",
3
3
  "type": "module",
4
- "version": "0.9.3",
4
+ "version": "0.10.1",
5
5
  "main": "./dist/index.js",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/wevm/mppx#readme",