@deeeed/metamask-harness 0.35.0 → 0.37.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 +39 -0
- package/README.md +9 -1
- package/adapters/extension/artifact-runtime-state.cjs +128 -0
- package/adapters/extension/check-infura-readiness.cjs +102 -0
- package/adapters/extension/inject.mjs +2 -0
- package/adapters/extension/launch-browser.cjs +22 -0
- package/adapters/extension/live.sh +103 -18
- package/adapters/extension/readiness.mjs +77 -36
- package/adapters/extension/snapshot-dist.sh +88 -3
- package/adapters/extension/start-watch.sh +15 -0
- package/adapters/extension/verify.sh +6 -2
- package/adapters/extension/wallet-fixture-state.cjs +3 -1
- package/adapters/manifest.json +25 -1
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +73 -42
- package/adapters/mobile/reset-app-data.sh +154 -0
- package/adapters/shared/log-tui.mjs +1 -1
- package/dist/adapters/extension/artifact-integrity.js +38 -0
- package/dist/adapters/extension/extension-id.js +23 -4
- package/dist/adapters/extension/product-config.js +29 -1
- package/dist/adapters/extension/release-artifact.js +386 -0
- package/dist/adapters/extension/runtime-decision.js +161 -20
- package/dist/adapters/extension/runtime.js +127 -0
- package/dist/adapters/mobile/release-artifact-state.js +124 -0
- package/dist/adapters/mobile/release-artifact.js +295 -0
- package/dist/adapters.js +29 -4
- package/dist/cli-commands.js +1 -1
- package/dist/cli.js +2 -2
- package/dist/command-contract.js +17 -1
- package/dist/commands/call.js +2 -1
- package/dist/commands/device-target.js +5 -0
- package/dist/commands/fixtures.js +106 -31
- package/dist/commands/launch/extension.js +92 -7
- package/dist/commands/launch/index.js +13 -0
- package/dist/commands/launch/mobile.js +2 -0
- package/dist/commands/provision.js +2 -0
- package/dist/commands/run-engine.js +89 -5
- package/dist/commands/run.js +3 -1
- package/dist/commands/runtime-launch.js +178 -10
- package/dist/heal-bounds.js +1 -1
- package/dist/live-adapter-contract.js +3 -1
- package/dist/metamask-action-validation.js +47 -1
- package/dist/mm-harness-cli.js +37 -4
- package/dist/recipe-security.js +3 -0
- package/dist/run-diagnostics.js +1 -1
- package/docs/RECIPES.md +29 -0
- package/docs/RELEASE-QA-CAPABILITY-MAP.md +150 -0
- package/library/actions/extension/perps/perps.mjs +2 -0
- package/library/actions/extension/perps/read_snapshot.mjs +470 -0
- package/library/actions/extension/platform/cdp.mjs +6 -3
- package/library/actions/extension/wallet/import.mjs +201 -0
- package/library/actions/extension/wallet/reset.mjs +98 -0
- package/library/actions/extension/wallet/secret-input.mjs +98 -0
- package/library/actions/extension/wallet/state.mjs +1 -0
- package/library/actions/mobile/analytics/consent-settings.mjs +112 -0
- package/library/actions/mobile/analytics/set_consent.mjs +4 -112
- package/library/actions/mobile/platform/bridge.mjs +8 -0
- package/library/actions/mobile/platform/observe-ui.mjs +84 -2
- package/library/actions/mobile/ui/native-navigation.mjs +225 -0
- package/library/actions/mobile/ui/navigate.mjs +7 -0
- package/library/actions/mobile/wallet/import.mjs +328 -0
- package/library/actions/mobile/wallet/native-ui.mjs +493 -0
- package/library/actions/mobile/wallet/read_state.mjs +16 -0
- package/library/actions/mobile/wallet/reset-helper.mjs +99 -0
- package/library/actions/mobile/wallet/reset.mjs +20 -0
- package/library/actions/shared/ui/locators.mjs +7 -0
- package/library/actions/shared/wallet/import-source.mjs +101 -0
- package/library/manifests/extension.action-manifest.json +228 -0
- package/library/manifests/mobile.action-manifest.json +124 -0
- package/library/recipes/extension/runner/action-validation.recipe.json +12 -1
- package/library/recipes/wallet/import.recipe.json +102 -0
- package/library/recipes/wallet/reset-import.recipe.json +107 -0
- package/package.json +1 -1
- package/scripts/completions.sh +2 -2
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Reset one installed MetaMask Mobile app without rebuilding it.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
PLATFORM="${PLATFORM:-ios}"
|
|
6
|
+
TARGET="$PWD"
|
|
7
|
+
SIMULATOR="${SIM_UDID:-${IOS_SIMULATOR:-booted}}"
|
|
8
|
+
ADB_SERIAL_ARG="${ADB_SERIAL:-${ANDROID_SERIAL:-}}"
|
|
9
|
+
ADB_BIN="${MM_HARNESS_ADB_PATH:-}"
|
|
10
|
+
MM_RESET_TEMP_ROOT=""
|
|
11
|
+
MM_RESET_STAGING_DIR=""
|
|
12
|
+
|
|
13
|
+
while [ "$#" -gt 0 ]; do
|
|
14
|
+
case "$1" in
|
|
15
|
+
--platform) PLATFORM="$2"; shift 2 ;;
|
|
16
|
+
--target) TARGET="$2"; shift 2 ;;
|
|
17
|
+
--simulator) SIMULATOR="$2"; shift 2 ;;
|
|
18
|
+
--adb-serial) ADB_SERIAL_ARG="$2"; shift 2 ;;
|
|
19
|
+
-h|--help)
|
|
20
|
+
printf 'Usage: reset-app-data.sh --platform ios|android [--target <dir>] [--simulator <udid|name>] [--adb-serial <serial>]\n'
|
|
21
|
+
exit 0
|
|
22
|
+
;;
|
|
23
|
+
*) printf 'reset-app-data: unknown arg: %s\n' "$1" >&2; exit 2 ;;
|
|
24
|
+
esac
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
TARGET="$(cd "$TARGET" && pwd -P)"
|
|
28
|
+
|
|
29
|
+
reset_ios() {
|
|
30
|
+
local bundle_id="" app_source="" candidate="" staged_app=""
|
|
31
|
+
local temp_root="${TMPDIR:-/tmp}" staging_dir=""
|
|
32
|
+
local -a candidates installed_ids installed_paths
|
|
33
|
+
|
|
34
|
+
temp_root="${temp_root%/}"
|
|
35
|
+
[ -n "$temp_root" ] && [ "$temp_root" != "/" ] && [ -d "$temp_root" ] && [ ! -L "$temp_root" ] || {
|
|
36
|
+
printf 'reset-app-data: unsafe temporary directory: %s\n' "$temp_root" >&2
|
|
37
|
+
return 1
|
|
38
|
+
}
|
|
39
|
+
if [ -n "${IOS_BUNDLE_ID:-}" ]; then
|
|
40
|
+
candidates=("$IOS_BUNDLE_ID")
|
|
41
|
+
else
|
|
42
|
+
candidates=("io.metamask.MetaMask" "io.metamask" "io.metamask.MetaMask-Flask" "io.metamask.qa")
|
|
43
|
+
fi
|
|
44
|
+
for candidate in "${candidates[@]}"; do
|
|
45
|
+
if app_source="$(xcrun simctl get_app_container "$SIMULATOR" "$candidate" app 2>/dev/null)"; then
|
|
46
|
+
installed_ids+=("$candidate")
|
|
47
|
+
installed_paths+=("$app_source")
|
|
48
|
+
fi
|
|
49
|
+
done
|
|
50
|
+
if [ "${#installed_ids[@]}" -gt 1 ]; then
|
|
51
|
+
printf 'reset-app-data: multiple MetaMask iOS variants are installed on simulator %s: %s.\n' "$SIMULATOR" "${installed_ids[*]}" >&2
|
|
52
|
+
printf 'Next: set IOS_BUNDLE_ID to the exact variant and retry.\n' >&2
|
|
53
|
+
return 1
|
|
54
|
+
fi
|
|
55
|
+
bundle_id="${installed_ids[0]:-}"
|
|
56
|
+
app_source="${installed_paths[0]:-}"
|
|
57
|
+
[ -n "$bundle_id" ] && [ -n "$app_source" ] || {
|
|
58
|
+
printf 'reset-app-data: no installed MetaMask app was found on iOS simulator %s.\n' "$SIMULATOR" >&2
|
|
59
|
+
printf "Next: mm-harness launch --adapter mobile --platform ios --target '%s'\n" "$TARGET" >&2
|
|
60
|
+
return 1
|
|
61
|
+
}
|
|
62
|
+
case "$app_source" in
|
|
63
|
+
*/Library/Developer/CoreSimulator/Devices/*/data/Containers/Bundle/Application/*/*.app) ;;
|
|
64
|
+
*) printf 'reset-app-data: refusing unexpected iOS app path: %s\n' "$app_source" >&2; return 1 ;;
|
|
65
|
+
esac
|
|
66
|
+
[ -d "$app_source" ] && [ ! -L "$app_source" ] || {
|
|
67
|
+
printf 'reset-app-data: iOS app is not a real directory: %s\n' "$app_source" >&2
|
|
68
|
+
return 1
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
staging_dir="$(mktemp -d "$temp_root/mm-harness-ios-reset.XXXXXX")"
|
|
72
|
+
case "$staging_dir" in
|
|
73
|
+
"$temp_root"/mm-harness-ios-reset.*) ;;
|
|
74
|
+
*) printf 'reset-app-data: refusing unexpected staging path: %s\n' "$staging_dir" >&2; return 1 ;;
|
|
75
|
+
esac
|
|
76
|
+
[ -d "$staging_dir" ] && [ ! -L "$staging_dir" ] || return 1
|
|
77
|
+
staged_app="$staging_dir/$(basename "$app_source")"
|
|
78
|
+
MM_RESET_TEMP_ROOT="$temp_root"
|
|
79
|
+
MM_RESET_STAGING_DIR="$staging_dir"
|
|
80
|
+
cleanup_staging() {
|
|
81
|
+
case "$MM_RESET_STAGING_DIR" in
|
|
82
|
+
"$MM_RESET_TEMP_ROOT"/mm-harness-ios-reset.*)
|
|
83
|
+
[ -d "$MM_RESET_STAGING_DIR" ] && [ ! -L "$MM_RESET_STAGING_DIR" ] && rm -r -- "$MM_RESET_STAGING_DIR"
|
|
84
|
+
;;
|
|
85
|
+
*) printf 'reset-app-data: staging cleanup refused: %s\n' "$MM_RESET_STAGING_DIR" >&2 ;;
|
|
86
|
+
esac
|
|
87
|
+
}
|
|
88
|
+
trap cleanup_staging EXIT HUP INT TERM
|
|
89
|
+
|
|
90
|
+
ditto "$app_source" "$staged_app"
|
|
91
|
+
[ -d "$staged_app" ] && [ ! -L "$staged_app" ] || {
|
|
92
|
+
printf 'reset-app-data: failed to preserve the installed iOS app.\n' >&2
|
|
93
|
+
return 1
|
|
94
|
+
}
|
|
95
|
+
printf 'Resetting iOS app data: simulator=%s bundle=%s\n' "$SIMULATOR" "$bundle_id" >&2
|
|
96
|
+
xcrun simctl terminate "$SIMULATOR" "$bundle_id" >/dev/null 2>&1 || true
|
|
97
|
+
xcrun simctl uninstall "$SIMULATOR" "$bundle_id"
|
|
98
|
+
xcrun simctl install "$SIMULATOR" "$staged_app"
|
|
99
|
+
xcrun simctl get_app_container "$SIMULATOR" "$bundle_id" app >/dev/null
|
|
100
|
+
printf 'Mobile app data reset; preserved installed iOS build %s.\n' "$bundle_id" >&2
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
reset_android() {
|
|
104
|
+
local package_id="" candidate="" clear_output=""
|
|
105
|
+
local -a candidates adb_target installed_ids
|
|
106
|
+
if [ -z "$ADB_BIN" ]; then
|
|
107
|
+
ADB_BIN="$(command -v adb 2>/dev/null || true)"
|
|
108
|
+
fi
|
|
109
|
+
[ -n "$ADB_BIN" ] && [ "${ADB_BIN#/}" != "$ADB_BIN" ] && [ -x "$ADB_BIN" ] || {
|
|
110
|
+
printf 'reset-app-data: Android SDK Platform-Tools (adb) is required.\n' >&2
|
|
111
|
+
printf 'Next: brew install android-platform-tools\n' >&2
|
|
112
|
+
return 1
|
|
113
|
+
}
|
|
114
|
+
[ -n "$ADB_SERIAL_ARG" ] || {
|
|
115
|
+
printf 'reset-app-data: an Android serial is required.\n' >&2
|
|
116
|
+
printf 'Next: mm-harness devices --adapter mobile --json\n' >&2
|
|
117
|
+
return 1
|
|
118
|
+
}
|
|
119
|
+
adb_target=(-s "$ADB_SERIAL_ARG")
|
|
120
|
+
if [ -n "${ANDROID_PACKAGE_ID:-}" ]; then
|
|
121
|
+
candidates=("$ANDROID_PACKAGE_ID")
|
|
122
|
+
else
|
|
123
|
+
candidates=("io.metamask" "io.metamask.flask" "io.metamask.qa")
|
|
124
|
+
fi
|
|
125
|
+
for candidate in "${candidates[@]}"; do
|
|
126
|
+
if "$ADB_BIN" "${adb_target[@]}" shell pm path "$candidate" 2>/dev/null | grep -q '^package:'; then
|
|
127
|
+
installed_ids+=("$candidate")
|
|
128
|
+
fi
|
|
129
|
+
done
|
|
130
|
+
if [ "${#installed_ids[@]}" -gt 1 ]; then
|
|
131
|
+
printf 'reset-app-data: multiple MetaMask Android variants are installed on device %s: %s.\n' "$ADB_SERIAL_ARG" "${installed_ids[*]}" >&2
|
|
132
|
+
printf 'Next: set ANDROID_PACKAGE_ID to the exact variant and retry.\n' >&2
|
|
133
|
+
return 1
|
|
134
|
+
fi
|
|
135
|
+
package_id="${installed_ids[0]:-}"
|
|
136
|
+
[ -n "$package_id" ] || {
|
|
137
|
+
printf 'reset-app-data: no installed MetaMask app was found on Android device %s.\n' "$ADB_SERIAL_ARG" >&2
|
|
138
|
+
printf "Next: mm-harness launch --adapter mobile --platform android --target '%s' --device '%s'\n" "$TARGET" "$ADB_SERIAL_ARG" >&2
|
|
139
|
+
return 1
|
|
140
|
+
}
|
|
141
|
+
printf 'Resetting Android app data: device=%s package=%s\n' "$ADB_SERIAL_ARG" "$package_id" >&2
|
|
142
|
+
clear_output="$("$ADB_BIN" "${adb_target[@]}" shell pm clear "$package_id")"
|
|
143
|
+
[ "$clear_output" = "Success" ] || {
|
|
144
|
+
printf 'reset-app-data: Android package clear failed: %s\n' "$clear_output" >&2
|
|
145
|
+
return 1
|
|
146
|
+
}
|
|
147
|
+
printf 'Mobile app data reset; preserved installed Android build %s.\n' "$package_id" >&2
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
case "$PLATFORM" in
|
|
151
|
+
ios) reset_ios ;;
|
|
152
|
+
android) reset_android ;;
|
|
153
|
+
*) printf 'reset-app-data: --platform must be ios or android (got: %s)\n' "$PLATFORM" >&2; exit 2 ;;
|
|
154
|
+
esac
|
|
@@ -236,7 +236,7 @@ async function watchLog(options) {
|
|
|
236
236
|
renderCompact({ label, logPath, events, quiet: mode === 'quiet' });
|
|
237
237
|
if (mode !== 'quiet') {
|
|
238
238
|
const elapsed = Math.round((Date.now() - started) / 1000);
|
|
239
|
-
process.stderr.write(`${color('label', 'mm-harness', { stream: process.stderr })} ${color('dim', '|', { stream: process.stderr })} ${color('ok',
|
|
239
|
+
process.stderr.write(`${color('label', 'mm-harness', { stream: process.stderr })} ${color('dim', '|', { stream: process.stderr })} ${color('ok', `${label} complete (${elapsed}s)`, { stream: process.stderr })}\n`);
|
|
240
240
|
}
|
|
241
241
|
return 0;
|
|
242
242
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
function extensionTreeSha256(root) {
|
|
5
|
+
const resolvedRoot = path.resolve(root);
|
|
6
|
+
const rootStat = fs.lstatSync(resolvedRoot);
|
|
7
|
+
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
8
|
+
throw new Error(`Extension artifact root must be a regular directory: ${resolvedRoot}`);
|
|
9
|
+
}
|
|
10
|
+
const digest = createHash("sha256");
|
|
11
|
+
walk(resolvedRoot, "");
|
|
12
|
+
return digest.digest("hex");
|
|
13
|
+
function walk(directory, relativeDirectory) {
|
|
14
|
+
const entries = fs.readdirSync(directory, { withFileTypes: true }).sort((left, right) => Buffer.compare(Buffer.from(left.name), Buffer.from(right.name)));
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const absolute = path.join(directory, entry.name);
|
|
17
|
+
const relative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
|
|
18
|
+
const stat = fs.lstatSync(absolute);
|
|
19
|
+
if (stat.isSymbolicLink()) {
|
|
20
|
+
throw new Error(`Extension artifact tree contains a symbolic link: ${relative}`);
|
|
21
|
+
}
|
|
22
|
+
if (stat.isDirectory()) {
|
|
23
|
+
digest.update(`directory\0${relative}\0`);
|
|
24
|
+
walk(absolute, relative);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (!stat.isFile()) {
|
|
28
|
+
throw new Error(`Extension artifact tree contains an unsupported entry: ${relative}`);
|
|
29
|
+
}
|
|
30
|
+
digest.update(`file\0${relative}\0${stat.size}\0`);
|
|
31
|
+
digest.update(fs.readFileSync(absolute));
|
|
32
|
+
digest.update("\0");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
extensionTreeSha256
|
|
38
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { recipeRuntimeDir } from "../../paths.js";
|
|
5
|
+
import { releaseArtifactState, runtimeDistCheck } from "./runtime-decision.js";
|
|
4
6
|
const DIST_MANIFEST = "dist/chrome/manifest.json";
|
|
5
7
|
function extensionIdFromKey(keyBase64) {
|
|
6
8
|
const der = Buffer.from(keyBase64, "base64");
|
|
@@ -12,8 +14,8 @@ function extensionIdFromKey(keyBase64) {
|
|
|
12
14
|
}
|
|
13
15
|
return id;
|
|
14
16
|
}
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
+
function idFromManifest(manifestPath) {
|
|
18
|
+
if (!manifestPath) return null;
|
|
17
19
|
if (!fs.existsSync(manifestPath)) return null;
|
|
18
20
|
try {
|
|
19
21
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
@@ -39,7 +41,24 @@ async function cdpExtensionIds(cdpPort) {
|
|
|
39
41
|
}
|
|
40
42
|
async function resolveExtensionId(target, options = {}) {
|
|
41
43
|
const resolved = path.resolve(target);
|
|
42
|
-
const
|
|
44
|
+
const runtimeSnapshot = runtimeDistCheck(resolved, releaseArtifactState(resolved));
|
|
45
|
+
const releaseArtifact = runtimeSnapshot.source === "release-artifact";
|
|
46
|
+
if (releaseArtifact && runtimeSnapshot.status !== "fresh") {
|
|
47
|
+
return {
|
|
48
|
+
adapter: "extension",
|
|
49
|
+
target: resolved,
|
|
50
|
+
extensionId: null,
|
|
51
|
+
source: "none",
|
|
52
|
+
verified: false
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const manifestPath = releaseArtifact ? runtimeSnapshot.status === "fresh" ? path.join(
|
|
56
|
+
resolved,
|
|
57
|
+
recipeRuntimeDir(),
|
|
58
|
+
process.env.RECIPE_RUNTIME_DIST_DIR || "runtime-dist",
|
|
59
|
+
"manifest.json"
|
|
60
|
+
) : null : path.join(resolved, DIST_MANIFEST);
|
|
61
|
+
const fromKey = idFromManifest(manifestPath);
|
|
43
62
|
let cdpIds = null;
|
|
44
63
|
if (options.cdpPort) cdpIds = await cdpExtensionIds(options.cdpPort);
|
|
45
64
|
if (fromKey) {
|
|
@@ -47,7 +66,7 @@ async function resolveExtensionId(target, options = {}) {
|
|
|
47
66
|
adapter: "extension",
|
|
48
67
|
target: resolved,
|
|
49
68
|
extensionId: fromKey,
|
|
50
|
-
source: "manifest-key",
|
|
69
|
+
source: releaseArtifact ? "release-manifest-key" : "manifest-key",
|
|
51
70
|
verified: cdpIds ? cdpIds.includes(fromKey) : null
|
|
52
71
|
};
|
|
53
72
|
}
|
|
@@ -1,6 +1,31 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
1
3
|
import path from "node:path";
|
|
2
4
|
import productConfig from "../../../adapters/extension/lib/product-config.cjs";
|
|
3
5
|
import { shellQuote } from "../../commands/parse-args.js";
|
|
6
|
+
const EXTENSION_PRODUCT_CONFIG_FINGERPRINT_FILENAME = "extension-product-config.sha256";
|
|
7
|
+
function extensionProductConfigFingerprint(target, environment = process.env) {
|
|
8
|
+
const resolution = productConfig.resolveExtensionInfuraProjectId(target, environment);
|
|
9
|
+
if (resolution.kind !== "configured") return null;
|
|
10
|
+
return createHash("sha256").update(resolution.value).digest("hex");
|
|
11
|
+
}
|
|
12
|
+
function extensionCompiledScriptsMatchProductConfig(target, dist, environment = process.env) {
|
|
13
|
+
const resolution = productConfig.resolveExtensionInfuraProjectId(target, environment);
|
|
14
|
+
if (resolution.kind !== "configured") return true;
|
|
15
|
+
const pending = [dist];
|
|
16
|
+
while (pending.length > 0) {
|
|
17
|
+
const current = pending.pop();
|
|
18
|
+
if (!current || !fs.existsSync(current)) continue;
|
|
19
|
+
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
|
|
20
|
+
const file = path.join(current, entry.name);
|
|
21
|
+
if (entry.isDirectory()) pending.push(file);
|
|
22
|
+
else if (entry.isFile() && entry.name.endsWith(".js") && fs.readFileSync(file, "utf8").includes(resolution.value)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
4
29
|
function extensionProductConfigBlock(target) {
|
|
5
30
|
const resolution = productConfig.resolveExtensionInfuraProjectId(
|
|
6
31
|
target,
|
|
@@ -55,5 +80,8 @@ function invalidConfigBlock(target, name, reason) {
|
|
|
55
80
|
};
|
|
56
81
|
}
|
|
57
82
|
export {
|
|
58
|
-
|
|
83
|
+
EXTENSION_PRODUCT_CONFIG_FINGERPRINT_FILENAME,
|
|
84
|
+
extensionCompiledScriptsMatchProductConfig,
|
|
85
|
+
extensionProductConfigBlock,
|
|
86
|
+
extensionProductConfigFingerprint
|
|
59
87
|
};
|