@deeeed/metamask-harness 0.34.0 → 0.34.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.
@@ -39,7 +39,30 @@ function routeName(status, input) {
39
39
  const selectedStatus = selectBridgeStatusEntry;
40
40
 
41
41
  async function status(input) {
42
- return bridgeCommand(input, ['status']);
42
+ return bridgeCommand(input, ['status-selected']);
43
+ }
44
+
45
+ async function statusBeforeDeadline(input, deadline) {
46
+ const remainingMs = Math.max(1, deadline - Date.now());
47
+ const configuredMs = Number(
48
+ input.node?.bridge_timeout_ms ??
49
+ input.node?.cdp_timeout_ms ??
50
+ process.env.CDP_TIMEOUT ??
51
+ 30000,
52
+ );
53
+ const probeTimeoutMs = Math.min(
54
+ 5000,
55
+ remainingMs,
56
+ Number.isFinite(configuredMs) && configuredMs > 0 ? configuredMs : 30000,
57
+ );
58
+ return status({
59
+ ...input,
60
+ node: {
61
+ ...input.node,
62
+ bridge_timeout_ms: probeTimeoutMs,
63
+ cdp_timeout_ms: probeTimeoutMs,
64
+ },
65
+ });
43
66
  }
44
67
 
45
68
  async function waitForTargetStatus(input, timeoutMs = 20000) {
@@ -48,7 +71,7 @@ async function waitForTargetStatus(input, timeoutMs = 20000) {
48
71
  let lastError = null;
49
72
  while (Date.now() < deadline) {
50
73
  try {
51
- last = await status(input);
74
+ last = await statusBeforeDeadline(input, deadline);
52
75
  const selected = selectedStatus(last, input);
53
76
  if (selected?.agenticPresent === true) return last;
54
77
  } catch (error) {
@@ -69,7 +92,7 @@ async function waitForWalletState(input, initialStatus, timeoutMs) {
69
92
  if (Date.now() >= deadline) break;
70
93
  await new Promise((resolve) => setTimeout(resolve, 250));
71
94
  try {
72
- last = await status(input);
95
+ last = await statusBeforeDeadline(input, deadline);
73
96
  } catch {
74
97
  // A rotating Hermes target during startup is transient. The target timeout
75
98
  // still bounds this loop and the final error reports the last wallet state.
@@ -80,13 +103,13 @@ async function waitForWalletState(input, initialStatus, timeoutMs) {
80
103
  );
81
104
  }
82
105
 
83
- async function waitForUnlocked(input, timeoutMs = 15000) {
106
+ async function waitForUnlocked(input, timeoutMs = 30000) {
84
107
  const deadline = Date.now() + timeoutMs;
85
108
  let last = null;
86
109
  let lastError = null;
87
110
  while (Date.now() < deadline) {
88
111
  try {
89
- last = await status(input);
112
+ last = await statusBeforeDeadline(input, deadline);
90
113
  if (selectedAccount(last, input) && routeName(last, input) !== 'Login') return last;
91
114
  } catch (error) {
92
115
  lastError = error;
@@ -108,7 +131,7 @@ async function waitForStableUnlocked(input, initialStatus, stableMs = 750) {
108
131
  while (Date.now() < deadline) {
109
132
  await new Promise((resolve) => setTimeout(resolve, 250));
110
133
  try {
111
- last = await status(input);
134
+ last = await statusBeforeDeadline(input, deadline);
112
135
  if (!isUnlockedStatus(last, input)) {
113
136
  if (routeName(last, input) === 'Login') return null;
114
137
  transientDrops += 1;
@@ -152,7 +175,7 @@ export async function ensureUnlocked(input) {
152
175
  const password = input.node?.password ?? await fixturePassword(input.context.projectRoot);
153
176
  try {
154
177
  const result = await bridgeCommand(input, ['unlock', String(password)]);
155
- const after = await waitForUnlocked(input, Number(input.node?.unlock_timeout_ms ?? 15000));
178
+ const after = await waitForUnlocked(input, Number(input.node?.unlock_timeout_ms ?? 30000));
156
179
  const stableAfter = await waitForStableUnlocked(input, after, Number(input.node?.stable_unlocked_ms ?? 750)) ?? after;
157
180
  return {
158
181
  action: input.action,
@@ -2489,6 +2489,24 @@
2489
2489
  "items": {
2490
2490
  "type": "string"
2491
2491
  }
2492
+ },
2493
+ "first_fresh_delivery_requirements": {
2494
+ "type": "array",
2495
+ "items": {
2496
+ "type": "object",
2497
+ "properties": {
2498
+ "stream": { "type": "string" },
2499
+ "lifecycle": { "type": "string" },
2500
+ "subscriber_throttle_ms": { "type": "number", "minimum": 0 },
2501
+ "max_socket_to_subscriber_ms": { "type": "number", "minimum": 0 }
2502
+ },
2503
+ "required": [
2504
+ "stream",
2505
+ "subscriber_throttle_ms",
2506
+ "max_socket_to_subscriber_ms"
2507
+ ],
2508
+ "additionalProperties": false
2509
+ }
2492
2510
  }
2493
2511
  },
2494
2512
  "required": ["phase"],
@@ -57,6 +57,8 @@
57
57
  },
58
58
  "unlock-after-restart": {
59
59
  "action": "metamask.wallet.ensure_unlocked",
60
+ "target_timeout_ms": 90000,
61
+ "unlock_timeout_ms": 90000,
60
62
  "intent": "Restore the fixture wallet after the cold process launch",
61
63
  "next": "open-wallet-home-after"
62
64
  },
@@ -108,17 +110,33 @@
108
110
  "finish-performance-capture": {
109
111
  "action": "metamask.perps.capture_performance",
110
112
  "phase": "end",
113
+ "artifact_prefix": "logs/homepage-order-cold-disk-cache",
111
114
  "required_stages": [
112
115
  "disk_cache_hydrated",
113
116
  "viewport_demand",
114
117
  "socket_received",
118
+ "subscriber_delivery",
115
119
  "react_commit",
116
120
  "next_frame_checkpoint"
117
121
  ],
118
122
  "required_lifecycles": ["cold_disk_cache"],
119
- "required_sources": ["disk_cache", "fresh_socket"],
123
+ "required_sources": ["fresh_socket"],
120
124
  "required_fresh_content_variants": ["orders"],
121
- "intent": "Preserve and validate the cold disk-cache measurement cohort",
125
+ "first_fresh_delivery_requirements": [
126
+ {
127
+ "stream": "positions",
128
+ "lifecycle": "cold_disk_cache",
129
+ "subscriber_throttle_ms": 5000,
130
+ "max_socket_to_subscriber_ms": 1000
131
+ },
132
+ {
133
+ "stream": "orders",
134
+ "lifecycle": "cold_disk_cache",
135
+ "subscriber_throttle_ms": 5000,
136
+ "max_socket_to_subscriber_ms": 1000
137
+ }
138
+ ],
139
+ "intent": "Require cache hydration, fresh visible order content, and immediate first-fresh positions/orders delivery",
122
140
  "next": "cleanup-order"
123
141
  },
124
142
  "cleanup-order": {
@@ -48,6 +48,8 @@
48
48
  },
49
49
  "unlock-wallet": {
50
50
  "action": "metamask.wallet.ensure_unlocked",
51
+ "target_timeout_ms": 90000,
52
+ "unlock_timeout_ms": 90000,
51
53
  "intent": "Unlock the fixture wallet after the cold process launch",
52
54
  "next": "open-wallet-home"
53
55
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.34.0",
3
+ "version": "0.34.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -1,93 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const { createRequire } = require('node:module');
5
- const path = require('node:path');
6
- const { pathToFileURL } = require('node:url');
7
-
8
- function escapeRegExp(value) {
9
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
10
- }
11
-
12
- function appendBlockList(blockList, pattern) {
13
- if (Array.isArray(blockList)) return [...blockList, pattern];
14
- return blockList instanceof RegExp ? [blockList, pattern] : [pattern];
15
- }
16
-
17
- function blockListFlags(blockList) {
18
- const first = Array.isArray(blockList) ? blockList[0] : blockList;
19
- return first instanceof RegExp ? first.flags : '';
20
- }
21
-
22
- function resolveExpoConfigLoader(projectRoot) {
23
- const requireFromProject = createRequire(path.join(projectRoot, 'package.json'));
24
- let requireUtilsPath;
25
- try {
26
- requireUtilsPath = requireFromProject.resolve('@expo/require-utils');
27
- } catch (error) {
28
- if (error?.code !== 'MODULE_NOT_FOUND') throw error;
29
- return null;
30
- }
31
- const { loadModuleSync } = requireFromProject(requireUtilsPath);
32
- return typeof loadModuleSync === 'function' ? loadModuleSync : null;
33
- }
34
-
35
- async function loadProductConfig(configPath, baseConfig, projectRoot) {
36
- let loaded;
37
- const expoConfigLoader = resolveExpoConfigLoader(projectRoot);
38
- if (expoConfigLoader) {
39
- loaded = expoConfigLoader(configPath);
40
- } else {
41
- try {
42
- loaded = require(configPath);
43
- } catch (error) {
44
- if (error?.code !== 'ERR_REQUIRE_ESM') throw error;
45
- loaded = await import(pathToFileURL(configPath).href);
46
- }
47
- }
48
-
49
- const moduleValue = await loaded;
50
- const exported =
51
- moduleValue?.__esModule ||
52
- moduleValue?.[Symbol.toStringTag] === 'Module'
53
- ? moduleValue.default
54
- : moduleValue;
55
- const config = await exported;
56
- return typeof config === 'function' ? config(baseConfig) : config;
57
- }
58
-
59
- module.exports = async function harnessMetroConfig(baseConfig) {
60
- const projectRoot = path.resolve(
61
- process.env.MM_HARNESS_METRO_PROJECT_ROOT || process.cwd(),
62
- );
63
- const productConfigPath = path.resolve(
64
- process.env.MM_HARNESS_METRO_BASE_CONFIG ||
65
- path.join(projectRoot, 'metro.config.js'),
66
- );
67
- let productConfig = baseConfig;
68
- if (fs.existsSync(productConfigPath)) {
69
- productConfig = await loadProductConfig(
70
- productConfigPath,
71
- baseConfig,
72
- projectRoot,
73
- );
74
- }
75
-
76
- const tempRoot = path.join(projectRoot, 'temp');
77
- const existingBlockList =
78
- productConfig.resolver?.blockList ?? baseConfig.resolver?.blockList;
79
- const tempPattern = new RegExp(
80
- `^${escapeRegExp(tempRoot)}(?:${escapeRegExp(path.sep)}|$)`,
81
- blockListFlags(existingBlockList),
82
- );
83
- return {
84
- ...productConfig,
85
- resolver: {
86
- ...productConfig.resolver,
87
- blockList: appendBlockList(
88
- existingBlockList,
89
- tempPattern,
90
- ),
91
- },
92
- };
93
- };