@deeeed/metamask-harness 0.94.3 → 0.94.5
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
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.94.5 - 2026-10-28
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Extension readiness uses the registered EVM background action and preserves its result when the optional Perps read times out, keeping genuine RPC failures fatal.
|
|
10
|
+
|
|
11
|
+
## 0.94.4 - 2026-10-27
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Shorten Extension testnet action descriptions while preserving mainnet guards.
|
|
16
|
+
|
|
5
17
|
## 0.94.3 - 2026-10-25
|
|
6
18
|
|
|
7
19
|
### Fixed
|
|
@@ -328,7 +328,7 @@ async function boundedCdpCall(session, method, params, timeoutMs) {
|
|
|
328
328
|
async function evaluateHealth(session, timeoutMs) {
|
|
329
329
|
const backgroundProbeTimeoutMs = extensionBackgroundProbeTimeoutMs(timeoutMs);
|
|
330
330
|
const result = await boundedCdpCall(session, "Runtime.evaluate", {
|
|
331
|
-
expression: `(() => {
|
|
331
|
+
expression: `(async () => {
|
|
332
332
|
const hooks = globalThis.stateHooks || {};
|
|
333
333
|
const bodyText = document.body?.innerText || '';
|
|
334
334
|
const storeState = hooks.store?.getState?.() || {};
|
|
@@ -336,78 +336,80 @@ async function evaluateHealth(session, timeoutMs) {
|
|
|
336
336
|
const accountCache = manager?.account?.cache;
|
|
337
337
|
const networkConnectionBanner = storeState.metamask?.networkConnectionBanner;
|
|
338
338
|
const networkClientId = storeState.metamask?.selectedNetworkClientId || networkConnectionBanner?.networkClientId;
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const accountState = await hooks.submitRequestToBackground('perpsGetAccountState', []);
|
|
348
|
-
const ok = Boolean(accountState && typeof accountState === 'object');
|
|
349
|
-
return { ok, error: ok ? null : 'perpsGetAccountState returned an empty result' };
|
|
350
|
-
} catch (error) {
|
|
351
|
-
return { ok: false, error: String(error?.message || error) };
|
|
352
|
-
}
|
|
353
|
-
})(),
|
|
354
|
-
(async () => {
|
|
355
|
-
if (typeof hooks.submitRequestToBackground !== 'function') {
|
|
356
|
-
return { ok: false, error: 'submitRequestToBackground is not a function' };
|
|
357
|
-
}
|
|
358
|
-
if (typeof networkClientId !== 'string' || networkClientId.length === 0) {
|
|
359
|
-
return { ok: false, error: 'selected EVM network client is unavailable' };
|
|
360
|
-
}
|
|
361
|
-
try {
|
|
362
|
-
const code = await hooks.submitRequestToBackground('getCode', [
|
|
363
|
-
'0x0000000000000000000000000000000000000000',
|
|
364
|
-
networkClientId,
|
|
365
|
-
]);
|
|
366
|
-
const ok = typeof code === 'string' && code.startsWith('0x');
|
|
367
|
-
return { ok, error: ok ? null : 'background EVM RPC returned an invalid result' };
|
|
368
|
-
} catch (error) {
|
|
369
|
-
return { ok: false, error: String(error?.message || error) };
|
|
370
|
-
}
|
|
371
|
-
})(),
|
|
339
|
+
async function withDeadline(read, error) {
|
|
340
|
+
let timer;
|
|
341
|
+
try {
|
|
342
|
+
return await Promise.race([
|
|
343
|
+
read,
|
|
344
|
+
new Promise((resolve) => {
|
|
345
|
+
timer = setTimeout(() => resolve({ ok: false, error }), ${backgroundProbeTimeoutMs});
|
|
346
|
+
}),
|
|
372
347
|
]);
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
348
|
+
} finally {
|
|
349
|
+
clearTimeout(timer);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const [backgroundProbe, evmRpcProbe] = await Promise.all([
|
|
353
|
+
withDeadline((async () => {
|
|
354
|
+
if (typeof hooks.submitRequestToBackground !== 'function') {
|
|
355
|
+
return { ok: false, error: 'submitRequestToBackground is not a function' };
|
|
356
|
+
}
|
|
357
|
+
try {
|
|
358
|
+
const accountState = await hooks.submitRequestToBackground('perpsGetAccountState', []);
|
|
359
|
+
const ok = Boolean(accountState && typeof accountState === 'object');
|
|
360
|
+
return { ok, error: ok ? null : 'perpsGetAccountState returned an empty result' };
|
|
361
|
+
} catch (error) {
|
|
362
|
+
return { ok: false, error: String(error?.message || error) };
|
|
363
|
+
}
|
|
364
|
+
})(), 'perpsGetAccountState timed out after ${backgroundProbeTimeoutMs}ms'),
|
|
365
|
+
withDeadline((async () => {
|
|
366
|
+
if (typeof hooks.submitRequestToBackground !== 'function') {
|
|
367
|
+
return { ok: false, error: 'submitRequestToBackground is not a function' };
|
|
368
|
+
}
|
|
369
|
+
if (typeof networkClientId !== 'string' || networkClientId.length === 0) {
|
|
370
|
+
return { ok: false, error: 'selected EVM network client is unavailable' };
|
|
371
|
+
}
|
|
372
|
+
try {
|
|
373
|
+
const args = ['0x0000000000000000000000000000000000000000', networkClientId];
|
|
374
|
+
let code;
|
|
375
|
+
try {
|
|
376
|
+
code = await hooks.submitRequestToBackground('messengerCall', ['LegacyBackgroundApiService:getCode', args]);
|
|
377
|
+
} catch (error) {
|
|
378
|
+
// Older builds may lack the messenger API or its EVM action.
|
|
379
|
+
const message = String(error?.message || error);
|
|
380
|
+
const missingApi = error?.code === -32601 && message === 'messengerCall not found';
|
|
381
|
+
const missingAction = message.includes('A handler for LegacyBackgroundApiService:getCode has not been registered');
|
|
382
|
+
if (!missingApi && !missingAction) throw error;
|
|
383
|
+
code = await hooks.submitRequestToBackground('getCode', args);
|
|
384
|
+
}
|
|
385
|
+
const ok = typeof code === 'string' && code.startsWith('0x');
|
|
386
|
+
return { ok, error: ok ? null : 'background EVM RPC returned an invalid result' };
|
|
387
|
+
} catch (error) {
|
|
388
|
+
return { ok: false, error: String(error?.message || error) };
|
|
389
|
+
}
|
|
390
|
+
})(), 'background EVM RPC timed out after ${backgroundProbeTimeoutMs}ms'),
|
|
410
391
|
]);
|
|
392
|
+
return {
|
|
393
|
+
href: location.href,
|
|
394
|
+
title: document.title,
|
|
395
|
+
hasPageContent: bodyText.trim().length > 0,
|
|
396
|
+
hookKeys: Object.keys(hooks),
|
|
397
|
+
hasSubmitRequest: typeof hooks.submitRequestToBackground === 'function',
|
|
398
|
+
hasStore: Boolean(hooks.store),
|
|
399
|
+
hasPerpsStreamManager: typeof hooks.getPerpsStreamManager === 'function',
|
|
400
|
+
backgroundUnresponsive: bodyText.includes('Background connection unresponsive') || bodyText.includes('MetaMask had trouble starting'),
|
|
401
|
+
ethereumConnectionUnavailable: bodyText.includes('Unable to connect to Ethereum'),
|
|
402
|
+
activeProvider: storeState.metamask?.activeProvider || null,
|
|
403
|
+
isTestnet: Boolean(storeState.metamask?.isTestnet),
|
|
404
|
+
perpsManagerInitialized: Boolean(manager?.isInitialized?.()),
|
|
405
|
+
positionsCacheIsArray: Array.isArray(manager?.positions?.cache),
|
|
406
|
+
ordersCacheIsArray: Array.isArray(manager?.orders?.cache),
|
|
407
|
+
accountCachePresent: Boolean(accountCache && typeof accountCache === 'object'),
|
|
408
|
+
backgroundProbeOk: backgroundProbe.ok,
|
|
409
|
+
backgroundProbeError: backgroundProbe.error,
|
|
410
|
+
evmRpcProbeOk: evmRpcProbe.ok,
|
|
411
|
+
evmRpcProbeError: evmRpcProbe.error,
|
|
412
|
+
};
|
|
411
413
|
})()`,
|
|
412
414
|
awaitPromise: true,
|
|
413
415
|
returnByValue: true
|
|
@@ -4138,7 +4138,7 @@
|
|
|
4138
4138
|
"execution_capabilities": []
|
|
4139
4139
|
},
|
|
4140
4140
|
"metamask.perps.close_orders": {
|
|
4141
|
-
"description": "extension Cancel selected live Perps open orders. Use selector/mode params to cancel matching symbols or all orders. On mainnet, the fixture-policy lane cancels only orders this run placed
|
|
4141
|
+
"description": "extension Cancel selected live Perps open orders. Use selector/mode params to cancel matching symbols or all orders. On mainnet, the fixture-policy lane cancels only orders this run placed.",
|
|
4142
4142
|
"schema": {
|
|
4143
4143
|
"type": "object",
|
|
4144
4144
|
"properties": {
|
|
@@ -4719,7 +4719,7 @@
|
|
|
4719
4719
|
"execution_capabilities": []
|
|
4720
4720
|
},
|
|
4721
4721
|
"metamask.perps.ensure_positions": {
|
|
4722
|
-
"description": "Read and assert the selected Extension Perps position state without creating or closing a position.
|
|
4722
|
+
"description": "Read and assert the selected Extension Perps position state without creating or closing a position. Mainnet is never mutated.",
|
|
4723
4723
|
"schema": {
|
|
4724
4724
|
"type": "object",
|
|
4725
4725
|
"properties": {
|
|
@@ -4848,7 +4848,7 @@
|
|
|
4848
4848
|
]
|
|
4849
4849
|
},
|
|
4850
4850
|
"metamask.perps.ensure_orders": {
|
|
4851
|
-
"description": "Read and assert the selected Extension Perps order state without creating or canceling an order.
|
|
4851
|
+
"description": "Read and assert the selected Extension Perps order state without creating or canceling an order. Mainnet is never mutated.",
|
|
4852
4852
|
"schema": {
|
|
4853
4853
|
"type": "object",
|
|
4854
4854
|
"properties": {
|