@broccolo1d/wallet-browser 0.1.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.
Files changed (53) hide show
  1. package/dist/cli.d.ts +14 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +197 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/config.d.ts +45 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +149 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/extension-pages.d.ts +26 -0
  10. package/dist/extension-pages.d.ts.map +1 -0
  11. package/dist/extension-pages.js +140 -0
  12. package/dist/extension-pages.js.map +1 -0
  13. package/dist/fixture-harness.d.ts +22 -0
  14. package/dist/fixture-harness.d.ts.map +1 -0
  15. package/dist/fixture-harness.js +69 -0
  16. package/dist/fixture-harness.js.map +1 -0
  17. package/dist/fixture-proof.d.ts +23 -0
  18. package/dist/fixture-proof.d.ts.map +1 -0
  19. package/dist/fixture-proof.js +90 -0
  20. package/dist/fixture-proof.js.map +1 -0
  21. package/dist/index.d.ts +13 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +13 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/launcher.d.ts +15 -0
  26. package/dist/launcher.d.ts.map +1 -0
  27. package/dist/launcher.js +26 -0
  28. package/dist/launcher.js.map +1 -0
  29. package/dist/metamask-prompts.d.ts +27 -0
  30. package/dist/metamask-prompts.d.ts.map +1 -0
  31. package/dist/metamask-prompts.js +116 -0
  32. package/dist/metamask-prompts.js.map +1 -0
  33. package/dist/metamask-smoke.d.ts +54 -0
  34. package/dist/metamask-smoke.d.ts.map +1 -0
  35. package/dist/metamask-smoke.js +261 -0
  36. package/dist/metamask-smoke.js.map +1 -0
  37. package/dist/network.d.ts +79 -0
  38. package/dist/network.d.ts.map +1 -0
  39. package/dist/network.js +243 -0
  40. package/dist/network.js.map +1 -0
  41. package/dist/onboarding.d.ts +95 -0
  42. package/dist/onboarding.d.ts.map +1 -0
  43. package/dist/onboarding.js +197 -0
  44. package/dist/onboarding.js.map +1 -0
  45. package/dist/profile-bootstrap.d.ts +33 -0
  46. package/dist/profile-bootstrap.d.ts.map +1 -0
  47. package/dist/profile-bootstrap.js +46 -0
  48. package/dist/profile-bootstrap.js.map +1 -0
  49. package/dist/wallet-control.d.ts +137 -0
  50. package/dist/wallet-control.d.ts.map +1 -0
  51. package/dist/wallet-control.js +453 -0
  52. package/dist/wallet-control.js.map +1 -0
  53. package/package.json +35 -0
@@ -0,0 +1,261 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
3
+ import { basename, join, resolve } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { discoverMetaMaskExtensionPage } from './extension-pages.js';
6
+ import { launchWalletBrowser } from './launcher.js';
7
+ export async function captureMetaMaskSmokeScreenshots(options = {}) {
8
+ const cwd = options.cwd ?? process.cwd();
9
+ const artifactDir = resolve(cwd, options.artifactDir ?? join('.wallet-artifacts', 'metamask-smoke', safeTimestamp()));
10
+ const extensionScreenshotLabel = options.extensionScreenshotLabel ?? 'metamask-extension';
11
+ mkdirSync(artifactDir, { recursive: true });
12
+ const { context } = await launchWalletBrowser({ cwd, env: options.env });
13
+ try {
14
+ const extensionPage = await openOrDiscoverMetaMaskPage(context);
15
+ await waitForMetaMaskUiReady(extensionPage);
16
+ await extensionPage.waitForTimeout(10000);
17
+ const browserPage = await openBrowserSmokePage(context, cwd);
18
+ const screenshots = [
19
+ { label: 'browser-page', path: join(artifactDir, 'browser-page.png') },
20
+ { label: extensionScreenshotLabel, path: join(artifactDir, `${extensionScreenshotLabel}.png`) }
21
+ ];
22
+ await browserPage.screenshot({ path: screenshots[0].path, fullPage: true });
23
+ await extensionPage.bringToFront();
24
+ await extensionPage.screenshot({ path: screenshots[1].path });
25
+ const notes = [
26
+ ...(options.notes ?? []),
27
+ 'No wallet was imported, unlocked, connected, used to sign, or used to transact.',
28
+ 'Treat generated screenshots as local-only until visually inspected for sensitive content.'
29
+ ];
30
+ const inspectionGuidePath = writeSmokeInspectionGuide({ artifactDir, screenshots, notes });
31
+ const manifestPath = writeSmokeArtifactManifest({ artifactDir, screenshots, inspectionGuidePath, notes });
32
+ return {
33
+ status: 'captured',
34
+ artifactDir,
35
+ screenshots,
36
+ inspectionGuidePath,
37
+ manifestPath,
38
+ notes
39
+ };
40
+ }
41
+ finally {
42
+ await context.close();
43
+ }
44
+ }
45
+ export async function captureFixtureExtensionSmokeScreenshots(options = {}) {
46
+ const cwd = options.cwd ?? process.cwd();
47
+ const artifactDir = resolve(cwd, options.artifactDir ?? join('.wallet-artifacts', 'fixture-extension-smoke', safeTimestamp()));
48
+ const extensionPath = join(artifactDir, 'fixture-extension');
49
+ createFixtureExtension(extensionPath);
50
+ const result = await captureMetaMaskSmokeScreenshots({
51
+ cwd,
52
+ artifactDir,
53
+ env: {
54
+ ...options.env,
55
+ METAMASK_EXTENSION_PATH: extensionPath,
56
+ WALLET_PROFILE_DIR: join(artifactDir, 'profile')
57
+ },
58
+ extensionScreenshotLabel: 'fixture-extension',
59
+ notes: [
60
+ 'Fixture extension smoke proves Chromium extension-loading mechanics only; it is not MetaMask UI.',
61
+ 'The generated fixture manifest identifies as MetaMask only to exercise the same launcher validation path without downloading the real bundle.'
62
+ ]
63
+ });
64
+ return result;
65
+ }
66
+ async function openBrowserSmokePage(context, cwd) {
67
+ const page = await context.newPage();
68
+ const fixtureDappUrl = resolveDefaultFixtureDappSmokeUrl(cwd);
69
+ if (fixtureDappUrl) {
70
+ await page.goto(fixtureDappUrl, { waitUntil: 'domcontentloaded' });
71
+ return page;
72
+ }
73
+ await page.setContent(`<!doctype html>
74
+ <title>brocolli-test MetaMask Smoke</title>
75
+ <main style="font-family: system-ui, sans-serif; padding: 2rem; max-width: 52rem;">
76
+ <h1>brocolli-test MetaMask smoke</h1>
77
+ <p>Chromium launched with an unpacked MetaMask extension in a persistent context.</p>
78
+ <p>This milestone does not import, unlock, connect, sign, or transact.</p>
79
+ </main>`);
80
+ return page;
81
+ }
82
+ async function openOrDiscoverMetaMaskPage(context) {
83
+ const extensionId = await discoverSingleExtensionId(context);
84
+ const page = await context.newPage();
85
+ await page.goto(`chrome-extension://${extensionId}/home.html`, { waitUntil: 'domcontentloaded' });
86
+ return page;
87
+ }
88
+ async function waitForMetaMaskUiReady(page) {
89
+ await page.waitForLoadState('domcontentloaded').catch(() => undefined);
90
+ await page
91
+ .getByText(/Create a new wallet|I have an existing wallet|Import an existing wallet|MetaMask encountered an error/i)
92
+ .first()
93
+ .waitFor({ state: 'visible', timeout: 15000 });
94
+ const bodyText = await page.locator('body').innerText({ timeout: 1000 }).catch(() => '');
95
+ if (/MetaMask encountered an error/i.test(bodyText)) {
96
+ throw new Error('MetaMask extension UI reached an error screen before smoke screenshot capture.');
97
+ }
98
+ }
99
+ export function resolveDefaultFixtureDappSmokeUrl(cwd) {
100
+ const fixtureDappIndex = resolve(cwd, 'apps', 'fixture-dapp', 'index.html');
101
+ return existsSync(fixtureDappIndex) ? pathToFileURL(fixtureDappIndex).toString() : undefined;
102
+ }
103
+ export function writeSmokeInspectionGuide(options) {
104
+ const guidePath = join(options.artifactDir, 'INSPECTION.md');
105
+ const checklist = options.screenshots.map((screenshot) => {
106
+ const fileName = basename(screenshot.path);
107
+ return `- [ ] Confirm \`${fileName}\` contains no seed phrases, private keys, passwords, RPC tokens, full wallet addresses, or sensitive local paths.`;
108
+ });
109
+ const notes = options.notes.map((note) => `- ${note}`);
110
+ writeFileSync(guidePath, `# Wallet browser smoke screenshot inspection
111
+
112
+ These screenshots are local-only evidence until reviewed. Do not commit or publish them by default.
113
+
114
+ ## Required visual checks
115
+
116
+ ${checklist.join('\n')}
117
+ - [ ] Confirm the screenshots do not show wallet import, unlock, account connection, signature approval, or transaction approval state.
118
+
119
+ ## Smoke notes
120
+
121
+ ${notes.join('\n')}
122
+
123
+ Keep this artifact directory ignored/local-only unless every screenshot above is reviewed and intentionally promoted.
124
+ `);
125
+ return guidePath;
126
+ }
127
+ export function writeSmokeArtifactManifest(options) {
128
+ const manifestPath = join(options.artifactDir, 'SMOKE-MANIFEST.json');
129
+ const screenshots = options.screenshots.map((screenshot) => {
130
+ const bytes = readFileSync(screenshot.path);
131
+ return {
132
+ label: screenshot.label,
133
+ file: basename(screenshot.path),
134
+ sizeBytes: statSync(screenshot.path).size,
135
+ sha256: createHash('sha256').update(bytes).digest('hex')
136
+ };
137
+ });
138
+ writeFileSync(manifestPath, `${JSON.stringify({
139
+ artifactType: 'wallet-browser-smoke-screenshots',
140
+ inspectionGuide: basename(options.inspectionGuidePath),
141
+ screenshots,
142
+ notes: options.notes
143
+ }, null, 2)}\n`);
144
+ return manifestPath;
145
+ }
146
+ export function verifySmokeArtifactManifest(artifactDir) {
147
+ const manifestPath = join(artifactDir, 'SMOKE-MANIFEST.json');
148
+ const manifestText = readFileSync(manifestPath, 'utf8');
149
+ if (manifestText.includes(artifactDir)) {
150
+ throw new Error('Smoke artifact manifest must not contain the full artifact directory path.');
151
+ }
152
+ const manifest = JSON.parse(manifestText);
153
+ if (manifest.artifactType !== 'wallet-browser-smoke-screenshots') {
154
+ throw new Error('Smoke artifact manifest has an unexpected artifact type.');
155
+ }
156
+ if (!isSafeArtifactFileName(manifest.inspectionGuide)) {
157
+ throw new Error('Smoke artifact manifest inspection guide must be a safe basename.');
158
+ }
159
+ const inspectionGuidePath = join(artifactDir, manifest.inspectionGuide);
160
+ if (!existsSync(inspectionGuidePath)) {
161
+ throw new Error('Smoke artifact inspection guide is missing.');
162
+ }
163
+ if (!Array.isArray(manifest.screenshots) || manifest.screenshots.length === 0) {
164
+ throw new Error('Smoke artifact manifest must list at least one screenshot.');
165
+ }
166
+ const screenshots = manifest.screenshots.map((screenshot) => verifyManifestScreenshot(artifactDir, screenshot));
167
+ return {
168
+ status: 'verified',
169
+ artifactDir,
170
+ manifestPath,
171
+ inspectionGuidePath,
172
+ screenshots,
173
+ notes: Array.isArray(manifest.notes) ? manifest.notes : []
174
+ };
175
+ }
176
+ function verifyManifestScreenshot(artifactDir, screenshot) {
177
+ if (!isKnownScreenshotLabel(screenshot.label)) {
178
+ throw new Error(`Smoke artifact manifest contains an unexpected screenshot label: ${String(screenshot.label)}`);
179
+ }
180
+ if (!isSafeArtifactFileName(screenshot.file)) {
181
+ throw new Error(`Smoke artifact manifest screenshot file must be a safe basename: ${String(screenshot.file)}`);
182
+ }
183
+ const screenshotPath = join(artifactDir, screenshot.file);
184
+ const bytes = readFileSync(screenshotPath);
185
+ const sizeBytes = statSync(screenshotPath).size;
186
+ const sha256 = createHash('sha256').update(bytes).digest('hex');
187
+ if (screenshot.sizeBytes !== sizeBytes) {
188
+ throw new Error(`Smoke artifact screenshot size mismatch for ${screenshot.file}.`);
189
+ }
190
+ if (screenshot.sha256 !== sha256) {
191
+ throw new Error(`Smoke artifact screenshot hash mismatch for ${screenshot.file}.`);
192
+ }
193
+ return { ...screenshot, sizeBytes, sha256 };
194
+ }
195
+ function isKnownScreenshotLabel(label) {
196
+ return label === 'browser-page' || label === 'metamask-extension' || label === 'fixture-extension';
197
+ }
198
+ function isSafeArtifactFileName(fileName) {
199
+ return typeof fileName === 'string' && fileName.length > 0 && fileName === basename(fileName) && !fileName.includes('..');
200
+ }
201
+ function createFixtureExtension(extensionPath) {
202
+ mkdirSync(extensionPath, { recursive: true });
203
+ writeFileSync(join(extensionPath, 'manifest.json'), `${JSON.stringify({
204
+ manifest_version: 3,
205
+ name: 'MetaMask',
206
+ short_name: 'MetaMask',
207
+ version: '0.0.0',
208
+ background: { service_worker: 'service-worker.js' },
209
+ action: { default_title: 'Fixture extension' }
210
+ }, null, 2)}\n`);
211
+ writeFileSync(join(extensionPath, 'service-worker.js'), "chrome.runtime.onInstalled.addListener(() => undefined);\n");
212
+ writeFileSync(join(extensionPath, 'home.html'), `<!doctype html>
213
+ <title>Fixture extension smoke</title>
214
+ <main style="font-family: system-ui, sans-serif; padding: 2rem; max-width: 48rem;">
215
+ <h1>Fixture extension loading smoke</h1>
216
+ <p>This generated extension proves Chromium loaded an unpacked extension in a persistent context.</p>
217
+ <p><strong>This is not MetaMask UI.</strong> It does not import, unlock, connect, sign, or transact.</p>
218
+ </main>`);
219
+ }
220
+ function tryDiscoverMetaMaskPage(pages) {
221
+ try {
222
+ return discoverMetaMaskExtensionPage(pages);
223
+ }
224
+ catch {
225
+ return undefined;
226
+ }
227
+ }
228
+ async function discoverSingleExtensionId(context) {
229
+ let ids = collectExtensionIds(context);
230
+ if (ids.size === 0) {
231
+ await context.waitForEvent('serviceworker', { timeout: 5000 }).catch(() => undefined);
232
+ ids = collectExtensionIds(context);
233
+ }
234
+ if (ids.size !== 1) {
235
+ throw new Error('Unable to discover a single loaded MetaMask extension id from Chromium service workers.');
236
+ }
237
+ return [...ids][0];
238
+ }
239
+ function collectExtensionIds(context) {
240
+ const ids = new Set();
241
+ for (const worker of context.serviceWorkers()) {
242
+ const id = extensionIdFromChromeExtensionUrl(worker.url());
243
+ if (id) {
244
+ ids.add(id);
245
+ }
246
+ }
247
+ return ids;
248
+ }
249
+ function extensionIdFromChromeExtensionUrl(url) {
250
+ try {
251
+ const parsed = new URL(url);
252
+ return parsed.protocol === 'chrome-extension:' ? parsed.hostname : undefined;
253
+ }
254
+ catch {
255
+ return undefined;
256
+ }
257
+ }
258
+ function safeTimestamp(date = new Date()) {
259
+ return date.toISOString().replace(/[:.]/g, '-');
260
+ }
261
+ //# sourceMappingURL=metamask-smoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metamask-smoke.js","sourceRoot":"","sources":["../src/metamask-smoke.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import type { Page } from 'playwright';
2
+ import type { WalletBrowserEnv } from './config.js';
3
+ export declare const DEFAULT_SEPOLIA_CHAIN_ID = 11155111;
4
+ export declare const DEFAULT_NETWORK_ASSERTION_TIMEOUT_MS = 30000;
5
+ export declare const DEFAULT_ALLOWED_WALLET_CHAIN_IDS: readonly [11155111, 31337, 1337];
6
+ export interface SepoliaNetworkEnv extends WalletBrowserEnv {
7
+ SEPOLIA_CHAIN_ID?: string;
8
+ SEPOLIA_RPC_URL?: string;
9
+ SEPOLIA_WALLET_ADDRESS?: string;
10
+ METAMASK_NETWORK_ASSERTION_TIMEOUT_MS?: string;
11
+ METAMASK_NETWORK_DEBUG?: string;
12
+ }
13
+ export interface ResolveSepoliaNetworkConfigOptions {
14
+ env?: SepoliaNetworkEnv;
15
+ chainId?: string | number;
16
+ rpcUrl?: string;
17
+ expectedAccount?: string;
18
+ timeoutMs?: number;
19
+ debug?: boolean;
20
+ }
21
+ export interface SepoliaNetworkConfig {
22
+ chainId: number;
23
+ chainIdHex: string;
24
+ expectedAccount: string;
25
+ rpcUrl?: string;
26
+ timeoutMs: number;
27
+ debug: boolean;
28
+ }
29
+ export interface RedactedSepoliaNetworkPlan {
30
+ status: 'pending';
31
+ chainId: number;
32
+ chainIdHex: string;
33
+ expectedAccount: string;
34
+ rpcUrlConfigured: boolean;
35
+ rpcUrl?: string;
36
+ timeoutMs: number;
37
+ debug: boolean;
38
+ }
39
+ export interface SepoliaNetworkAssertionResult {
40
+ status: 'verified';
41
+ chainId: number;
42
+ chainIdHex: string;
43
+ expectedAccount: string;
44
+ activeAccount: string;
45
+ }
46
+ export interface AddEthereumChainInput {
47
+ chainId: string;
48
+ chainName: string;
49
+ rpcUrls: string[];
50
+ nativeCurrency: {
51
+ name: string;
52
+ symbol: string;
53
+ decimals: number;
54
+ };
55
+ blockExplorerUrls: string[];
56
+ }
57
+ export interface MetaMaskNetworkDriver {
58
+ getChainId(): Promise<string | number>;
59
+ getAccounts(): Promise<string[]>;
60
+ switchChain(chainIdHex: string): Promise<void>;
61
+ addEthereumChain(input: AddEthereumChainInput): Promise<void>;
62
+ }
63
+ export interface MetaMaskNetworkPageDriverOptions {
64
+ page: Page;
65
+ timeoutMs?: number;
66
+ }
67
+ export declare function normalizeChainId(value: string | number | undefined): number;
68
+ export declare function chainIdToHex(chainId: number): string;
69
+ export declare function normalizeExpectedAccount(value: string | undefined): string;
70
+ export declare function isAllowedWalletChainId(value: string | number): boolean;
71
+ export declare function resolveSepoliaNetworkConfig(options?: ResolveSepoliaNetworkConfigOptions): SepoliaNetworkConfig;
72
+ export declare function validateOptionalRpcUrl(value: string | undefined): string | undefined;
73
+ export declare function createSepoliaNetworkPlan(config: SepoliaNetworkConfig): RedactedSepoliaNetworkPlan;
74
+ export declare function assertExpectedChainAndAccount(config: SepoliaNetworkConfig, driver: MetaMaskNetworkDriver): Promise<SepoliaNetworkAssertionResult>;
75
+ export declare function provisionSepoliaNetwork(config: SepoliaNetworkConfig, driver: MetaMaskNetworkDriver): Promise<SepoliaNetworkAssertionResult>;
76
+ export declare function createSepoliaAddChainInput(config: SepoliaNetworkConfig): AddEthereumChainInput;
77
+ export declare function createMetaMaskNetworkPageDriver(options: MetaMaskNetworkPageDriverOptions): MetaMaskNetworkDriver;
78
+ export declare function redactRpcUrl(value: string): string;
79
+ //# sourceMappingURL=network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,243 @@
1
+ import { validateEthereumAddress } from './onboarding.js';
2
+ export const DEFAULT_SEPOLIA_CHAIN_ID = 11_155_111;
3
+ export const DEFAULT_NETWORK_ASSERTION_TIMEOUT_MS = 30_000;
4
+ export const DEFAULT_ALLOWED_WALLET_CHAIN_IDS = [DEFAULT_SEPOLIA_CHAIN_ID, 31_337, 1_337];
5
+ export function normalizeChainId(value) {
6
+ if (typeof value === 'number') {
7
+ if (!Number.isInteger(value) || value <= 0) {
8
+ throw new Error('Chain id must be a positive integer.');
9
+ }
10
+ return validateSafeChainId(value);
11
+ }
12
+ const trimmed = value?.trim();
13
+ if (!trimmed) {
14
+ throw new Error('Chain id is required.');
15
+ }
16
+ if (/^0x[0-9a-fA-F]+$/.test(trimmed)) {
17
+ return validateSafeChainId(Number.parseInt(trimmed, 16));
18
+ }
19
+ if (/^[0-9]+$/.test(trimmed)) {
20
+ return validateSafeChainId(Number.parseInt(trimmed, 10));
21
+ }
22
+ throw new Error('Chain id must be a decimal integer or 0x-prefixed hexadecimal value.');
23
+ }
24
+ export function chainIdToHex(chainId) {
25
+ return `0x${validatePositiveSafeChainId(chainId).toString(16)}`;
26
+ }
27
+ function validateSafeChainId(chainId) {
28
+ if (!Number.isSafeInteger(chainId)) {
29
+ throw new Error('Chain id must be within JavaScript safe integer range.');
30
+ }
31
+ return chainId;
32
+ }
33
+ function validatePositiveSafeChainId(chainId) {
34
+ if (!Number.isInteger(chainId) || chainId <= 0) {
35
+ throw new Error('Chain id must be a positive integer.');
36
+ }
37
+ return validateSafeChainId(chainId);
38
+ }
39
+ export function normalizeExpectedAccount(value) {
40
+ return validateEthereumAddress(value);
41
+ }
42
+ export function isAllowedWalletChainId(value) {
43
+ try {
44
+ const chainId = normalizeChainId(value);
45
+ return DEFAULT_ALLOWED_WALLET_CHAIN_IDS.includes(chainId);
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ export function resolveSepoliaNetworkConfig(options = {}) {
52
+ const env = options.env ?? process.env;
53
+ const chainId = normalizeChainId(options.chainId ?? env.SEPOLIA_CHAIN_ID ?? DEFAULT_SEPOLIA_CHAIN_ID);
54
+ if (chainId !== DEFAULT_SEPOLIA_CHAIN_ID) {
55
+ throw new Error(`SEPOLIA_CHAIN_ID must be ${DEFAULT_SEPOLIA_CHAIN_ID} for Sepolia provisioning.`);
56
+ }
57
+ return {
58
+ chainId,
59
+ chainIdHex: chainIdToHex(chainId),
60
+ expectedAccount: normalizeExpectedAccount(options.expectedAccount ?? env.SEPOLIA_WALLET_ADDRESS),
61
+ rpcUrl: validateOptionalRpcUrl(options.rpcUrl ?? env.SEPOLIA_RPC_URL),
62
+ timeoutMs: resolveNetworkTimeoutMs(options.timeoutMs, env.METAMASK_NETWORK_ASSERTION_TIMEOUT_MS),
63
+ debug: options.debug ?? parseBoolean(env.METAMASK_NETWORK_DEBUG)
64
+ };
65
+ }
66
+ export function validateOptionalRpcUrl(value) {
67
+ const trimmed = value?.trim();
68
+ if (!trimmed) {
69
+ return undefined;
70
+ }
71
+ let parsed;
72
+ try {
73
+ parsed = new URL(trimmed);
74
+ }
75
+ catch {
76
+ throw new Error('SEPOLIA_RPC_URL must be a valid http(s) URL when provided.');
77
+ }
78
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
79
+ throw new Error('SEPOLIA_RPC_URL must use http or https when provided.');
80
+ }
81
+ return trimmed;
82
+ }
83
+ export function createSepoliaNetworkPlan(config) {
84
+ return {
85
+ status: 'pending',
86
+ chainId: config.chainId,
87
+ chainIdHex: config.chainIdHex,
88
+ expectedAccount: config.expectedAccount,
89
+ rpcUrlConfigured: config.rpcUrl !== undefined,
90
+ rpcUrl: config.rpcUrl ? redactRpcUrl(config.rpcUrl) : undefined,
91
+ timeoutMs: config.timeoutMs,
92
+ debug: config.debug
93
+ };
94
+ }
95
+ export async function assertExpectedChainAndAccount(config, driver) {
96
+ const activeChainId = await runRedactedNetworkStep(config, 'read active wallet chain', () => driver.getChainId());
97
+ const normalizedChainId = normalizeChainId(activeChainId);
98
+ if (!isAllowedWalletChainId(normalizedChainId)) {
99
+ throw new Error(`Wallet chain ${chainIdToHex(normalizedChainId)} is not allowed for this harness.`);
100
+ }
101
+ if (normalizedChainId !== config.chainId) {
102
+ throw new Error(`Wallet chain ${chainIdToHex(normalizedChainId)} does not match expected Sepolia chain ${config.chainIdHex}.`);
103
+ }
104
+ const accounts = await runRedactedNetworkStep(config, 'read active wallet accounts', () => driver.getAccounts());
105
+ const activeAccount = normalizeExpectedAccount(accounts[0]);
106
+ if (activeAccount !== config.expectedAccount) {
107
+ throw new Error(`Wallet active account ${activeAccount} does not match expected ${config.expectedAccount}.`);
108
+ }
109
+ return {
110
+ status: 'verified',
111
+ chainId: config.chainId,
112
+ chainIdHex: config.chainIdHex,
113
+ expectedAccount: config.expectedAccount,
114
+ activeAccount
115
+ };
116
+ }
117
+ export async function provisionSepoliaNetwork(config, driver) {
118
+ const activeChainId = normalizeChainId(await runRedactedNetworkStep(config, 'read active wallet chain', () => driver.getChainId()));
119
+ if (!isAllowedWalletChainId(activeChainId)) {
120
+ throw new Error(`Wallet chain ${chainIdToHex(activeChainId)} is not allowed for this harness.`);
121
+ }
122
+ if (activeChainId !== config.chainId) {
123
+ try {
124
+ await runRedactedNetworkStep(config, 'switch MetaMask to Sepolia', () => driver.switchChain(config.chainIdHex));
125
+ }
126
+ catch (error) {
127
+ if (!config.rpcUrl) {
128
+ throw new Error(`SEPOLIA_RPC_URL is required to add Sepolia after MetaMask switch failed: ${redactNetworkErrorMessage(config, error)}`);
129
+ }
130
+ await runRedactedNetworkStep(config, 'add Sepolia to MetaMask', () => driver.addEthereumChain(createSepoliaAddChainInput(config)));
131
+ await runRedactedNetworkStep(config, 'switch MetaMask to Sepolia after adding network', () => driver.switchChain(config.chainIdHex));
132
+ }
133
+ }
134
+ return assertExpectedChainAndAccount(config, driver);
135
+ }
136
+ export function createSepoliaAddChainInput(config) {
137
+ if (!config.rpcUrl) {
138
+ throw new Error('SEPOLIA_RPC_URL is required to add Sepolia to MetaMask.');
139
+ }
140
+ return {
141
+ chainId: config.chainIdHex,
142
+ chainName: 'Sepolia',
143
+ rpcUrls: [config.rpcUrl],
144
+ nativeCurrency: {
145
+ name: 'Sepolia Ether',
146
+ symbol: 'ETH',
147
+ decimals: 18
148
+ },
149
+ blockExplorerUrls: ['https://sepolia.etherscan.io']
150
+ };
151
+ }
152
+ export function createMetaMaskNetworkPageDriver(options) {
153
+ const timeoutMs = resolvePageDriverTimeoutMs(options.timeoutMs);
154
+ return {
155
+ async getChainId() {
156
+ const result = await requestEthereum(options.page, { method: 'eth_chainId' }, timeoutMs);
157
+ if (typeof result !== 'string' && typeof result !== 'number') {
158
+ throw new Error('MetaMask returned an invalid eth_chainId response.');
159
+ }
160
+ return result;
161
+ },
162
+ async getAccounts() {
163
+ const result = await requestEthereum(options.page, { method: 'eth_accounts' }, timeoutMs);
164
+ if (!Array.isArray(result) || !result.every((value) => typeof value === 'string')) {
165
+ throw new Error('MetaMask returned an invalid eth_accounts response.');
166
+ }
167
+ return result;
168
+ },
169
+ async switchChain(chainIdHex) {
170
+ await requestEthereum(options.page, { method: 'wallet_switchEthereumChain', params: [{ chainId: chainIdHex }] }, timeoutMs);
171
+ },
172
+ async addEthereumChain(input) {
173
+ await requestEthereum(options.page, { method: 'wallet_addEthereumChain', params: [input] }, timeoutMs);
174
+ }
175
+ };
176
+ }
177
+ async function requestEthereum(page, request, timeoutMs) {
178
+ let timeoutHandle;
179
+ try {
180
+ return await Promise.race([
181
+ page.evaluate(async (input) => {
182
+ const maybeProvider = globalThis.ethereum;
183
+ if (!maybeProvider?.request) {
184
+ throw new Error('window.ethereum.request is not available on the selected MetaMask page.');
185
+ }
186
+ return maybeProvider.request(input);
187
+ }, request),
188
+ new Promise((_, reject) => {
189
+ timeoutHandle = setTimeout(() => {
190
+ reject(new Error(`MetaMask EIP-1193 request ${request.method} timed out after ${timeoutMs}ms.`));
191
+ }, timeoutMs);
192
+ })
193
+ ]);
194
+ }
195
+ finally {
196
+ if (timeoutHandle) {
197
+ clearTimeout(timeoutHandle);
198
+ }
199
+ }
200
+ }
201
+ function resolvePageDriverTimeoutMs(timeoutMs) {
202
+ const resolved = timeoutMs ?? DEFAULT_NETWORK_ASSERTION_TIMEOUT_MS;
203
+ if (!Number.isInteger(resolved) || resolved <= 0) {
204
+ throw new Error('MetaMask page network driver timeoutMs must be a positive integer.');
205
+ }
206
+ return resolved;
207
+ }
208
+ function resolveNetworkTimeoutMs(explicit, envValue) {
209
+ const raw = explicit ?? (envValue ? Number(envValue) : DEFAULT_NETWORK_ASSERTION_TIMEOUT_MS);
210
+ if (!Number.isInteger(raw) || raw <= 0) {
211
+ throw new Error('METAMASK_NETWORK_ASSERTION_TIMEOUT_MS must be a positive integer.');
212
+ }
213
+ return raw;
214
+ }
215
+ function parseBoolean(value) {
216
+ if (value === undefined || value.trim() === '') {
217
+ return false;
218
+ }
219
+ return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
220
+ }
221
+ async function runRedactedNetworkStep(config, label, step) {
222
+ try {
223
+ return await step();
224
+ }
225
+ catch (error) {
226
+ throw new Error(`${label} failed: ${redactNetworkErrorMessage(config, error)}`);
227
+ }
228
+ }
229
+ function redactNetworkErrorMessage(config, error) {
230
+ const raw = error instanceof Error ? error.message : String(error);
231
+ const withoutConfiguredRpc = config.rpcUrl ? raw.split(config.rpcUrl).join(redactRpcUrl(config.rpcUrl)) : raw;
232
+ return withoutConfiguredRpc.replace(/https?:\/\/[^\s)]+/gi, (match) => redactRpcUrl(match));
233
+ }
234
+ export function redactRpcUrl(value) {
235
+ try {
236
+ const parsed = new URL(value);
237
+ return `${parsed.protocol}//${parsed.host}/[redacted-url]`;
238
+ }
239
+ catch {
240
+ return '[redacted-rpc-url]';
241
+ }
242
+ }
243
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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"}