Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/snaps-cli/src/cmds/init/initHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
readJsonFile,
satisfiesVersionRange,
NpmSnapPackageJson,
SemVerVersion,
SemVerRange,
} from '@metamask/snaps-utils';
import { promises as fs } from 'fs';
import pathUtils from 'path';
Expand All @@ -19,7 +21,7 @@ import {
yarnInstall,
} from './initUtils';

const SATISFIED_VERSION = '>=16';
const SATISFIED_VERSION = '>=16' as SemVerRange;

/**
* Creates a new snap package, based on one of the provided templates. This
Expand All @@ -35,7 +37,7 @@ export async function initHandler(argv: YargsArgs) {
const { directory } = argv;

const isVersionSupported = satisfiesVersionRange(
process.version,
process.version as SemVerVersion,
SATISFIED_VERSION,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
HandlerType,
deepClone,
TruncatedSnap,
SemVerVersion,
} from '@metamask/snaps-utils';
import {
MOCK_ORIGIN,
Expand Down Expand Up @@ -77,6 +78,8 @@ const MOCK_CRONJOB_SINGLE_JOB_PERMISSION = {
parentCapability: SnapEndowments.Cronjob,
};

const MOCK_VERSION = '1.0' as SemVerVersion;

describe('CronjobController', () => {
beforeEach(() => {
jest.useFakeTimers().setSystemTime(new Date('2022-01-01'));
Expand Down Expand Up @@ -315,7 +318,7 @@ describe('CronjobController', () => {
id: MOCK_SNAP_ID,
initialPermissions: {},
permissionName: '',
version: '',
version: MOCK_VERSION,
};
// @ts-expect-error Accessing private property
cronjobController._handleEventSnapInstalled(snapInfo);
Expand Down Expand Up @@ -367,7 +370,7 @@ describe('CronjobController', () => {
id: MOCK_SNAP_ID,
initialPermissions: {},
permissionName: '',
version: '',
version: MOCK_VERSION,
};

// @ts-expect-error Accessing private property
Expand Down Expand Up @@ -432,7 +435,7 @@ describe('CronjobController', () => {
id: MOCK_SNAP_ID,
initialPermissions: {},
permissionName: '',
version: '',
version: MOCK_VERSION,
};

// @ts-expect-error Accessing private property
Expand Down
14 changes: 9 additions & 5 deletions packages/snaps-controllers/src/snaps/SnapController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
DEFAULT_ENDOWMENTS,
getSnapSourceShasum,
HandlerType,
SemVerVersion,
SnapCaveatType,
SnapManifest,
SnapStatus,
Expand Down Expand Up @@ -2545,7 +2546,7 @@ describe('SnapController', () => {
fetchSnapSpy.mockImplementationOnce(async () => {
const manifest: SnapManifest = {
...getSnapManifest(),
version: '1.1.0',
version: '1.1.0' as SemVerVersion,
};

return Promise.resolve({
Expand Down Expand Up @@ -2580,7 +2581,7 @@ describe('SnapController', () => {
fetchSnapSpy.mockImplementationOnce(async () => {
const manifest: SnapManifest = {
...getSnapManifest(),
version: '0.9.0',
version: '0.9.0' as SemVerVersion,
};

return Promise.resolve({
Expand Down Expand Up @@ -2625,7 +2626,7 @@ describe('SnapController', () => {
.mockImplementationOnce(async () => {
const manifest: SnapManifest = {
...getSnapManifest(),
version: '1.1.0',
version: '1.1.0' as SemVerVersion,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved to a constant on top of the file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not possible in this case. Tests that use specific versions instead of creation utils, do it because they're testing version/updates functionality.

};

return Promise.resolve({
Expand Down Expand Up @@ -2757,7 +2758,7 @@ describe('SnapController', () => {
fetchSnapSpy.mockImplementationOnce(async () => {
const manifest: SnapManifest = {
...getSnapManifest(),
version: '1.1.0',
version: '1.1.0' as SemVerVersion,
};

return Promise.resolve({
Expand Down Expand Up @@ -2864,7 +2865,7 @@ describe('SnapController', () => {
fetchSnapSpy.mockImplementationOnce(async () => {
const manifest: SnapManifest = {
...getSnapManifest(),
version: '1.1.0',
version: '1.1.0' as SemVerVersion,
};

return Promise.resolve({
Expand Down Expand Up @@ -3949,6 +3950,9 @@ describe('SnapController', () => {
) {
return true;
}
// TypeScript doesn't allow variadic list of arguments into non-variadic functions.
// messenger.call is a union of functions that take a constant amount of arguments, and
// so, TypeScript errors.
return (originalCall as any)(method, ...args);
Comment thread
ritave marked this conversation as resolved.
});

Expand Down
20 changes: 10 additions & 10 deletions packages/snaps-controllers/src/snaps/SnapController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ import {
getSnapPrefix,
gtVersion,
InstallSnapsResult,
isValidSnapVersionRange,
isValidSemVerRange,
LOCALHOST_HOSTNAMES,
NpmSnapFileNames,
PersistedSnap,
ProcessSnapResult,
RequestedSnapPermissions,
resolveVersion,
resolveVersionRange,
satisfiesVersionRange,
SemVerRange,
Snap,
SnapId,
SnapIdPrefixes,
Expand Down Expand Up @@ -536,7 +537,7 @@ type SnapControllerArgs = {
type AddSnapArgsBase = {
id: SnapId;
origin: string;
versionRange?: string;
versionRange?: SemVerRange;
};

// A snap can either be added directly, with manifest and source code, or it
Expand Down Expand Up @@ -1535,17 +1536,16 @@ export class SnapController extends BaseController<
await Promise.all(
Object.entries(requestedSnaps).map(
async ([snapId, { version: rawVersion }]) => {
const version = resolveVersion(rawVersion);
const permissionName = getSnapPermissionName(snapId);

if (!isValidSnapVersionRange(version)) {
const [error, version] = resolveVersionRange(rawVersion);
if (error) {
result[snapId] = {
error: ethErrors.rpc.invalidParams(
`The "version" field must be a valid SemVer version range if specified. Received: "${version}".`,
),
};
return;
}
const permissionName = getSnapPermissionName(snapId);

if (
this.messagingSystem.call(
Expand Down Expand Up @@ -1585,7 +1585,7 @@ export class SnapController extends BaseController<
private async processRequestedSnap(
origin: string,
snapId: SnapId,
versionRange: string,
versionRange: SemVerRange,
): Promise<ProcessSnapResult> {
try {
validateSnapId(snapId);
Expand Down Expand Up @@ -1688,7 +1688,7 @@ export class SnapController extends BaseController<
): Promise<TruncatedSnap | null> {
const snap = this.getExpect(snapId);

if (!isValidSnapVersionRange(newVersionRange)) {
if (!isValidSemVerRange(newVersionRange)) {
throw new Error(
`Received invalid snap version range: "${newVersionRange}".`,
);
Expand Down Expand Up @@ -2052,7 +2052,7 @@ export class SnapController extends BaseController<
packageName: string,
versionRange: string,
): Promise<FetchSnapResult> {
if (!isValidSnapVersionRange(versionRange)) {
if (!isValidSemVerRange(versionRange)) {
throw new Error(
`Received invalid Snap version range: "${versionRange}".`,
);
Expand Down
21 changes: 14 additions & 7 deletions packages/snaps-controllers/src/snaps/utils/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {
isValidUrl,
getTargetVersion,
validateNpmSnap,
assertIsSemVerVersion,
SemVerRange,
SemVerVersion,
} from '@metamask/snaps-utils';
import { isObject } from '@metamask/utils';
import createGunzipStream from 'gunzip-maybe';
Expand All @@ -26,7 +29,7 @@ export const DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org';
*/
export async function fetchNpmSnap(
packageName: string,
versionRange: string,
versionRange: SemVerRange,
registryUrl = DEFAULT_NPM_REGISTRY,
fetchFunction = fetch,
): Promise<SnapFiles> {
Expand Down Expand Up @@ -56,7 +59,7 @@ export async function fetchNpmSnap(
// object if they exist.
return validateNpmSnap(
snapFiles,
`npm Snap "${packageName}@${actualVersion}" validation error: `,
`npm Snap "${packageName}@${actualVersion}" validation error: ` as `${string}: `,
);
}

Expand All @@ -75,10 +78,10 @@ export async function fetchNpmSnap(
*/
async function fetchNpmTarball(
packageName: string,
versionRange: string,
versionRange: SemVerRange,
registryUrl = DEFAULT_NPM_REGISTRY,
fetchFunction = fetch,
): Promise<[ReadableStream, string]> {
): Promise<[ReadableStream, SemVerVersion]> {
const packageMetadata = await (
await fetchFunction(new URL(packageName, registryUrl).toString())
).json();
Expand All @@ -89,11 +92,15 @@ async function fetchNpmTarball(
);
}

const targetVersion = getTargetVersion(
Object.keys((packageMetadata as any)?.versions ?? {}),
versionRange,
const versions = Object.keys((packageMetadata as any)?.versions ?? {}).map(
(version) => {
assertIsSemVerVersion(version);
return version;
},
);

const targetVersion = getTargetVersion(versions, versionRange);

if (targetVersion === null) {
throw new Error(
`Failed to find a matching version in npm metadata for package "${packageName}" and requested semver range "${versionRange}"`,
Expand Down
8 changes: 4 additions & 4 deletions packages/snaps-utils/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ module.exports = deepmerge(baseConfig, {
],
coverageThreshold: {
global: {
branches: 93.15,
functions: 95.18,
lines: 98.07,
statements: 98.07,
branches: 93.45,
functions: 95.45,
lines: 98.34,
statements: 98.34,
},
},
testTimeout: 2500,
Expand Down
3 changes: 2 additions & 1 deletion packages/snaps-utils/src/manifest/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {

import { CronjobSpecificationArrayStruct } from '../cronjob';
import { NamespacesStruct } from '../namespace';
import { NameStruct, NpmSnapFileNames, VersionStruct } from '../types';
import { NameStruct, NpmSnapFileNames } from '../types';
import { VersionStruct } from '../versions';

// 0xd36e6170 - 0x80000000
export const SIP_6_MAGIC_VALUE = `1399742832'` as `${number}'`;
Expand Down
3 changes: 2 additions & 1 deletion packages/snaps-utils/src/snaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SerializedEthereumRpcError } from 'eth-rpc-errors/dist/classes';

import { SnapManifest, SnapPermissions } from './manifest/validation';
import { SnapId, SnapIdPrefixes, SnapValidationFailureReason } from './types';
import { SemVerVersion } from './versions';

export const LOCALHOST_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1']);
export const SNAP_PREFIX = 'wallet_snap_';
Expand Down Expand Up @@ -119,7 +120,7 @@ export type Snap = {
/**
* The version of the Snap.
*/
version: string;
version: SemVerVersion;

/**
* The version history of the Snap.
Expand Down
12 changes: 12 additions & 0 deletions packages/snaps-utils/src/test-utils/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { SemVerVersion } from '../versions';

/**
* Tens/hundreds legacy tests use creation utils.
*
* Updating them to use proper type casting is unfeasible at this time.
* We use this function to make creation utils backwards compatible,
* until we're ready to update tests.
*/
export type MakeSemVer<T> = {
[K in keyof T]: K extends 'version' ? SemVerVersion | string : T[K];
};
16 changes: 10 additions & 6 deletions packages/snaps-utils/src/test-utils/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ import {
SessionNamespace,
} from '../namespace';
import { NpmSnapPackageJson } from '../types';
import { SemVerVersion } from '../versions';
import { MakeSemVer } from './common';
import { DEFAULT_SNAP_SHASUM } from './snap';

type GetSnapManifestOptions = Partial<Omit<SnapManifest, 'source'>> & {
type GetSnapManifestOptions = Partial<MakeSemVer<SnapManifest>> & {
shasum?: string;
filePath?: string;
packageName?: string;
registry?: string;
iconPath?: string;
};

type GetPackageJsonOptions = Partial<MakeSemVer<NpmSnapPackageJson>>;

/**
* Get the default package repository, in a format compatible with
* `package.json`.
Expand Down Expand Up @@ -47,7 +51,7 @@ export const getDefaultRepository = () => {
* @returns The snap manifest.
*/
export const getSnapManifest = ({
version = '1.0.0',
version = '1.0.0' as SemVerVersion,
description = 'The test example snap!',
proposedName = '@metamask/example-snap',
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand All @@ -59,7 +63,7 @@ export const getSnapManifest = ({
iconPath = 'images/icon.svg',
}: GetSnapManifestOptions = {}): SnapManifest => {
return {
version,
version: version as SemVerVersion,
description,
proposedName,
repository,
Expand Down Expand Up @@ -94,14 +98,14 @@ export const getSnapManifest = ({
*/
export const getPackageJson = ({
name = '@metamask/example-snap',
version = '1.0.0',
version = '1.0.0' as SemVerVersion,
description = 'The test example snap!',
main = 'src/index.js',
repository = getDefaultRepository(),
}: Partial<NpmSnapPackageJson> = {}): NpmSnapPackageJson => {
}: GetPackageJsonOptions = {}): NpmSnapPackageJson => {
return {
name,
version,
version: version as SemVerVersion,
description,
main,
repository,
Expand Down
Loading