mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 01:39:44 +01:00
Merge pull request #14143 from MetaMask/Version-v10.11.4
Version v10.11.4 RC
This commit is contained in:
commit
48fa62f42a
@ -53,6 +53,9 @@ workflows:
|
||||
- prep-build-test:
|
||||
requires:
|
||||
- prep-deps
|
||||
- prep-build-test-flask:
|
||||
requires:
|
||||
- prep-deps
|
||||
- prep-build-test-metrics:
|
||||
requires:
|
||||
- prep-deps
|
||||
@ -78,6 +81,12 @@ workflows:
|
||||
- test-e2e-firefox:
|
||||
requires:
|
||||
- prep-build-test
|
||||
- test-e2e-chrome-snaps:
|
||||
requires:
|
||||
- prep-build-test-flask
|
||||
- test-e2e-firefox-snaps:
|
||||
requires:
|
||||
- prep-build-test-flask
|
||||
- test-e2e-chrome-metrics:
|
||||
requires:
|
||||
- prep-build-test-metrics
|
||||
@ -130,6 +139,8 @@ workflows:
|
||||
- test-e2e-firefox
|
||||
- test-e2e-chrome-metrics
|
||||
- test-e2e-firefox-metrics
|
||||
- test-e2e-chrome-snaps
|
||||
- test-e2e-firefox-snaps
|
||||
- benchmark:
|
||||
requires:
|
||||
- prep-build-test
|
||||
@ -149,6 +160,7 @@ workflows:
|
||||
requires:
|
||||
- prep-deps
|
||||
- prep-build
|
||||
- prep-build-flask
|
||||
- all-tests-pass
|
||||
- job-publish-storybook:
|
||||
filters:
|
||||
@ -283,6 +295,28 @@ jobs:
|
||||
- dist-flask
|
||||
- builds-flask
|
||||
|
||||
prep-build-test-flask:
|
||||
executor: node-browsers-medium-plus
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Build extension for testing
|
||||
command: yarn build:test:flask
|
||||
- run:
|
||||
name: Move test build to 'dist-test' to avoid conflict with production build
|
||||
command: mv ./dist ./dist-test-flask
|
||||
- run:
|
||||
name: Move test zips to 'builds-test' to avoid conflict with production build
|
||||
command: mv ./builds ./builds-test-flask
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- dist-test-flask
|
||||
- builds-test-flask
|
||||
|
||||
|
||||
prep-build-test:
|
||||
executor: node-browsers-medium-plus
|
||||
steps:
|
||||
@ -338,7 +372,7 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- storybook-build
|
||||
|
||||
|
||||
test-storybook:
|
||||
executor: node-browsers
|
||||
steps:
|
||||
@ -465,6 +499,60 @@ jobs:
|
||||
path: test-artifacts
|
||||
destination: test-artifacts
|
||||
|
||||
test-e2e-firefox-snaps:
|
||||
executor: node-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install Firefox
|
||||
command: ./.circleci/scripts/firefox-install.sh
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Move test build to dist
|
||||
command: mv ./dist-test-flask ./dist
|
||||
- run:
|
||||
name: Move test zips to builds
|
||||
command: mv ./builds-test-flask ./builds
|
||||
- run:
|
||||
name: test:e2e:firefox:snaps
|
||||
command: |
|
||||
if .circleci/scripts/test-run-e2e.sh
|
||||
then
|
||||
yarn test:e2e:firefox:snaps --retries 2
|
||||
fi
|
||||
no_output_timeout: 20m
|
||||
- store_artifacts:
|
||||
path: test-artifacts
|
||||
destination: test-artifacts
|
||||
|
||||
test-e2e-chrome-snaps:
|
||||
executor: node-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Re-Install Chrome
|
||||
command: ./.circleci/scripts/chrome-install.sh
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Move test build to dist
|
||||
command: mv ./dist-test-flask ./dist
|
||||
- run:
|
||||
name: Move test zips to builds
|
||||
command: mv ./builds-test-flask ./builds
|
||||
- run:
|
||||
name: test:e2e:chrome:snaps
|
||||
command: |
|
||||
if .circleci/scripts/test-run-e2e.sh
|
||||
then
|
||||
yarn test:e2e:chrome:snaps --retries 2
|
||||
fi
|
||||
no_output_timeout: 20m
|
||||
- store_artifacts:
|
||||
path: test-artifacts
|
||||
destination: test-artifacts
|
||||
|
||||
test-e2e-chrome-metrics:
|
||||
executor: node-browsers
|
||||
steps:
|
||||
@ -631,8 +719,11 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: sentry sourcemaps upload
|
||||
command: SENTRY_ORG=metamask SENTRY_PROJECT=metamask yarn sentry:publish
|
||||
name: Publish main release to Sentry
|
||||
command: yarn sentry:publish
|
||||
- run:
|
||||
name: Publish Flask release to Sentry
|
||||
command: yarn sentry:publish --build-type flask
|
||||
- run:
|
||||
name: Create GitHub release
|
||||
command: |
|
||||
|
@ -26,25 +26,53 @@ function install_github_cli ()
|
||||
popd
|
||||
}
|
||||
|
||||
function print_flask_version ()
|
||||
{
|
||||
local flask_filename
|
||||
flask_filename="$(find ./builds-flask -type f -name 'metamask-flask-chrome-*.zip' -exec basename {} .zip \;)"
|
||||
|
||||
local flask_build_filename_prefix
|
||||
flask_build_filename_prefix='metamask-flask-chrome-'
|
||||
local flask_build_filename_prefix_size
|
||||
flask_build_filename_prefix_size="${#flask_build_filename_prefix}"
|
||||
|
||||
# Use substring parameter expansion to remove the filename prefix, leaving just the version
|
||||
echo "${flask_filename:$flask_build_filename_prefix_size}"
|
||||
}
|
||||
|
||||
function publish_flask_tag ()
|
||||
{
|
||||
local flask_version="${1}"; shift
|
||||
|
||||
git config user.email "metamaskbot@users.noreply.github.com"
|
||||
git config user.name "MetaMask Bot"
|
||||
git tag -a "v${flask_version}" -m "Flask version ${flask_version}"
|
||||
repo_slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
|
||||
git push "https://$GITHUB_TOKEN@github.com/$repo_slug" "v${flask_version}"
|
||||
}
|
||||
|
||||
current_commit_msg=$(git show -s --format='%s' HEAD)
|
||||
|
||||
if [[ $current_commit_msg =~ Version[-[:space:]](v[[:digit:]]+.[[:digit:]]+.[[:digit:]]+) ]]
|
||||
then
|
||||
tag="${BASH_REMATCH[1]}"
|
||||
flask_version="$(print_flask_version)"
|
||||
|
||||
install_github_cli
|
||||
|
||||
printf '%s\n' 'Creating GitHub Release'
|
||||
release_body="$(awk -v version="${tag##v}" -f .circleci/scripts/show-changelog.awk CHANGELOG.md)"
|
||||
pushd builds
|
||||
hub release create \
|
||||
--attach metamask-chrome-*.zip \
|
||||
--attach metamask-firefox-*.zip \
|
||||
--message "Version ${tag##v}" \
|
||||
--message "$release_body" \
|
||||
--commitish "$CIRCLE_SHA1" \
|
||||
"$tag"
|
||||
popd
|
||||
hub release create \
|
||||
--attach builds/metamask-chrome-*.zip \
|
||||
--attach builds/metamask-firefox-*.zip \
|
||||
--attach builds-flask/metamask-flask-chrome-*.zip \
|
||||
--attach builds-flask/metamask-flask-firefox-*.zip \
|
||||
--message "Version ${tag##v}" \
|
||||
--message "$release_body" \
|
||||
--commitish "$CIRCLE_SHA1" \
|
||||
"$tag"
|
||||
|
||||
publish_flask_tag "${flask_version}"
|
||||
else
|
||||
printf '%s\n' 'Version not found in commit message; skipping GitHub Release'
|
||||
exit 0
|
||||
|
27
CHANGELOG.md
27
CHANGELOG.md
@ -6,6 +6,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [10.11.4]
|
||||
### Added
|
||||
- **[FLASK]** Snap removal confirmation ([#13619](https://github.com/MetaMask/metamask-extension/pull/13619))
|
||||
|
||||
### Changed
|
||||
- **[FLASK]** Update MetaMask Flask
|
||||
- This is the first release of [MetaMask Flask](https://metamask.io/flask) since the initial release on January 18. This release includes a significant number of fixes and DevX improvements. Flask will henceforth be released at a more frequent cadence, usually in close proximity to releases of the regular MetaMask Extension.
|
||||
- For reference, [#13462](https://github.com/MetaMask/metamask-extension/pull/13462) used the feature branch that produced the original Flask release after some additional changes were made.
|
||||
- **[FLASK]** Update Snaps packages to version `^0.10.6` ([#13901](https://github.com/MetaMask/metamask-extension/pull/13901), [#14041](https://github.com/MetaMask/metamask-extension/pull/14041), [#14070](https://github.com/MetaMask/metamask-extension/pull/14070))
|
||||
- Updates the following packages from `0.9.0` to `0.10.6`:
|
||||
- `@metamask/iframe-execution-environment-service`
|
||||
- `@metamask/rpc-methods`
|
||||
- `@metamask/snap-controllers`
|
||||
- Updates the targeted [`iframe-execution-environment`](https://github.com/MetaMask/iframe-execution-environment) version from `0.3.1` to `0.4.2`.
|
||||
- These changes encompass a variety of fixes and devX improvements. See the [releases](https://github.com/MetaMask/snaps-skunkworks/releases) of the Snaps monorepo for details.
|
||||
|
||||
### Fixed
|
||||
- **[FLASK]** Various UI issues ([#13462](https://github.com/MetaMask/metamask-extension/pull/13462))
|
||||
- _Note:_ The original Flask release was cut from the feature branch of [#13462](https://github.com/MetaMask/metamask-extension/pull/13462) before it was merged.
|
||||
- Fix Snaps permission request confirmation page title ([#13342](https://github.com/MetaMask/metamask-extension/pull/13342))
|
||||
- Fix Snaps custom confirmation `textarea` height ([#13572](https://github.com/MetaMask/metamask-extension/pull/13572))
|
||||
- Fix various styling issues ([#13577](https://github.com/MetaMask/metamask-extension/pull/13577))
|
||||
- **[FLASK]** Fix Snap key management install warning appearance ([#13844](https://github.com/MetaMask/metamask-extension/pull/13844))
|
||||
|
||||
## [10.11.3]
|
||||
### Changed
|
||||
- Split secret recovery phrase input into one-field-per-word ([#14016](https://github.com/MetaMask/metamask-extension/pull/14016))
|
||||
@ -2783,7 +2807,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Uncategorized
|
||||
- Added the ability to restore accounts from seed words.
|
||||
|
||||
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.11.3...HEAD
|
||||
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.11.4...HEAD
|
||||
[10.11.4]: https://github.com/MetaMask/metamask-extension/compare/v10.11.3...v10.11.4
|
||||
[10.11.3]: https://github.com/MetaMask/metamask-extension/compare/v10.11.2...v10.11.3
|
||||
[10.11.2]: https://github.com/MetaMask/metamask-extension/compare/v10.11.1...v10.11.2
|
||||
[10.11.1]: https://github.com/MetaMask/metamask-extension/compare/v10.11.0...v10.11.1
|
||||
|
11
app/_locales/en/messages.json
generated
11
app/_locales/en/messages.json
generated
@ -2299,6 +2299,9 @@
|
||||
"personalAddressDetected": {
|
||||
"message": "Personal address detected. Input the token contract address."
|
||||
},
|
||||
"pleaseConfirm": {
|
||||
"message": "Please confirm"
|
||||
},
|
||||
"plusXMore": {
|
||||
"message": "+ $1 more",
|
||||
"description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items"
|
||||
@ -2434,6 +2437,10 @@
|
||||
"removeSnap": {
|
||||
"message": "Remove Snap"
|
||||
},
|
||||
"removeSnapConfirmation": {
|
||||
"message": "Are you sure you want to remove $1?",
|
||||
"description": "$1 represents the name of the snap"
|
||||
},
|
||||
"removeSnapDescription": {
|
||||
"message": "This action will delete the snap, its data and revoke your given permissions."
|
||||
},
|
||||
@ -2662,6 +2669,10 @@
|
||||
"settings": {
|
||||
"message": "Settings"
|
||||
},
|
||||
"shorthandVersion": {
|
||||
"message": "v$1",
|
||||
"description": "$1 is replaced by a version string (e.g. 1.2.3)"
|
||||
},
|
||||
"show": {
|
||||
"message": "Show"
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { CaveatMutatorOperation } from '@metamask/snap-controllers';
|
||||
import { CaveatMutatorOperation } from '@metamask/controllers';
|
||||
import { CaveatTypes } from '../../../../shared/constants/permissions';
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { CaveatMutatorOperation } from '@metamask/snap-controllers';
|
||||
import { CaveatMutatorOperation } from '@metamask/controllers';
|
||||
import { CaveatTypes } from '../../../../shared/constants/permissions';
|
||||
import { CaveatMutatorFactories } from './caveat-mutators';
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { endowmentPermissionBuilders } from '@metamask/controllers';
|
||||
import {
|
||||
restrictedMethodPermissionBuilders,
|
||||
selectHooks,
|
||||
} from '@metamask/rpc-methods';
|
||||
import { endowmentPermissionBuilders } from '@metamask/snap-controllers';
|
||||
import { ExcludedSnapPermissions } from '../../../../../shared/constants/permissions';
|
||||
|
||||
/**
|
||||
* @returns {Record<string, Record<string, unknown>>} All endowment permission
|
||||
@ -24,9 +25,11 @@ export const buildSnapEndowmentSpecifications = () =>
|
||||
export function buildSnapRestrictedMethodSpecifications(hooks) {
|
||||
return Object.values(restrictedMethodPermissionBuilders).reduce(
|
||||
(specifications, { targetKey, specificationBuilder, methodHooks }) => {
|
||||
specifications[targetKey] = specificationBuilder({
|
||||
methodHooks: selectHooks(hooks, methodHooks),
|
||||
});
|
||||
if (!ExcludedSnapPermissions.has(targetKey)) {
|
||||
specifications[targetKey] = specificationBuilder({
|
||||
methodHooks: selectHooks(hooks, methodHooks),
|
||||
});
|
||||
}
|
||||
return specifications;
|
||||
},
|
||||
{},
|
||||
|
@ -1,7 +1,4 @@
|
||||
import {
|
||||
constructPermission,
|
||||
PermissionType,
|
||||
} from '@metamask/snap-controllers';
|
||||
import { constructPermission, PermissionType } from '@metamask/controllers';
|
||||
import {
|
||||
CaveatTypes,
|
||||
RestrictedMethods,
|
||||
|
@ -1,10 +1,10 @@
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
import { handlers as permittedSnapMethods } from '@metamask/rpc-methods/dist/permitted';
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
import { flatten } from 'lodash';
|
||||
import { permissionRpcMethods } from '@metamask/snap-controllers';
|
||||
import { permissionRpcMethods } from '@metamask/controllers';
|
||||
import { selectHooks } from '@metamask/rpc-methods';
|
||||
import { ethErrors } from 'eth-rpc-errors';
|
||||
import { flatten } from 'lodash';
|
||||
import { UNSUPPORTED_RPC_METHODS } from '../../../../shared/constants/network';
|
||||
import localHandlers from './handlers';
|
||||
|
||||
|
@ -70,6 +70,7 @@ import { MILLISECOND } from '../../shared/constants/time';
|
||||
import {
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
MESSAGE_TYPE,
|
||||
PLATFORM_FIREFOX,
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
POLLING_TOKEN_ENVIRONMENT_TYPES,
|
||||
SUBJECT_TYPES,
|
||||
@ -130,6 +131,10 @@ import {
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
} from './controllers/permissions';
|
||||
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
import { getPlatform } from './lib/util';
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
|
||||
export const METAMASK_CONTROLLER_EVENTS = {
|
||||
// Fired after state changes that impact the extension badge (unapproved msg count)
|
||||
// The process of updating the badge happens in app/scripts/background.js.
|
||||
@ -580,7 +585,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.workerController = new IframeExecutionService({
|
||||
onError: this.onExecutionEnvironmentError.bind(this),
|
||||
iframeUrl: new URL(
|
||||
'https://metamask.github.io/iframe-execution-environment/0.3.1',
|
||||
'https://metamask.github.io/iframe-execution-environment/0.4.2',
|
||||
),
|
||||
messenger: this.controllerMessenger.getRestricted({
|
||||
name: 'ExecutionService',
|
||||
@ -598,12 +603,16 @@ export default class MetamaskController extends EventEmitter {
|
||||
`${this.permissionController.name}:getEndowments`,
|
||||
`${this.permissionController.name}:getPermissions`,
|
||||
`${this.permissionController.name}:hasPermission`,
|
||||
`${this.permissionController.name}:hasPermissions`,
|
||||
`${this.permissionController.name}:requestPermissions`,
|
||||
`${this.permissionController.name}:revokeAllPermissions`,
|
||||
],
|
||||
});
|
||||
|
||||
const usingFirefox = getPlatform() === PLATFORM_FIREFOX;
|
||||
|
||||
this.snapController = new SnapController({
|
||||
npmRegistryUrl: usingFirefox ? 'https://registry.npmjs.cf/' : undefined,
|
||||
endowmentPermissionNames: Object.values(EndowmentPermissions),
|
||||
terminateAllSnaps: this.workerController.terminateAllSnaps.bind(
|
||||
this.workerController,
|
||||
|
@ -1,6 +1,7 @@
|
||||
# The MetaMask Build System
|
||||
|
||||
> _tl;dr_ `yarn dist` for prod, `yarn start` for local development
|
||||
> _tl;dr_ `yarn dist` for prod, `yarn start` for local development.
|
||||
> Add `--build-type flask` to build Flask, our canary distribution with more experimental features.
|
||||
|
||||
This directory contains the MetaMask build system, which is used to build the MetaMask Extension such that it can be used in a supported browser.
|
||||
From the repository root, the build system entry file is located at [`./development/build/index.js`](https://github.com/MetaMask/metamask-extension/blob/develop/development/build/index.js).
|
||||
@ -40,7 +41,8 @@ Commands:
|
||||
e2e tests.
|
||||
|
||||
Options:
|
||||
--build-type The "type" of build to create. One of: "beta", "main"
|
||||
--build-type The "type" of build to create. One of: "beta", "flask",
|
||||
"main"
|
||||
[string] [default: "main"]
|
||||
--lint-fence-files Whether files with code fences should be linted after
|
||||
fences have been removed by the code fencing transform.
|
||||
|
@ -4,13 +4,13 @@ const gulpZip = require('gulp-zip');
|
||||
const del = require('del');
|
||||
const pify = require('pify');
|
||||
const pump = pify(require('pump'));
|
||||
const { version } = require('../../package.json');
|
||||
|
||||
const { BuildType } = require('../lib/build-type');
|
||||
const { createTask, composeParallel } = require('./task');
|
||||
const { BuildType } = require('./utils');
|
||||
|
||||
module.exports = createEtcTasks;
|
||||
|
||||
function createEtcTasks({ browserPlatforms, buildType, livereload }) {
|
||||
function createEtcTasks({ browserPlatforms, buildType, livereload, version }) {
|
||||
const clean = createTask('clean', async function clean() {
|
||||
await del(['./dist/*']);
|
||||
await Promise.all(
|
||||
@ -28,14 +28,16 @@ function createEtcTasks({ browserPlatforms, buildType, livereload }) {
|
||||
const zip = createTask(
|
||||
'zip',
|
||||
composeParallel(
|
||||
...browserPlatforms.map((platform) => createZipTask(platform, buildType)),
|
||||
...browserPlatforms.map((platform) =>
|
||||
createZipTask(platform, buildType, version),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return { clean, reload, zip };
|
||||
}
|
||||
|
||||
function createZipTask(platform, buildType) {
|
||||
function createZipTask(platform, buildType, version) {
|
||||
return async () => {
|
||||
const path =
|
||||
buildType === BuildType.main
|
||||
|
@ -7,6 +7,8 @@ const path = require('path');
|
||||
const livereload = require('gulp-livereload');
|
||||
const minimist = require('minimist');
|
||||
const { sync: globby } = require('globby');
|
||||
const { getVersion } = require('../lib/get-version');
|
||||
const { BuildType } = require('../lib/build-type');
|
||||
const {
|
||||
createTask,
|
||||
composeSeries,
|
||||
@ -18,7 +20,7 @@ const createScriptTasks = require('./scripts');
|
||||
const createStyleTasks = require('./styles');
|
||||
const createStaticAssetTasks = require('./static');
|
||||
const createEtcTasks = require('./etc');
|
||||
const { BuildType, getBrowserVersionMap } = require('./utils');
|
||||
const { getBrowserVersionMap } = require('./utils');
|
||||
|
||||
// Packages required dynamically via browserify configuration in dependencies
|
||||
// Required for LavaMoat policy generation
|
||||
@ -58,11 +60,12 @@ function defineAndRunBuildTasks() {
|
||||
shouldIncludeLockdown,
|
||||
shouldLintFenceFiles,
|
||||
skipStats,
|
||||
version,
|
||||
} = parseArgv();
|
||||
|
||||
const browserPlatforms = ['firefox', 'chrome', 'brave', 'opera'];
|
||||
|
||||
const browserVersionMap = getBrowserVersionMap(browserPlatforms);
|
||||
const browserVersionMap = getBrowserVersionMap(browserPlatforms, version);
|
||||
|
||||
const ignoredFiles = getIgnoredFiles(buildType);
|
||||
|
||||
@ -89,12 +92,14 @@ function defineAndRunBuildTasks() {
|
||||
livereload,
|
||||
policyOnly,
|
||||
shouldLintFenceFiles,
|
||||
version,
|
||||
});
|
||||
|
||||
const { clean, reload, zip } = createEtcTasks({
|
||||
livereload,
|
||||
browserPlatforms,
|
||||
buildType,
|
||||
version,
|
||||
});
|
||||
|
||||
// build for development (livereload)
|
||||
@ -162,6 +167,7 @@ function defineAndRunBuildTasks() {
|
||||
function parseArgv() {
|
||||
const NamedArgs = {
|
||||
BuildType: 'build-type',
|
||||
BuildVersion: 'build-version',
|
||||
LintFenceFiles: 'lint-fence-files',
|
||||
Lockdown: 'lockdown',
|
||||
PolicyOnly: 'policy-only',
|
||||
@ -175,9 +181,10 @@ function parseArgv() {
|
||||
NamedArgs.PolicyOnly,
|
||||
NamedArgs.SkipStats,
|
||||
],
|
||||
string: [NamedArgs.BuildType],
|
||||
string: [NamedArgs.BuildType, NamedArgs.BuildVersion],
|
||||
default: {
|
||||
[NamedArgs.BuildType]: BuildType.main,
|
||||
[NamedArgs.BuildVersion]: '0',
|
||||
[NamedArgs.LintFenceFiles]: true,
|
||||
[NamedArgs.Lockdown]: true,
|
||||
[NamedArgs.PolicyOnly]: false,
|
||||
@ -201,6 +208,14 @@ function parseArgv() {
|
||||
throw new Error(`MetaMask build: Invalid build type: "${buildType}"`);
|
||||
}
|
||||
|
||||
const rawBuildVersion = argv[NamedArgs.BuildVersion];
|
||||
const buildVersion = Number.parseInt(rawBuildVersion, 10);
|
||||
if (rawBuildVersion.match(/^\d+$/u) === null || Number.isNaN(buildVersion)) {
|
||||
throw new Error(
|
||||
`MetaMask build: Invalid build version: "${rawBuildVersion}"`,
|
||||
);
|
||||
}
|
||||
|
||||
// Manually default this to `false` for dev builds only.
|
||||
const shouldLintFenceFiles = process.argv.includes(
|
||||
`--${NamedArgs.LintFenceFiles}`,
|
||||
@ -210,6 +225,8 @@ function parseArgv() {
|
||||
|
||||
const policyOnly = argv[NamedArgs.PolicyOnly];
|
||||
|
||||
const version = getVersion(buildType, buildVersion);
|
||||
|
||||
return {
|
||||
buildType,
|
||||
entryTask,
|
||||
@ -218,6 +235,7 @@ function parseArgv() {
|
||||
shouldIncludeLockdown: argv[NamedArgs.Lockdown],
|
||||
shouldLintFenceFiles,
|
||||
skipStats: argv[NamedArgs.SkipStats],
|
||||
version,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,9 @@ const path = require('path');
|
||||
const { mergeWith, cloneDeep } = require('lodash');
|
||||
|
||||
const baseManifest = require('../../app/manifest/_base.json');
|
||||
const { BuildType } = require('../lib/build-type');
|
||||
|
||||
const { createTask, composeSeries } = require('./task');
|
||||
const { BuildType } = require('./utils');
|
||||
|
||||
module.exports = createManifestTasks;
|
||||
|
||||
|
@ -45,7 +45,7 @@ const metamaskrc = require('rc')('metamask', {
|
||||
});
|
||||
|
||||
const { streamFlatMap } = require('../stream-flat-map.js');
|
||||
const { version } = require('../../package.json');
|
||||
const { BuildType } = require('../lib/build-type');
|
||||
|
||||
const {
|
||||
createTask,
|
||||
@ -56,7 +56,6 @@ const {
|
||||
const {
|
||||
createRemoveFencedCodeTransform,
|
||||
} = require('./transforms/remove-fenced-code');
|
||||
const { BuildType } = require('./utils');
|
||||
|
||||
/**
|
||||
* The build environment. This describes the environment this build was produced in.
|
||||
@ -147,6 +146,7 @@ function createScriptTasks({
|
||||
livereload,
|
||||
shouldLintFenceFiles,
|
||||
policyOnly,
|
||||
version,
|
||||
}) {
|
||||
// internal tasks
|
||||
const core = {
|
||||
@ -192,6 +192,7 @@ function createScriptTasks({
|
||||
policyOnly,
|
||||
shouldLintFenceFiles,
|
||||
testing,
|
||||
version,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -344,6 +345,7 @@ function createFactoredBuild({
|
||||
policyOnly,
|
||||
shouldLintFenceFiles,
|
||||
testing,
|
||||
version,
|
||||
}) {
|
||||
return async function () {
|
||||
// create bundler setup and apply defaults
|
||||
@ -355,7 +357,12 @@ function createFactoredBuild({
|
||||
const reloadOnChange = Boolean(devMode);
|
||||
const minify = Boolean(devMode) === false;
|
||||
|
||||
const envVars = getEnvironmentVariables({ buildType, devMode, testing });
|
||||
const envVars = getEnvironmentVariables({
|
||||
buildType,
|
||||
devMode,
|
||||
testing,
|
||||
version,
|
||||
});
|
||||
setupBundlerDefaults(buildConfiguration, {
|
||||
buildType,
|
||||
devMode,
|
||||
@ -780,7 +787,7 @@ async function bundleIt(buildConfiguration, { reloadOnChange }) {
|
||||
}
|
||||
}
|
||||
|
||||
function getEnvironmentVariables({ buildType, devMode, testing }) {
|
||||
function getEnvironmentVariables({ buildType, devMode, testing, version }) {
|
||||
const environment = getEnvironment({ devMode, testing });
|
||||
if (environment === ENVIRONMENT.PRODUCTION && !process.env.SENTRY_DSN) {
|
||||
throw new Error('Missing SENTRY_DSN environment variable');
|
||||
|
@ -4,9 +4,9 @@ const watch = require('gulp-watch');
|
||||
const glob = require('fast-glob');
|
||||
|
||||
const locales = require('../../app/_locales/index.json');
|
||||
const { BuildType } = require('../lib/build-type');
|
||||
|
||||
const { createTask, composeSeries } = require('./task');
|
||||
const { BuildType } = require('./utils');
|
||||
|
||||
const EMPTY_JS_FILE = './development/empty.js';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
const path = require('path');
|
||||
const { PassThrough, Transform } = require('stream');
|
||||
const { BuildType } = require('../utils');
|
||||
const { BuildType } = require('../../lib/build-type');
|
||||
const { lintTransformedFile } = require('./utils');
|
||||
|
||||
const hasKey = (obj, key) => Reflect.hasOwnProperty.call(obj, key);
|
||||
|
@ -1,5 +1,5 @@
|
||||
const deepFreeze = require('deep-freeze-strict');
|
||||
const { BuildType } = require('../utils');
|
||||
const { BuildType } = require('../../lib/build-type');
|
||||
const {
|
||||
createRemoveFencedCodeTransform,
|
||||
removeFencedCode,
|
||||
|
@ -1,16 +1,5 @@
|
||||
const semver = require('semver');
|
||||
const { version } = require('../../package.json');
|
||||
|
||||
/**
|
||||
* The distribution this build is intended for.
|
||||
*
|
||||
* This should be kept in-sync with the `BuildType` map in `shared/constants/app.js`.
|
||||
*/
|
||||
const BuildType = {
|
||||
beta: 'beta',
|
||||
flask: 'flask',
|
||||
main: 'main',
|
||||
};
|
||||
const { BuildType } = require('../lib/build-type');
|
||||
|
||||
/**
|
||||
* Map the current version to a format that is compatible with each browser.
|
||||
@ -20,11 +9,12 @@ const BuildType = {
|
||||
* where the build version is a positive integer.
|
||||
*
|
||||
* @param {string[]} platforms - A list of browsers to generate versions for.
|
||||
* @param {string} version - The current version.
|
||||
* @returns {Object} An object with the browser as the key and the browser-specific version object
|
||||
* as the value. For example, the version `9.6.0-beta.1` would return the object
|
||||
* `{ firefox: { version: '9.6.0.beta1' }, chrome: { version: '9.6.0.1', version_name: '9.6.0-beta.1' } }`.
|
||||
*/
|
||||
function getBrowserVersionMap(platforms) {
|
||||
function getBrowserVersionMap(platforms, version) {
|
||||
const major = semver.major(version);
|
||||
const minor = semver.minor(version);
|
||||
const patch = semver.patch(version);
|
||||
@ -62,6 +52,5 @@ function getBrowserVersionMap(platforms) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
BuildType,
|
||||
getBrowserVersionMap,
|
||||
};
|
||||
|
12
development/lib/build-type.js
Normal file
12
development/lib/build-type.js
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* The distribution this build is intended for.
|
||||
*
|
||||
* This should be kept in-sync with the `BuildType` map in `shared/constants/app.js`.
|
||||
*/
|
||||
const BuildType = {
|
||||
beta: 'beta',
|
||||
flask: 'flask',
|
||||
main: 'main',
|
||||
};
|
||||
|
||||
module.exports = { BuildType };
|
21
development/lib/get-version.js
Normal file
21
development/lib/get-version.js
Normal file
@ -0,0 +1,21 @@
|
||||
const { version: manifestVersion } = require('../../package.json');
|
||||
const { BuildType } = require('./build-type');
|
||||
|
||||
/**
|
||||
* Get the current version of the MetaMask extension. The base manifest version
|
||||
* is modified according to the build type and version.
|
||||
*
|
||||
* The build version is needed because certain build types (such as beta) may
|
||||
* be released multiple times during the release process.
|
||||
*
|
||||
* @param {BuildType} buildType - The build type.
|
||||
* @param {number} buildVersion - The build version.
|
||||
* @returns {string} The MetaMask extension version.
|
||||
*/
|
||||
function getVersion(buildType, buildVersion) {
|
||||
return buildType === BuildType.main
|
||||
? manifestVersion
|
||||
: `${manifestVersion}-${buildType}.${buildVersion}`;
|
||||
}
|
||||
|
||||
module.exports = { getVersion };
|
@ -3,7 +3,7 @@ const { promises: fs } = require('fs');
|
||||
const path = require('path');
|
||||
const fetch = require('node-fetch');
|
||||
const glob = require('fast-glob');
|
||||
const VERSION = require('../dist/chrome/manifest.json').version; // eslint-disable-line import/no-unresolved
|
||||
const VERSION = require('../package.json').version;
|
||||
const { getHighlights } = require('./highlights');
|
||||
|
||||
start().catch(console.error);
|
||||
|
@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
const VERSION = require('../dist/chrome/manifest.json').version; // eslint-disable-line import/no-unresolved
|
||||
|
||||
const yargs = require('yargs/yargs');
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
|
||||
const { runCommand, runInShell } = require('./lib/run-command');
|
||||
const { getVersion } = require('./lib/get-version');
|
||||
const { BuildType } = require('./lib/build-type');
|
||||
|
||||
start().catch((error) => {
|
||||
console.error(error);
|
||||
@ -8,34 +13,63 @@ start().catch((error) => {
|
||||
});
|
||||
|
||||
async function start() {
|
||||
if (!process.env.SENTRY_ORG) {
|
||||
throw new Error('Missing required "SENTRY_ORG" environment variable');
|
||||
} else if (!process.env.SENTRY_PROJECT) {
|
||||
throw new Error('Missing required "SENTRY_PROJECT" environment variable');
|
||||
}
|
||||
const { argv } = yargs(hideBin(process.argv)).usage(
|
||||
'$0 [options]',
|
||||
'Publish a release to Sentry',
|
||||
(_yargs) =>
|
||||
_yargs
|
||||
.option('org', {
|
||||
default: 'metamask',
|
||||
description: 'The Sentry organization',
|
||||
type: 'string',
|
||||
})
|
||||
.option('project', {
|
||||
default: 'metamask',
|
||||
description: 'The Sentry project to publish',
|
||||
type: 'string',
|
||||
})
|
||||
.option('build-type', {
|
||||
default: BuildType.main,
|
||||
description: 'The MetaMask extension build type',
|
||||
choices: Object.values(BuildType),
|
||||
})
|
||||
.option('build-version', {
|
||||
default: 0,
|
||||
description: 'The MetaMask extension build version',
|
||||
type: 'number',
|
||||
}),
|
||||
);
|
||||
|
||||
const { buildType, buildVersion, org, project } = argv;
|
||||
|
||||
process.env.SENTRY_ORG = org;
|
||||
process.env.SENTRY_PROJECT = project;
|
||||
|
||||
const authWorked = await checkIfAuthWorks();
|
||||
if (!authWorked) {
|
||||
throw new Error(`Sentry auth failed`);
|
||||
}
|
||||
|
||||
const version = getVersion(buildType, buildVersion);
|
||||
|
||||
// check if version exists or not
|
||||
const versionAlreadyExists = await checkIfVersionExists();
|
||||
const versionAlreadyExists = await checkIfVersionExists(version);
|
||||
// abort if versions exists
|
||||
if (versionAlreadyExists) {
|
||||
console.log(
|
||||
`Version "${VERSION}" already exists on Sentry, skipping version creation`,
|
||||
`Version "${version}" already exists on Sentry, skipping version creation`,
|
||||
);
|
||||
} else {
|
||||
// create sentry release
|
||||
console.log(`creating Sentry release for "${VERSION}"...`);
|
||||
await runCommand('sentry-cli', ['releases', 'new', VERSION]);
|
||||
console.log(`creating Sentry release for "${version}"...`);
|
||||
await runCommand('sentry-cli', ['releases', 'new', version]);
|
||||
console.log(
|
||||
`removing any existing files from Sentry release "${VERSION}"...`,
|
||||
`removing any existing files from Sentry release "${version}"...`,
|
||||
);
|
||||
await runCommand('sentry-cli', [
|
||||
'releases',
|
||||
'files',
|
||||
VERSION,
|
||||
version,
|
||||
'delete',
|
||||
'--all',
|
||||
]);
|
||||
@ -43,18 +77,23 @@ async function start() {
|
||||
|
||||
// check if version has artifacts or not
|
||||
const versionHasArtifacts =
|
||||
versionAlreadyExists && (await checkIfVersionHasArtifacts());
|
||||
versionAlreadyExists && (await checkIfVersionHasArtifacts(version));
|
||||
if (versionHasArtifacts) {
|
||||
console.log(
|
||||
`Version "${VERSION}" already has artifacts on Sentry, skipping sourcemap upload`,
|
||||
`Version "${version}" already has artifacts on Sentry, skipping sourcemap upload`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const additionalUploadArgs = [];
|
||||
if (buildType !== BuildType.main) {
|
||||
additionalUploadArgs.push('--dist-directory', `dist-${buildType}`);
|
||||
}
|
||||
// upload sentry source and sourcemaps
|
||||
await runInShell('./development/sentry-upload-artifacts.sh', [
|
||||
'--release',
|
||||
VERSION,
|
||||
version,
|
||||
...additionalUploadArgs,
|
||||
]);
|
||||
}
|
||||
|
||||
@ -64,17 +103,17 @@ async function checkIfAuthWorks() {
|
||||
);
|
||||
}
|
||||
|
||||
async function checkIfVersionExists() {
|
||||
async function checkIfVersionExists(version) {
|
||||
return await doesNotFail(() =>
|
||||
runCommand('sentry-cli', ['releases', 'info', VERSION]),
|
||||
runCommand('sentry-cli', ['releases', 'info', version]),
|
||||
);
|
||||
}
|
||||
|
||||
async function checkIfVersionHasArtifacts() {
|
||||
async function checkIfVersionHasArtifacts(version) {
|
||||
const [artifact] = await runCommand('sentry-cli', [
|
||||
'releases',
|
||||
'files',
|
||||
VERSION,
|
||||
version,
|
||||
'list',
|
||||
]);
|
||||
// When there's no artifacts, we get a response from the shell like this ['', '']
|
||||
|
@ -23,17 +23,20 @@ Upload JavaScript bundles and sourcemaps to Sentry
|
||||
Options:
|
||||
-h, --help Show help text
|
||||
-r, --release <release> Sentry release to upload files to (defaults to 'VERSION' environment variable)
|
||||
--dist-directory <path> The 'dist' directory to use. Defaults to 'dist'.
|
||||
EOF
|
||||
}
|
||||
|
||||
function upload_sourcemaps {
|
||||
local release="${1}"; shift
|
||||
local dist_directory="${1}"; shift
|
||||
|
||||
sentry-cli releases files "${release}" upload-sourcemaps ./dist/chrome/*.js ./dist/sourcemaps/ --rewrite --url-prefix 'metamask'
|
||||
sentry-cli releases files "${release}" upload-sourcemaps "${dist_directory}"/chrome/*.js "${dist_directory}"/sourcemaps/ --rewrite --url-prefix 'metamask'
|
||||
}
|
||||
|
||||
function main {
|
||||
local release=VERSION
|
||||
local dist_directory='dist'
|
||||
|
||||
while :; do
|
||||
case "${1-default}" in
|
||||
@ -51,6 +54,16 @@ function main {
|
||||
release="${2}"
|
||||
shift
|
||||
;;
|
||||
--dist-directory)
|
||||
if [[ -z $2 ]]
|
||||
then
|
||||
printf "'dist-directory' option requires an argument.\\n" >&2
|
||||
printf '%s\n' "${__SEE_HELP_MESSAGE__}" >&2
|
||||
exit 1
|
||||
fi
|
||||
dist_directory="${2}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
break
|
||||
esac
|
||||
@ -70,7 +83,7 @@ function main {
|
||||
fi
|
||||
|
||||
printf 'uploading source files and sourcemaps for Sentry release "%s"...\n' "${release}"
|
||||
upload_sourcemaps "${release}"
|
||||
upload_sourcemaps "${release}" "${dist_directory}"
|
||||
printf 'all done!\n'
|
||||
}
|
||||
|
||||
|
@ -695,6 +695,7 @@
|
||||
},
|
||||
"@metamask/rpc-methods": {
|
||||
"packages": {
|
||||
"@metamask/controllers": true,
|
||||
"@metamask/key-tree": true,
|
||||
"@metamask/snap-controllers": true,
|
||||
"eth-rpc-errors": true
|
||||
@ -734,25 +735,24 @@
|
||||
"clearTimeout": true,
|
||||
"console.error": true,
|
||||
"console.log": true,
|
||||
"fetch": true,
|
||||
"console.warn": true,
|
||||
"setTimeout": true
|
||||
},
|
||||
"packages": {
|
||||
"@metamask/controllers": true,
|
||||
"@metamask/execution-environments": true,
|
||||
"@metamask/object-multiplex": true,
|
||||
"@metamask/obs-store": true,
|
||||
"@metamask/post-message-stream": true,
|
||||
"@metamask/safe-event-emitter": true,
|
||||
"@metamask/snap-workers": true,
|
||||
"ajv": true,
|
||||
"buffer": true,
|
||||
"concat-stream": true,
|
||||
"cross-fetch": true,
|
||||
"crypto-browserify": true,
|
||||
"deep-freeze-strict": true,
|
||||
"eth-rpc-errors": true,
|
||||
"fast-deep-equal": true,
|
||||
"gunzip-maybe": true,
|
||||
"immer": true,
|
||||
"json-rpc-engine": true,
|
||||
"json-rpc-middleware-stream": true,
|
||||
"nanoid": true,
|
||||
|
@ -630,16 +630,15 @@
|
||||
"@metamask/iframe-execution-environment-service": {
|
||||
"globals": {
|
||||
"clearTimeout": true,
|
||||
"console.log": true,
|
||||
"document.body.appendChild": true,
|
||||
"document.createElement": true,
|
||||
"document.getElementById": true,
|
||||
"setTimeout": true
|
||||
},
|
||||
"packages": {
|
||||
"@metamask/execution-environments": true,
|
||||
"@metamask/post-message-stream": true,
|
||||
"@metamask/snap-controllers": true,
|
||||
"@metamask/snap-workers": true,
|
||||
"json-rpc-engine": true,
|
||||
"json-rpc-middleware-stream": true,
|
||||
"nanoid": true,
|
||||
@ -714,6 +713,7 @@
|
||||
},
|
||||
"@metamask/rpc-methods": {
|
||||
"packages": {
|
||||
"@metamask/controllers": true,
|
||||
"@metamask/key-tree": true,
|
||||
"@metamask/snap-controllers": true,
|
||||
"eth-rpc-errors": true
|
||||
@ -753,25 +753,24 @@
|
||||
"clearTimeout": true,
|
||||
"console.error": true,
|
||||
"console.log": true,
|
||||
"fetch": true,
|
||||
"console.warn": true,
|
||||
"setTimeout": true
|
||||
},
|
||||
"packages": {
|
||||
"@metamask/controllers": true,
|
||||
"@metamask/execution-environments": true,
|
||||
"@metamask/object-multiplex": true,
|
||||
"@metamask/obs-store": true,
|
||||
"@metamask/post-message-stream": true,
|
||||
"@metamask/safe-event-emitter": true,
|
||||
"@metamask/snap-workers": true,
|
||||
"ajv": true,
|
||||
"buffer": true,
|
||||
"concat-stream": true,
|
||||
"cross-fetch": true,
|
||||
"crypto-browserify": true,
|
||||
"deep-freeze-strict": true,
|
||||
"eth-rpc-errors": true,
|
||||
"fast-deep-equal": true,
|
||||
"gunzip-maybe": true,
|
||||
"immer": true,
|
||||
"json-rpc-engine": true,
|
||||
"json-rpc-middleware-stream": true,
|
||||
"nanoid": true,
|
||||
|
@ -695,6 +695,7 @@
|
||||
},
|
||||
"@metamask/rpc-methods": {
|
||||
"packages": {
|
||||
"@metamask/controllers": true,
|
||||
"@metamask/key-tree": true,
|
||||
"@metamask/snap-controllers": true,
|
||||
"eth-rpc-errors": true
|
||||
@ -734,25 +735,24 @@
|
||||
"clearTimeout": true,
|
||||
"console.error": true,
|
||||
"console.log": true,
|
||||
"fetch": true,
|
||||
"console.warn": true,
|
||||
"setTimeout": true
|
||||
},
|
||||
"packages": {
|
||||
"@metamask/controllers": true,
|
||||
"@metamask/execution-environments": true,
|
||||
"@metamask/object-multiplex": true,
|
||||
"@metamask/obs-store": true,
|
||||
"@metamask/post-message-stream": true,
|
||||
"@metamask/safe-event-emitter": true,
|
||||
"@metamask/snap-workers": true,
|
||||
"ajv": true,
|
||||
"buffer": true,
|
||||
"concat-stream": true,
|
||||
"cross-fetch": true,
|
||||
"crypto-browserify": true,
|
||||
"deep-freeze-strict": true,
|
||||
"eth-rpc-errors": true,
|
||||
"fast-deep-equal": true,
|
||||
"gunzip-maybe": true,
|
||||
"immer": true,
|
||||
"json-rpc-engine": true,
|
||||
"json-rpc-middleware-stream": true,
|
||||
"nanoid": true,
|
||||
|
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "metamask-crx",
|
||||
"version": "10.11.3",
|
||||
"version": "10.11.4",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -18,6 +18,7 @@
|
||||
"benchmark:chrome": "SELENIUM_BROWSER=chrome node test/e2e/benchmark.js",
|
||||
"benchmark:firefox": "SELENIUM_BROWSER=firefox node test/e2e/benchmark.js",
|
||||
"build:test": "yarn build test",
|
||||
"build:test:flask": "yarn build test --build-type flask",
|
||||
"build:test:metrics": "SEGMENT_HOST='http://localhost:9090' SEGMENT_WRITE_KEY='FAKE' yarn build test",
|
||||
"test": "yarn lint && yarn test:unit && yarn test:unit:jest",
|
||||
"dapp": "node development/static-server.js node_modules/@metamask/test-dapp/dist --port 8080",
|
||||
@ -30,8 +31,10 @@
|
||||
"test:unit:mocha": "mocha './app/**/*.test.js'",
|
||||
"test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js",
|
||||
"test:e2e:chrome:metrics": "SELENIUM_BROWSER=chrome node test/e2e/run-e2e-test.js test/e2e/metrics.spec.js",
|
||||
"test:e2e:chrome:snaps": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --snaps",
|
||||
"test:e2e:firefox": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js",
|
||||
"test:e2e:firefox:metrics": "SELENIUM_BROWSER=firefox node test/e2e/run-e2e-test.js test/e2e/metrics.spec.js",
|
||||
"test:e2e:firefox:snaps": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js --snaps",
|
||||
"test:e2e:single": "node test/e2e/run-e2e-test.js",
|
||||
"test:coverage:mocha": "nyc --reporter=text --reporter=html yarn test:unit:mocha",
|
||||
"test:coverage:jest": "yarn test:unit:jest --coverage --maxWorkers=2",
|
||||
@ -113,16 +116,16 @@
|
||||
"@metamask/eth-ledger-bridge-keyring": "^0.10.0",
|
||||
"@metamask/eth-token-tracker": "^4.0.0",
|
||||
"@metamask/etherscan-link": "^2.1.0",
|
||||
"@metamask/iframe-execution-environment-service": "^0.9.0",
|
||||
"@metamask/iframe-execution-environment-service": "^0.10.6",
|
||||
"@metamask/jazzicon": "^2.0.0",
|
||||
"@metamask/logo": "^3.1.1",
|
||||
"@metamask/obs-store": "^5.0.0",
|
||||
"@metamask/post-message-stream": "^4.0.0",
|
||||
"@metamask/providers": "^8.1.1",
|
||||
"@metamask/rpc-methods": "^0.9.0",
|
||||
"@metamask/rpc-methods": "^0.10.6",
|
||||
"@metamask/slip44": "^2.0.0",
|
||||
"@metamask/smart-transactions-controller": "^1.9.1",
|
||||
"@metamask/snap-controllers": "^0.9.0",
|
||||
"@metamask/snap-controllers": "^0.10.6",
|
||||
"@ngraveio/bc-ur": "^1.1.6",
|
||||
"@popperjs/core": "^2.4.0",
|
||||
"@reduxjs/toolkit": "^1.6.2",
|
||||
@ -417,7 +420,11 @@
|
||||
"ganache>leveldown": false,
|
||||
"geckodriver": true,
|
||||
"react-devtools>electron": true,
|
||||
"eth-trezor-keyring>trezor-connect>@trezor/transport>protobufjs": false
|
||||
"eth-trezor-keyring>trezor-connect>@trezor/transport>protobufjs": false,
|
||||
"@metamask/iframe-execution-environment-service>@metamask/execution-environments": false,
|
||||
"@metamask/snap-controllers>@metamask/execution-environments": false,
|
||||
"@metamask/iframe-execution-environment-service>@metamask/snap-controllers>@metamask/execution-environments": false,
|
||||
"@metamask/rpc-methods>@metamask/snap-controllers>@metamask/execution-environments": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,4 +21,7 @@ export const PermissionNamespaces = Object.freeze({
|
||||
export const EndowmentPermissions = Object.freeze({
|
||||
'endowment:network-access': 'endowment:network-access',
|
||||
});
|
||||
|
||||
// Methods / permissions in external packages that we are temporarily excluding.
|
||||
export const ExcludedSnapPermissions = new Set(['snap_notify']);
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { endowmentPermissionBuilders } from '@metamask/snap-controllers';
|
||||
import { endowmentPermissionBuilders } from '@metamask/controllers';
|
||||
import { restrictedMethodPermissionBuilders } from '@metamask/rpc-methods';
|
||||
import { EndowmentPermissions, RestrictedMethods } from './permissions';
|
||||
import {
|
||||
EndowmentPermissions,
|
||||
ExcludedSnapPermissions,
|
||||
RestrictedMethods,
|
||||
} from './permissions';
|
||||
|
||||
describe('EndowmentPermissions', () => {
|
||||
it('has the expected permission keys', () => {
|
||||
@ -15,7 +19,9 @@ describe('RestrictedMethods', () => {
|
||||
expect(Object.keys(RestrictedMethods).sort()).toStrictEqual(
|
||||
[
|
||||
'eth_accounts',
|
||||
...Object.keys(restrictedMethodPermissionBuilders),
|
||||
...Object.keys(restrictedMethodPermissionBuilders).filter(
|
||||
(targetKey) => !ExcludedSnapPermissions.has(targetKey),
|
||||
),
|
||||
].sort(),
|
||||
);
|
||||
});
|
||||
|
@ -17,6 +17,10 @@ async function main() {
|
||||
type: 'string',
|
||||
choices: ['chrome', 'firefox'],
|
||||
})
|
||||
.option('snaps', {
|
||||
description: `run snaps e2e tests`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('retries', {
|
||||
description:
|
||||
'Set how many times the test should be retried upon failure.',
|
||||
@ -26,16 +30,22 @@ async function main() {
|
||||
.strict()
|
||||
.help('help');
|
||||
|
||||
const { browser, retries } = argv;
|
||||
const { browser, retries, snaps } = argv;
|
||||
|
||||
const testDir = path.join(__dirname, 'tests');
|
||||
const metamaskUiTest = path.join(__dirname, 'metamask-ui.spec.js');
|
||||
let testDir = path.join(__dirname, 'tests');
|
||||
|
||||
if (snaps) {
|
||||
testDir = path.join(__dirname, 'snaps');
|
||||
}
|
||||
|
||||
const testFilenames = await fs.readdir(testDir);
|
||||
const testPaths = testFilenames.map((filename) =>
|
||||
path.join(testDir, filename),
|
||||
);
|
||||
const allE2eTestPaths = [...testPaths, metamaskUiTest];
|
||||
|
||||
if (!snaps) {
|
||||
testPaths.push(path.join(__dirname, 'metamask-ui.spec.js'));
|
||||
}
|
||||
|
||||
const runE2eTestPath = path.join(__dirname, 'run-e2e-test.js');
|
||||
|
||||
@ -47,7 +57,7 @@ async function main() {
|
||||
args.push('--retries', retries);
|
||||
}
|
||||
|
||||
for (const testPath of allE2eTestPaths) {
|
||||
for (const testPath of testPaths) {
|
||||
await runInShell('node', [...args, testPath]);
|
||||
}
|
||||
}
|
||||
|
98
test/e2e/snaps/test-snap-confirm.spec.js
Normal file
98
test/e2e/snaps/test-snap-confirm.spec.js
Normal file
@ -0,0 +1,98 @@
|
||||
const { strict: assert } = require('assert');
|
||||
const { withFixtures } = require('../helpers');
|
||||
|
||||
describe('Test Snap Confirm', function () {
|
||||
it('can pop up a snap confirm and get its result', async function () {
|
||||
const ganacheOptions = {
|
||||
accounts: [
|
||||
{
|
||||
secretKey:
|
||||
'0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC',
|
||||
balance: 25000000000000000000,
|
||||
},
|
||||
],
|
||||
};
|
||||
await withFixtures(
|
||||
{
|
||||
fixtures: 'imported-account',
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
driverOptions: {
|
||||
type: 'flask',
|
||||
},
|
||||
},
|
||||
async ({ driver }) => {
|
||||
await driver.navigate();
|
||||
|
||||
// enter pw into extension
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
|
||||
// navigate to test snaps page and connect
|
||||
await driver.driver.get('https://metamask.github.io/test-snaps/');
|
||||
await driver.fill('.snapId', 'npm:@metamask/test-snap-confirm');
|
||||
await driver.clickElement({
|
||||
text: 'Connect To Confirm Snap',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// switch to metamask extension and click connect
|
||||
await driver.waitUntilXWindowHandles(2, 5000, 10000);
|
||||
let windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.clickElement(
|
||||
{
|
||||
text: 'Connect',
|
||||
tag: 'button',
|
||||
},
|
||||
10000,
|
||||
);
|
||||
|
||||
await driver.delay(2000);
|
||||
|
||||
// approve install of snap
|
||||
await driver.waitUntilXWindowHandles(2, 5000, 10000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.clickElement({
|
||||
text: 'Approve & Install',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// click send inputs on test snap page
|
||||
await driver.waitUntilXWindowHandles(1, 5000, 10000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle('Test Snaps', windowHandles);
|
||||
await driver.clickElement({
|
||||
text: 'Send Inputs to Hello Snap',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// hit 'approve' on the custom confirm
|
||||
await driver.waitUntilXWindowHandles(2, 5000, 10000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.clickElement({
|
||||
text: 'Approve',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// check the results of the custom confirm
|
||||
await driver.waitUntilXWindowHandles(1, 5000, 10000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle('Test Snaps', windowHandles);
|
||||
const confirmResult = await driver.findElement('.sendResults');
|
||||
assert.equal(await confirmResult.getText(), 'true');
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
90
test/e2e/snaps/test-snap-error.spec.js
Normal file
90
test/e2e/snaps/test-snap-error.spec.js
Normal file
@ -0,0 +1,90 @@
|
||||
const { strict: assert } = require('assert');
|
||||
const { withFixtures } = require('../helpers');
|
||||
const { PAGES } = require('../webdriver/driver');
|
||||
|
||||
describe('Test Snap Error', function () {
|
||||
it('can pop up a snap error and see the error', async function () {
|
||||
const ganacheOptions = {
|
||||
accounts: [
|
||||
{
|
||||
secretKey:
|
||||
'0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC',
|
||||
balance: 25000000000000000000,
|
||||
},
|
||||
],
|
||||
};
|
||||
await withFixtures(
|
||||
{
|
||||
fixtures: 'imported-account',
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
driverOptions: { type: 'flask' },
|
||||
},
|
||||
async ({ driver }) => {
|
||||
await driver.navigate();
|
||||
|
||||
// enter pw into extension
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
|
||||
// navigate to test snaps page and connect
|
||||
await driver.driver.get('https://metamask.github.io/test-snaps/');
|
||||
await driver.fill('.snapId2', 'npm:@metamask/test-snap-error');
|
||||
await driver.clickElement({
|
||||
text: 'Connect Error Snap',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// switch to metamask extension and click connect
|
||||
await driver.waitUntilXWindowHandles(2, 5000, 10000);
|
||||
let windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.clickElement(
|
||||
{
|
||||
text: 'Connect',
|
||||
tag: 'button',
|
||||
},
|
||||
10000,
|
||||
);
|
||||
|
||||
await driver.delay(2000);
|
||||
|
||||
// approve install of snap
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.clickElement({
|
||||
text: 'Approve & Install',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// click send inputs on test snap page
|
||||
await driver.waitUntilXWindowHandles(1, 5000, 10000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle('Test Snaps', windowHandles);
|
||||
await driver.clickElement({
|
||||
text: 'Send Test to Error Snap',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
await driver.navigate(PAGES.HOME);
|
||||
|
||||
const error = await driver.findElement(
|
||||
'.home-notification__content-container',
|
||||
);
|
||||
const text = await error.getText();
|
||||
assert.equal(
|
||||
text.includes(
|
||||
"Snap Error: 'random error inside'. Error Code: '-32603'",
|
||||
),
|
||||
true,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
@ -69,7 +69,7 @@ class ChromeDriver {
|
||||
for (let i = 0; i < extensions.length; i++) {
|
||||
const extension = extensions[i].shadowRoot
|
||||
const name = extension.querySelector('#name').textContent
|
||||
if (name === "${extensionName}") {
|
||||
if (name.startsWith("${extensionName}")) {
|
||||
return extensions[i].getAttribute("id")
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ class Driver {
|
||||
const ignoredLogTypes = ['WARNING'];
|
||||
const ignoredErrorMessages = [
|
||||
// Third-party Favicon 404s show up as errors
|
||||
'favicon.ico - Failed to load resource: the server responded with a status of 404 (Not Found)',
|
||||
'favicon.ico - Failed to load resource: the server responded with a status of 404',
|
||||
// Sentry rate limiting
|
||||
'Failed to load resource: the server responded with a status of 429',
|
||||
// 4Byte
|
||||
|
@ -4,7 +4,8 @@ const path = require('path');
|
||||
const { Builder, By, until } = require('selenium-webdriver');
|
||||
const firefox = require('selenium-webdriver/firefox');
|
||||
const proxy = require('selenium-webdriver/proxy');
|
||||
const { version } = require('../../../package.json');
|
||||
const { getVersion } = require('../../../development/lib/get-version');
|
||||
const { BuildType } = require('../../../development/lib/build-type');
|
||||
|
||||
/**
|
||||
* The prefix for temporary Firefox profiles. All Firefox profiles used for e2e tests
|
||||
@ -31,9 +32,10 @@ class FirefoxDriver {
|
||||
* @param {Object} options - the options for the build
|
||||
* @param options.responsive
|
||||
* @param options.port
|
||||
* @param options.type
|
||||
* @returns {Promise<{driver: !ThenableWebDriver, extensionUrl: string, extensionId: string}>}
|
||||
*/
|
||||
static async build({ responsive, port }) {
|
||||
static async build({ responsive, port, type }) {
|
||||
const templateProfile = fs.mkdtempSync(TEMP_PROFILE_PATH_PREFIX);
|
||||
const options = new firefox.Options().setProfile(templateProfile);
|
||||
options.setProxy(proxy.manual({ https: HTTPS_PROXY_HOST }));
|
||||
@ -48,9 +50,14 @@ class FirefoxDriver {
|
||||
const driver = builder.build();
|
||||
const fxDriver = new FirefoxDriver(driver);
|
||||
|
||||
const extensionId = await fxDriver.installExtension(
|
||||
`builds/metamask-firefox-${version}.zip`,
|
||||
);
|
||||
const version = getVersion(type || BuildType.main, 0);
|
||||
let extensionString = `builds/metamask-firefox-${version}.zip`;
|
||||
|
||||
if (type) {
|
||||
extensionString = `builds/metamask-${type}-firefox-${version}.zip`;
|
||||
}
|
||||
|
||||
const extensionId = await fxDriver.installExtension(extensionString);
|
||||
const internalExtensionId = await fxDriver.getInternalId();
|
||||
|
||||
if (responsive) {
|
||||
|
@ -4,14 +4,14 @@ const Driver = require('./driver');
|
||||
const ChromeDriver = require('./chrome');
|
||||
const FirefoxDriver = require('./firefox');
|
||||
|
||||
async function buildWebDriver({ responsive, port } = {}) {
|
||||
async function buildWebDriver({ responsive, port, type } = {}) {
|
||||
const browser = process.env.SELENIUM_BROWSER;
|
||||
|
||||
const {
|
||||
driver: seleniumDriver,
|
||||
extensionId,
|
||||
extensionUrl,
|
||||
} = await buildBrowserWebDriver(browser, { responsive, port });
|
||||
} = await buildBrowserWebDriver(browser, { responsive, port, type });
|
||||
await setupFetchMocking(seleniumDriver);
|
||||
const driver = new Driver(seleniumDriver, browser, extensionUrl);
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
@import 'edit-gas-fee-popover/edit-gas-tooltip/index';
|
||||
@import 'flask/experimental-area/index';
|
||||
@import 'flask/snap-install-warning/index';
|
||||
@import 'flask/snap-remove-warning/index';
|
||||
@import 'flask/snap-settings-card/index';
|
||||
@import 'flask/snaps-authorship-pill/index';
|
||||
@import 'gas-customization/gas-modal-page-container/index';
|
||||
|
@ -7,10 +7,6 @@
|
||||
gap: 0 16px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 0 16px 24px;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
|
@ -43,21 +43,22 @@ export default function SnapInstallWarning({ onCancel, onSubmit, snapName }) {
|
||||
className="snap-install-warning"
|
||||
title={t('areYouSure')}
|
||||
footer={<SnapInstallWarningFooter />}
|
||||
headerProps={{ padding: [6, 6, 0] }}
|
||||
contentProps={{ padding: [0, 6, 4] }}
|
||||
footerProps={{ padding: [4, 6] }}
|
||||
>
|
||||
<div className="snap-install-warning__content">
|
||||
<Typography variant={TYPOGRAPHY.H6} boxProps={{ paddingBottom: 4 }}>
|
||||
{t('snapInstallWarningCheck')}
|
||||
</Typography>
|
||||
<div className="checkbox-label">
|
||||
<CheckBox
|
||||
checked={isConfirmed}
|
||||
id="warning-accept"
|
||||
onClick={onCheckboxClicked}
|
||||
/>
|
||||
<label htmlFor="warning-accept">
|
||||
{t('snapInstallWarningKeyAccess', [snapName])}
|
||||
</label>
|
||||
</div>
|
||||
<Typography variant={TYPOGRAPHY.H6} boxProps={{ paddingBottom: 4 }}>
|
||||
{t('snapInstallWarningCheck')}
|
||||
</Typography>
|
||||
<div className="checkbox-label">
|
||||
<CheckBox
|
||||
checked={isConfirmed}
|
||||
id="warning-accept"
|
||||
onClick={onCheckboxClicked}
|
||||
/>
|
||||
<label htmlFor="warning-accept">
|
||||
{t('snapInstallWarningKeyAccess', [snapName])}
|
||||
</label>
|
||||
</div>
|
||||
</Popover>
|
||||
);
|
||||
|
1
ui/components/app/flask/snap-remove-warning/index.js
Normal file
1
ui/components/app/flask/snap-remove-warning/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './snap-remove-warning';
|
12
ui/components/app/flask/snap-remove-warning/index.scss
Normal file
12
ui/components/app/flask/snap-remove-warning/index.scss
Normal file
@ -0,0 +1,12 @@
|
||||
.snap-remove-warning {
|
||||
color: var(--black);
|
||||
|
||||
&__footer-button {
|
||||
height: 40px;
|
||||
margin-inline-end: 24px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useI18nContext } from '../../../../hooks/useI18nContext';
|
||||
import Typography from '../../../ui/typography/typography';
|
||||
import { TYPOGRAPHY } from '../../../../helpers/constants/design-system';
|
||||
import Box from '../../../ui/box/box';
|
||||
import Popover from '../../../ui/popover';
|
||||
import Button from '../../../ui/button';
|
||||
|
||||
export default function SnapRemoveWarning({ onCancel, onSubmit, snapName }) {
|
||||
const t = useI18nContext();
|
||||
|
||||
const SnapRemoveWarningFooter = () => {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className="snap-remove-warning__footer-button"
|
||||
type="default"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t('nevermind')}
|
||||
</Button>
|
||||
<Button
|
||||
className="snap-remove-warning__footer-button"
|
||||
type="danger-primary"
|
||||
onClick={onSubmit}
|
||||
>
|
||||
{t('removeSnap')}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover
|
||||
className="snap-remove-warning"
|
||||
title={t('pleaseConfirm')}
|
||||
footer={<SnapRemoveWarningFooter />}
|
||||
onClose={onCancel}
|
||||
headerProps={{ padding: [6, 4, 0, 6] }}
|
||||
>
|
||||
<Box paddingRight={4} paddingBottom={4} paddingLeft={6}>
|
||||
<Typography variant={TYPOGRAPHY.H4}>
|
||||
{t('removeSnapConfirmation', [snapName])}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
SnapRemoveWarning.propTypes = {
|
||||
/**
|
||||
* onCancel handler
|
||||
*/
|
||||
onCancel: PropTypes.func,
|
||||
/**
|
||||
* onSubmit handler
|
||||
*/
|
||||
onSubmit: PropTypes.func,
|
||||
/**
|
||||
* Name of snap
|
||||
*/
|
||||
snapName: PropTypes.string,
|
||||
};
|
@ -180,7 +180,7 @@ const SnapSettingsCard = ({
|
||||
tag="span"
|
||||
className="snap-settings-card__version"
|
||||
>
|
||||
v {version}
|
||||
{t('shorthandVersion', [version])}
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
|
@ -53,6 +53,7 @@
|
||||
}
|
||||
|
||||
&__requested {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@ -91,6 +92,7 @@
|
||||
}
|
||||
|
||||
&__permissions-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 38px;
|
||||
|
@ -5,12 +5,24 @@ import Box from '../../ui/box';
|
||||
import {
|
||||
FLEX_DIRECTION,
|
||||
JUSTIFY_CONTENT,
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
COLORS,
|
||||
TYPOGRAPHY,
|
||||
TEXT_ALIGN,
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
} from '../../../helpers/constants/design-system';
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
import SnapsAuthorshipPill from '../flask/snaps-authorship-pill';
|
||||
import Typography from '../../ui/typography';
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
|
||||
export default class PermissionsConnectHeader extends Component {
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
|
||||
static propTypes = {
|
||||
iconUrl: PropTypes.string,
|
||||
iconName: PropTypes.string.isRequired,
|
||||
@ -20,6 +32,7 @@ export default class PermissionsConnectHeader extends Component {
|
||||
headerText: PropTypes.string,
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
npmPackageName: PropTypes.string,
|
||||
snapVersion: PropTypes.string,
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
};
|
||||
|
||||
@ -47,10 +60,12 @@ export default class PermissionsConnectHeader extends Component {
|
||||
headerText,
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
npmPackageName,
|
||||
snapVersion,
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
} = this.props;
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
const npmPackageUrl = `https://www.npmjs.com/package/${npmPackageName}`;
|
||||
const { t } = this.context;
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
return (
|
||||
<Box
|
||||
@ -71,6 +86,24 @@ export default class PermissionsConnectHeader extends Component {
|
||||
) : null
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
}
|
||||
{
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
snapVersion && (
|
||||
<Typography
|
||||
boxProps={{
|
||||
margin: [2, 0],
|
||||
}}
|
||||
color={COLORS.TEXT_MUTED}
|
||||
variant={TYPOGRAPHY.H7}
|
||||
align={TEXT_ALIGN.CENTER}
|
||||
tag="span"
|
||||
className="version"
|
||||
>
|
||||
{t('shorthandVersion', [snapVersion])}
|
||||
</Typography>
|
||||
)
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
}
|
||||
<div className="permissions-connect-header__subtitle">{headerText}</div>
|
||||
</Box>
|
||||
);
|
||||
|
@ -1,7 +1,10 @@
|
||||
.permissions-connect-permission-list {
|
||||
width: 100%;
|
||||
|
||||
.permission {
|
||||
@include H6;
|
||||
|
||||
width: 100%;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid var(--Grey-100);
|
||||
display: flex;
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
|
||||
|
||||
import Popover from './popover.component';
|
||||
|
||||
# Popover
|
||||
|
||||
A modal component to show info
|
||||
|
||||
<Canvas>
|
||||
<Story id="ui-components-ui-popover-popover-stories-js--default-story" />
|
||||
</Canvas>
|
||||
|
||||
## Component API
|
||||
|
||||
<ArgsTable of={Popover} />
|
||||
|
@ -21,12 +21,7 @@
|
||||
}
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
padding: 24px 16px 16px;
|
||||
flex-direction: column;
|
||||
background: white;
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
|
||||
&__title {
|
||||
display: flex;
|
||||
@ -78,13 +73,8 @@
|
||||
&-content {
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&-container {
|
||||
@ -100,11 +90,7 @@
|
||||
}
|
||||
|
||||
&-footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
border-top: 1px solid #d2d8dd;
|
||||
padding: 16px 24px 24px;
|
||||
|
||||
> :only-child {
|
||||
margin: 0 auto;
|
||||
|
@ -3,6 +3,34 @@ import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import Box from '../box';
|
||||
import {
|
||||
ALIGN_ITEMS,
|
||||
FLEX_DIRECTION,
|
||||
JUSTIFY_CONTENT,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
|
||||
const defaultHeaderProps = {
|
||||
padding: [6, 4, 4],
|
||||
display: 'flex',
|
||||
flexDirection: FLEX_DIRECTION.COLUMN,
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 'xl',
|
||||
};
|
||||
|
||||
const defaultContentProps = {
|
||||
display: 'flex',
|
||||
flexDirection: FLEX_DIRECTION.COLUMN,
|
||||
justifyContent: JUSTIFY_CONTENT.FLEX_START,
|
||||
alignItems: ALIGN_ITEMS.STRETCH,
|
||||
borderRadius: 'xl',
|
||||
};
|
||||
|
||||
const defaultFooterProps = {
|
||||
display: 'flex',
|
||||
justifyContent: JUSTIFY_CONTENT.SPACE_BETWEEN,
|
||||
padding: [4, 6, 6],
|
||||
};
|
||||
|
||||
const Popover = ({
|
||||
title,
|
||||
@ -18,9 +46,50 @@ const Popover = ({
|
||||
CustomBackground,
|
||||
popoverRef,
|
||||
centerTitle,
|
||||
headerProps = defaultHeaderProps,
|
||||
contentProps = defaultContentProps,
|
||||
footerProps = defaultFooterProps,
|
||||
}) => {
|
||||
const t = useI18nContext();
|
||||
const showHeader = title || onBack || subtitle || onClose;
|
||||
const Header = () => {
|
||||
return (
|
||||
<Box
|
||||
{...{ ...defaultHeaderProps, ...headerProps }}
|
||||
className="popover-header"
|
||||
>
|
||||
<div
|
||||
className={classnames(
|
||||
'popover-header__title',
|
||||
centerTitle ? 'center' : '',
|
||||
)}
|
||||
>
|
||||
<h2 title="popover">
|
||||
{onBack ? (
|
||||
<button
|
||||
className="fas fa-chevron-left popover-header__button"
|
||||
title={t('back')}
|
||||
onClick={onBack}
|
||||
/>
|
||||
) : null}
|
||||
{title}
|
||||
</h2>
|
||||
{onClose ? (
|
||||
<button
|
||||
className="fas fa-times popover-header__button"
|
||||
title={t('close')}
|
||||
data-testid="popover-close"
|
||||
onClick={onClose}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
{subtitle ? (
|
||||
<p className="popover-header__subtitle">{subtitle}</p>
|
||||
) : null}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="popover-container">
|
||||
{CustomBackground ? (
|
||||
@ -33,47 +102,22 @@ const Popover = ({
|
||||
ref={popoverRef}
|
||||
>
|
||||
{showArrow ? <div className="popover-arrow" /> : null}
|
||||
{showHeader && (
|
||||
<header className="popover-header">
|
||||
<div
|
||||
className={classnames(
|
||||
'popover-header__title',
|
||||
centerTitle ? 'center' : '',
|
||||
)}
|
||||
>
|
||||
<h2 title="popover">
|
||||
{onBack ? (
|
||||
<button
|
||||
className="fas fa-chevron-left popover-header__button"
|
||||
title={t('back')}
|
||||
onClick={onBack}
|
||||
/>
|
||||
) : null}
|
||||
{title}
|
||||
</h2>
|
||||
{onClose ? (
|
||||
<button
|
||||
className="fas fa-times popover-header__button"
|
||||
title={t('close')}
|
||||
data-testid="popover-close"
|
||||
onClick={onClose}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
{subtitle ? (
|
||||
<p className="popover-header__subtitle">{subtitle}</p>
|
||||
) : null}
|
||||
</header>
|
||||
)}
|
||||
{showHeader && <Header />}
|
||||
{children ? (
|
||||
<div className={classnames('popover-content', contentClassName)}>
|
||||
<Box
|
||||
className={classnames('popover-content', contentClassName)}
|
||||
{...{ ...defaultContentProps, ...contentProps }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</Box>
|
||||
) : null}
|
||||
{footer ? (
|
||||
<footer className={classnames('popover-footer', footerClassName)}>
|
||||
<Box
|
||||
className={classnames('popover-footer', footerClassName)}
|
||||
{...{ ...defaultFooterProps, ...footerProps }}
|
||||
>
|
||||
{footer}
|
||||
</footer>
|
||||
</Box>
|
||||
) : null}
|
||||
</section>
|
||||
</div>
|
||||
@ -132,6 +176,18 @@ Popover.propTypes = {
|
||||
* Check if use centered title
|
||||
*/
|
||||
centerTitle: PropTypes.bool,
|
||||
/**
|
||||
* Box props for the header
|
||||
*/
|
||||
headerProps: PropTypes.shape({ ...Box.propTypes }),
|
||||
/**
|
||||
* Box props for the content
|
||||
*/
|
||||
contentProps: PropTypes.shape({ ...Box.propTypes }),
|
||||
/**
|
||||
* Box props for the footer
|
||||
*/
|
||||
footerProps: PropTypes.shape({ ...Box.propTypes }),
|
||||
};
|
||||
|
||||
export default class PopoverPortal extends PureComponent {
|
||||
|
@ -1,18 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import Button from '../button';
|
||||
import Box from '../box';
|
||||
import README from './README.mdx';
|
||||
import Popover from './popover.component';
|
||||
|
||||
export default {
|
||||
title: 'Components/UI/Popover',
|
||||
id: __filename,
|
||||
component: Popover,
|
||||
parameters: {
|
||||
docs: {
|
||||
page: README,
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
title: { control: 'text' },
|
||||
subtitle: { control: 'text' },
|
||||
@ -26,6 +20,21 @@ export default {
|
||||
showArrow: { control: 'boolean' },
|
||||
popoverRef: { control: 'object' },
|
||||
centerTitle: { control: 'boolean' },
|
||||
headerProps: {
|
||||
control: 'object',
|
||||
description:
|
||||
'Box component props used to add container CSS for the header',
|
||||
},
|
||||
contentProps: {
|
||||
control: 'object',
|
||||
description:
|
||||
'Box component props used to add container CSS for the content',
|
||||
},
|
||||
footerProps: {
|
||||
control: 'object',
|
||||
description:
|
||||
'Box component props used to add container CSS for the footer',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.version {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.page-container__footer {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -75,16 +75,18 @@ export default function SnapInstall({
|
||||
headerText={null} // TODO(ritave): Add header text when snaps support description
|
||||
siteOrigin={targetSubjectMetadata.origin}
|
||||
npmPackageName={npmId}
|
||||
snapVersion={targetSubjectMetadata.version}
|
||||
boxProps={{ alignItems: ALIGN_ITEMS.CENTER }}
|
||||
/>
|
||||
<Typography></Typography>
|
||||
<Box
|
||||
className="snap-requests-permission"
|
||||
padding={4}
|
||||
tag={TYPOGRAPHY.H7}
|
||||
<Typography
|
||||
boxProps={{
|
||||
padding: [4, 4, 0, 4],
|
||||
}}
|
||||
variant={TYPOGRAPHY.H7}
|
||||
tag="span"
|
||||
>
|
||||
<span>{t('snapRequestsPermission')}</span>
|
||||
</Box>
|
||||
{t('snapRequestsPermission')}
|
||||
</Typography>
|
||||
<PermissionsConnectPermissionList
|
||||
permissions={request.permissions || {}}
|
||||
/>
|
||||
@ -149,5 +151,6 @@ SnapInstall.propTypes = {
|
||||
name: PropTypes.string,
|
||||
origin: PropTypes.string.isRequired,
|
||||
sourceCode: PropTypes.string,
|
||||
version: PropTypes.string,
|
||||
}).isRequired,
|
||||
};
|
||||
|
@ -43,7 +43,7 @@ export default class PermissionConnect extends Component {
|
||||
extensionId: PropTypes.string,
|
||||
iconUrl: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
origin: PropTypes.string.isRequired,
|
||||
origin: PropTypes.string,
|
||||
subjectType: PropTypes.string,
|
||||
}),
|
||||
isRequestingAccounts: PropTypes.bool.isRequired,
|
||||
|
@ -6,8 +6,6 @@
|
||||
}
|
||||
|
||||
&__subheader {
|
||||
@include H4;
|
||||
|
||||
padding: 16px 4px;
|
||||
border-bottom: 1px solid var(--alto);
|
||||
margin-right: 24px;
|
||||
@ -51,12 +49,18 @@
|
||||
}
|
||||
|
||||
&__toggle-container {
|
||||
margin-left: auto;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
padding-left: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
&__toggle-button {
|
||||
margin-right: -12px;
|
||||
}
|
||||
|
||||
&__content-container {
|
||||
@media screen and (max-width: $break-small) {
|
||||
width: 100%;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import Button from '../../../../components/ui/button';
|
||||
@ -12,6 +12,7 @@ import {
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import SnapsAuthorshipPill from '../../../../components/app/flask/snaps-authorship-pill';
|
||||
import Box from '../../../../components/ui/box';
|
||||
import SnapRemoveWarning from '../../../../components/app/flask/snap-remove-warning';
|
||||
import ToggleButton from '../../../../components/ui/toggle-button';
|
||||
import PermissionsConnectPermissionList from '../../../../components/app/permissions-connect-permission-list/permissions-connect-permission-list';
|
||||
import ConnectedSitesList from '../../../../components/app/connected-sites-list';
|
||||
@ -39,6 +40,8 @@ function ViewSnap() {
|
||||
return snapState.id === decoded;
|
||||
});
|
||||
|
||||
const [isShowingRemoveWarning, setIsShowingRemoveWarning] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!snap) {
|
||||
history.push(SNAPS_LIST_ROUTE);
|
||||
@ -86,15 +89,12 @@ function ViewSnap() {
|
||||
url={authorshipPillUrl}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
paddingLeft={4}
|
||||
className="snap-settings-card__toggle-container view-snap__toggle-container"
|
||||
>
|
||||
<Box paddingLeft={4} className="view-snap__toggle-container">
|
||||
<Tooltip interactive position="bottom" html={t('snapsToggle')}>
|
||||
<ToggleButton
|
||||
value={snap.enabled}
|
||||
onToggle={onToggle}
|
||||
className="snap-settings-card__toggle-container__toggle-button"
|
||||
className="view-snap__toggle-button"
|
||||
/>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
@ -155,12 +155,19 @@ function ViewSnap() {
|
||||
css={{
|
||||
maxWidth: '175px',
|
||||
}}
|
||||
onClick={async () => {
|
||||
await dispatch(removeSnap(snap));
|
||||
}}
|
||||
onClick={() => setIsShowingRemoveWarning(true)}
|
||||
>
|
||||
{t('removeSnap')}
|
||||
</Button>
|
||||
{isShowingRemoveWarning && (
|
||||
<SnapRemoveWarning
|
||||
onCancel={() => setIsShowingRemoveWarning(false)}
|
||||
onSubmit={async () => {
|
||||
await dispatch(removeSnap(snap));
|
||||
}}
|
||||
snapName={snap.manifest.proposedName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
</div>
|
||||
|
139
yarn.lock
139
yarn.lock
@ -2707,6 +2707,46 @@
|
||||
web3 "^0.20.7"
|
||||
web3-provider-engine "^16.0.3"
|
||||
|
||||
"@metamask/controllers@^26.0.0":
|
||||
version "26.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/controllers/-/controllers-26.0.0.tgz#3df4a3071ffb26d357ba99f288d52fb9d913c35a"
|
||||
integrity sha512-iAWDoP/omxGzPfYyBFRNPJ32zcYvZHnUhIM2LyWoCwQj9ZYC1qh+dDX6I0O5jEeQcBrEb+Nl6AcnwHKVdEUz5Q==
|
||||
dependencies:
|
||||
"@ethereumjs/common" "^2.3.1"
|
||||
"@ethereumjs/tx" "^3.2.1"
|
||||
"@metamask/contract-metadata" "^1.31.0"
|
||||
"@metamask/metamask-eth-abis" "3.0.0"
|
||||
"@metamask/types" "^1.1.0"
|
||||
"@types/uuid" "^8.3.0"
|
||||
abort-controller "^3.0.0"
|
||||
async-mutex "^0.2.6"
|
||||
babel-runtime "^6.26.0"
|
||||
deep-freeze-strict "^1.1.1"
|
||||
eth-ens-namehash "^2.0.8"
|
||||
eth-json-rpc-infura "^5.1.0"
|
||||
eth-keyring-controller "^6.2.1"
|
||||
eth-method-registry "1.1.0"
|
||||
eth-phishing-detect "^1.1.14"
|
||||
eth-query "^2.1.2"
|
||||
eth-rpc-errors "^4.0.0"
|
||||
eth-sig-util "^3.0.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
ethereumjs-wallet "^1.0.1"
|
||||
ethers "^5.4.1"
|
||||
ethjs-unit "^0.1.6"
|
||||
fast-deep-equal "^3.1.3"
|
||||
immer "^9.0.6"
|
||||
isomorphic-fetch "^3.0.0"
|
||||
json-rpc-engine "^6.1.0"
|
||||
jsonschema "^1.2.4"
|
||||
multiformats "^9.5.2"
|
||||
nanoid "^3.1.31"
|
||||
punycode "^2.1.1"
|
||||
single-call-balance-checker-abi "^1.0.0"
|
||||
uuid "^8.3.2"
|
||||
web3 "^0.20.7"
|
||||
web3-provider-engine "^16.0.3"
|
||||
|
||||
"@metamask/controllers@^27.0.0":
|
||||
version "27.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/controllers/-/controllers-27.0.0.tgz#23fb24960880047635a7e0b226375b843f385ad1"
|
||||
@ -2806,22 +2846,37 @@
|
||||
resolved "https://registry.yarnpkg.com/@metamask/etherscan-link/-/etherscan-link-2.1.0.tgz#c0be8e68445b7b83cf85bcc03a56cdf8e256c973"
|
||||
integrity sha512-ADuWlTUkFfN2vXlz81Bg/0BA+XRor+CdK1055p6k7H6BLIPoDKn9SBOFld9haQFuR9cKh/JYHcnlSIv5R4fUEw==
|
||||
|
||||
"@metamask/execution-environments@^0.10.6":
|
||||
version "0.10.6"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/execution-environments/-/execution-environments-0.10.6.tgz#930ff056e63accf7ab7a59a28bd99064d217599c"
|
||||
integrity sha512-6ID8vzmIiy418LqRiDKPuDl0RBhHmDMzhgyb65ia6zZNDXKhsBotF/lNMhtHlsAbD9+3XYhi/Nl6YprJxaRisA==
|
||||
dependencies:
|
||||
"@metamask/object-multiplex" "^1.2.0"
|
||||
"@metamask/post-message-stream" "^4.0.0"
|
||||
"@metamask/providers" "^8.1.1"
|
||||
"@metamask/snap-types" "^0.10.6"
|
||||
cross-fetch "^3.1.5"
|
||||
eth-rpc-errors "^4.0.3"
|
||||
pump "^3.0.0"
|
||||
ses "^0.15.7"
|
||||
stream-browserify "^3.0.0"
|
||||
|
||||
"@metamask/forwarder@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/forwarder/-/forwarder-1.1.0.tgz#13829d8244bbf19ea658c0b20d21a77b67de0bdd"
|
||||
integrity sha512-Hggj4y0QIjDzKGTXzarhEPIQyFSB2bi2y6YLJNwaT4JmP30UB5Cj6gqoY0M4pj3QT57fzp0BUuGp7F/AUe28tw==
|
||||
|
||||
"@metamask/iframe-execution-environment-service@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/iframe-execution-environment-service/-/iframe-execution-environment-service-0.9.0.tgz#721e15ee4651741a599940dbcfa524cc55eaaa47"
|
||||
integrity sha512-a240sg83sX1dxfBDdRd0uoujaN4V9VtHKELMcTMgpYCI0uE83//Q01a7L8MiBtLhzr8o4D/xXRUIDR0Y9NKc3Q==
|
||||
"@metamask/iframe-execution-environment-service@^0.10.6":
|
||||
version "0.10.6"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/iframe-execution-environment-service/-/iframe-execution-environment-service-0.10.6.tgz#ba7e5499efba2018cef38fff916eaabbfbe1b27b"
|
||||
integrity sha512-BZbE4+CffNmD1J7Mpvh/evvKcDuP82Jl9panIV0JKzddG8zzOi9xlGtImYf8QWjwN5zx2TyTHAb/WxA+R+nFzw==
|
||||
dependencies:
|
||||
"@metamask/controllers" "^25.1.0"
|
||||
"@metamask/controllers" "^26.0.0"
|
||||
"@metamask/execution-environments" "^0.10.6"
|
||||
"@metamask/object-multiplex" "^1.2.0"
|
||||
"@metamask/post-message-stream" "^4.0.0"
|
||||
"@metamask/snap-controllers" "^0.9.0"
|
||||
"@metamask/snap-types" "^0.9.0"
|
||||
"@metamask/snap-workers" "^0.9.0"
|
||||
"@metamask/snap-controllers" "^0.10.6"
|
||||
"@metamask/snap-types" "^0.10.6"
|
||||
eth-rpc-errors "^4.0.3"
|
||||
json-rpc-engine "^6.1.0"
|
||||
json-rpc-middleware-stream "^3.0.0"
|
||||
@ -2915,13 +2970,15 @@
|
||||
pump "^3.0.0"
|
||||
webextension-polyfill-ts "^0.25.0"
|
||||
|
||||
"@metamask/rpc-methods@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/rpc-methods/-/rpc-methods-0.9.0.tgz#eb55cc39d2ea9a663211e8d805bdf566af70c764"
|
||||
integrity sha512-wii0TMuRscet8+x3tqfAcEmY0TrMFzOnD3QFpFVUy3fznv4b/EzDD/XLQToafd2yUaDjUrrS9FHwU9omqzPxcg==
|
||||
"@metamask/rpc-methods@^0.10.6":
|
||||
version "0.10.6"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/rpc-methods/-/rpc-methods-0.10.6.tgz#6e91c2bf33c909e203db438effec6663da4e8692"
|
||||
integrity sha512-cPqAQExwZGRLqtl22HUBVblr/tIAm/aI3ZMt6QKhwymwU7f/yM+4BOZB1M3+dVlhcIfX1SFFxDW3rFe+MsCksA==
|
||||
dependencies:
|
||||
"@metamask/controllers" "^26.0.0"
|
||||
"@metamask/key-tree" "^3.0.1"
|
||||
"@metamask/snap-controllers" "^0.9.0"
|
||||
"@metamask/snap-controllers" "^0.10.6"
|
||||
"@metamask/types" "^1.1.0"
|
||||
eth-rpc-errors "^4.0.2"
|
||||
|
||||
"@metamask/safe-event-emitter@^2.0.0":
|
||||
@ -2947,20 +3004,22 @@
|
||||
isomorphic-fetch "^3.0.0"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@metamask/snap-controllers@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/snap-controllers/-/snap-controllers-0.9.0.tgz#e0006fc9991e995dd86dff792106990aae2aeda0"
|
||||
integrity sha512-os3fEai0w4ctpyy6ExlthY8tnww98Vm+RVwOZgrCKDY5dAXqlSXpyWc1uOfkQyiPhUEJtdznJTWzaWzNIO9MfQ==
|
||||
"@metamask/snap-controllers@^0.10.6":
|
||||
version "0.10.6"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/snap-controllers/-/snap-controllers-0.10.6.tgz#72fc52271264c4ae8c986ce4d1a64c34505c7a8b"
|
||||
integrity sha512-Pa8g1dBVKtjkemRXFUPDQLnP8gcVmQpSgkTMK/m7tVqUinyZX7Gufq5wuApEh1pwRjMQ2R7he/zQn7oZ4qwTJw==
|
||||
dependencies:
|
||||
"@metamask/controllers" "^25.1.0"
|
||||
"@metamask/controllers" "^26.0.0"
|
||||
"@metamask/execution-environments" "^0.10.6"
|
||||
"@metamask/object-multiplex" "^1.1.0"
|
||||
"@metamask/obs-store" "^7.0.0"
|
||||
"@metamask/post-message-stream" "4.0.0"
|
||||
"@metamask/safe-event-emitter" "^2.0.0"
|
||||
"@metamask/snap-workers" "^0.9.0"
|
||||
"@types/deep-freeze-strict" "^1.1.0"
|
||||
"@types/semver" "^7.3.9"
|
||||
ajv "^8.8.2"
|
||||
concat-stream "^2.0.0"
|
||||
cross-fetch "^3.1.5"
|
||||
deep-freeze-strict "^1.1.1"
|
||||
eth-rpc-errors "^4.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
@ -2974,17 +3033,12 @@
|
||||
semver "^7.3.5"
|
||||
tar-stream "^2.2.0"
|
||||
|
||||
"@metamask/snap-types@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/snap-types/-/snap-types-0.9.0.tgz#aa164111be1b5c53fbaaf03c1bccbdbd0741daa4"
|
||||
integrity sha512-pK4tvurUhcKMEkTD0XvQze5HCbtrgmpFWDztBekNIMJTXDrnYIEw4Dxn+LwCX7WJ0DN/03brQSEzmIrYbcBw7Q==
|
||||
"@metamask/snap-types@^0.10.6":
|
||||
version "0.10.6"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/snap-types/-/snap-types-0.10.6.tgz#83e3eab797829a9f31906a27fa967a8096e5b704"
|
||||
integrity sha512-6eSc9hHhC+X133Nw6/WSUy0RWRipdOF3NBKgGFYJxCpvhkY4jGxQ1HAKDUZRzZ3eSewsmQ4hhhIQ+zczj0Subw==
|
||||
dependencies:
|
||||
"@metamask/controllers" "^25.1.0"
|
||||
|
||||
"@metamask/snap-workers@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/snap-workers/-/snap-workers-0.9.0.tgz#215407b632fef4723dd75af7accf1f02a6a46916"
|
||||
integrity sha512-+4YY5CQ7OPFPWh4QF5e4COgc0aWL6Df7Oc8/y//Sabp1rmXWI429OzCOlBi+NGJfQ1K7ORBMlRtOwYB9ZmWyLA==
|
||||
"@metamask/controllers" "^26.0.0"
|
||||
|
||||
"@metamask/test-dapp@^5.0.0":
|
||||
version "5.0.0"
|
||||
@ -4662,6 +4716,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/semver@^7.3.9":
|
||||
version "7.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc"
|
||||
integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==
|
||||
|
||||
"@types/source-list-map@*":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
||||
@ -8842,12 +8901,12 @@ cross-fetch@^2.1.0:
|
||||
node-fetch "2.1.2"
|
||||
whatwg-fetch "2.0.4"
|
||||
|
||||
cross-fetch@^3.1.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
|
||||
integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==
|
||||
cross-fetch@^3.1.4, cross-fetch@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
|
||||
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
|
||||
dependencies:
|
||||
node-fetch "2.6.1"
|
||||
node-fetch "2.6.7"
|
||||
|
||||
cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
version "7.0.3"
|
||||
@ -19714,12 +19773,7 @@ node-fetch@2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5"
|
||||
integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=
|
||||
|
||||
node-fetch@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-fetch@^2.3.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@~2.6.1:
|
||||
node-fetch@2.6.7, node-fetch@^2.3.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@~2.6.1:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
@ -24562,6 +24616,11 @@ ses@^0.12.4:
|
||||
"@agoric/make-hardener" "^0.1.2"
|
||||
"@agoric/transform-module" "^0.4.1"
|
||||
|
||||
ses@^0.15.7:
|
||||
version "0.15.11"
|
||||
resolved "https://registry.yarnpkg.com/ses/-/ses-0.15.11.tgz#851cb6a20d8967537075d25bb0185051c28c23db"
|
||||
integrity sha512-lQg6q8/PVf+n18EjP+5Uv1tN9oVQ3br5QxJzPXoAVQleSYnlf20JY9coe7n1B9A6CtIKIHyr6m/TfskcRCufgA==
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
|
Loading…
Reference in New Issue
Block a user