diff --git a/.github/workflows/lint-build-test.yml b/.github/workflows/lint-build-test.yml index bccdd6a61..c90912846 100644 --- a/.github/workflows/lint-build-test.yml +++ b/.github/workflows/lint-build-test.yml @@ -114,6 +114,7 @@ jobs: matrix: node-version: [24.x] script: + - lint:tsc - lint:eslint - lint:misc:check - constraints diff --git a/AGENTS.md b/AGENTS.md index e9941d065..ce98b4a70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,13 +46,14 @@ The monorepo uses a hierarchical configuration approach for different tools. For #### TypeScript -- `tsconfig.base.json` defines shared development-specific TypeScript settings for all other config files. -- `tsconfig.build.json` defines shared build-specific TypeScript settings for all other config files. -- `tsconfig.packages.json` defines shared development-specific TypeScript settings for all directories in `packages/`. -- `tsconfig.packages.build.json` defines shared build-specific TypeScript settings for all directories in `packages/`. +- `tsconfig.base.json` defines shared compiler defaults for all other config files. +- `tsconfig.json` defines TypeScript settings for repository scripts and editor features. +- `tsconfig.packages.json` defines shared source, editor, and type-checking settings for all packages. - `tsconfig.scripts.json` defines shared TypeScript settings for directories in `scripts/`. -- `packages/**/tsconfig.json` (and `scripts/create-package/package-template/tsconfig.json`) defines TypeScript settings for each package that are meant to be used by code editors and lint tasks. -- `packages/**/tsconfig.build.json` (and `scripts/create-package/package-template/tsconfig.build.json`) defines TypeScript settings for each package that are used to produce a build. +- The root `lint:tsc` script checks repository scripts with `tsconfig.json`, then checks each + workspace package configuration directly. It does not build Snap bundles with `tsc`. +- `packages/**/tsconfig.json` (and `scripts/create-package/package-template/tsconfig.json`) defines TypeScript settings for each package that are meant to be used by code editors and type checking. +- Library packages and the package template also have `tsconfig.build.json` files for `ts-bridge` declaration builds. Snap packages do not have build configs because `mm-snap` builds their bundles. - `scripts/create-package/tsconfig.json` customizes TypeScript settings for the `create-package` tool. #### Jest diff --git a/eslint-suppressions.json b/eslint-suppressions.json index bf14f99f3..b008be1d3 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -245,9 +245,6 @@ } }, "packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.ts": { - "@typescript-eslint/no-base-to-string": { - "count": 1 - }, "@typescript-eslint/no-explicit-any": { "count": 10 }, @@ -258,7 +255,7 @@ "count": 1 }, "@typescript-eslint/restrict-template-expressions": { - "count": 2 + "count": 1 }, "no-restricted-syntax": { "count": 1 diff --git a/jest.config.packages.js b/jest.config.packages.js index a7c6bc1e1..e7fbc4ab2 100644 --- a/jest.config.packages.js +++ b/jest.config.packages.js @@ -78,7 +78,7 @@ module.exports = { // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module // Here we ensure that Jest resolves `@metamask/*` imports to the uncompiled source code for packages that live in this repo. - // NOTE: This must be synchronized with the `paths` option in `tsconfig.base.json`. + // NOTE: This must be synchronized with the `paths` option in `tsconfig.packages.json`. moduleNameMapper: { '^@metamask/json-rpc-engine/v2$': [ '/../json-rpc-engine/src/v2/index.ts', diff --git a/package.json b/package.json index d14872289..89f67c73f 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,14 @@ "changelog:validate": "yarn workspaces foreach --all --no-private --parallel --interlaced --verbose run changelog:validate", "create-release-branch": "create-release-branch --formatter oxfmt", "create-package": "tsx scripts/create-package", - "lint": "yarn lint:eslint && echo && yarn lint:misc --check && yarn constraints && yarn lint:dependencies && yarn readme-content:check", + "lint": "yarn lint:tsc && yarn lint:eslint && echo && yarn lint:misc --check && yarn constraints && yarn lint:dependencies && yarn readme-content:check", "lint:dependencies": "depcheck && yarn dedupe --check", "lint:dependencies:fix": "depcheck && yarn dedupe", "lint:eslint": "yarn eslint", "lint:fix": "yarn lint:eslint --fix --prune-suppressions && echo && yarn lint:misc --write && yarn constraints --fix && yarn lint:dependencies:fix && yarn readme-content:update", "lint:misc": "oxfmt --ignore-path .gitignore", "lint:misc:check": "yarn lint:misc --check", + "lint:tsc": "tsc --project tsconfig.json && yarn workspaces foreach --all exec tsc --project tsconfig.json --noEmit", "prepack": "./scripts/prepack.sh", "readme-content:check": "tsx scripts/update-readme-content.ts --check", "readme-content:update": "tsx scripts/update-readme-content.ts", diff --git a/packages/bitcoin-wallet-snap/jest.config.mjs b/packages/bitcoin-wallet-snap/jest.config.mjs index e8bd87859..6448641e0 100644 --- a/packages/bitcoin-wallet-snap/jest.config.mjs +++ b/packages/bitcoin-wallet-snap/jest.config.mjs @@ -25,7 +25,7 @@ const config = { coverageThreshold: { global: { branches: 65.5, - functions: 62.64, + functions: 61.63, lines: 75.29, statements: 74.57, }, diff --git a/packages/bitcoin-wallet-snap/snap.config.ts b/packages/bitcoin-wallet-snap/snap.config.ts index 5fd9a71ec..e78c43244 100644 --- a/packages/bitcoin-wallet-snap/snap.config.ts +++ b/packages/bitcoin-wallet-snap/snap.config.ts @@ -6,6 +6,9 @@ dotenv(); const config: SnapConfig = { input: resolve(__dirname, 'src/index.ts'), + typescript: { + enabled: true, + }, server: { port: 8080, }, diff --git a/packages/bitcoin-wallet-snap/snap.manifest.json b/packages/bitcoin-wallet-snap/snap.manifest.json index 344e0a8c7..3fd7c0f9d 100644 --- a/packages/bitcoin-wallet-snap/snap.manifest.json +++ b/packages/bitcoin-wallet-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "ZEMZtj4BZq+pj3bzb81K1Vk5WQuqMA0NArfIhrIppds=", + "shasum": "N40X9yuzuO3nWtRwrVRhAMQC1+XOcB3Ay3sxYrg2YFA=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/bitcoin-wallet-snap/src/handlers/CronHandler.ts b/packages/bitcoin-wallet-snap/src/handlers/CronHandler.ts index c87557425..6384e37d0 100644 --- a/packages/bitcoin-wallet-snap/src/handlers/CronHandler.ts +++ b/packages/bitcoin-wallet-snap/src/handlers/CronHandler.ts @@ -1,5 +1,5 @@ import { getSelectedAccounts } from '@metamask/keyring-snap-sdk'; -import { InFlightCoalescer } from '@metamask/snap-networks-utils/dedupe'; +import { InFlightCoalescer } from '@metamask/snap-networks-utils'; import type { JsonRpcRequest, SnapsProvider } from '@metamask/snaps-sdk'; import { array, assert, object, string } from 'superstruct'; diff --git a/packages/bitcoin-wallet-snap/src/store/BdkAccountRepository.ts b/packages/bitcoin-wallet-snap/src/store/BdkAccountRepository.ts index 37998eabb..efae5c57b 100644 --- a/packages/bitcoin-wallet-snap/src/store/BdkAccountRepository.ts +++ b/packages/bitcoin-wallet-snap/src/store/BdkAccountRepository.ts @@ -8,6 +8,7 @@ import { xpriv_to_descriptor, xpub_to_descriptor, } from '@metamask/bitcoindevkit'; +import type { BIP32Node } from '@metamask/key-tree'; import { SLIP10Node } from '@metamask/key-tree'; import { v4 } from 'uuid'; @@ -271,7 +272,7 @@ export class BdkAccountRepository implements BitcoinAccountRepository { const parentNode = parentNodes.get(parentKey) as SLIP10Node; const childSegment = derivationPath[derivationPath.length - 1] as string; const childNode = ( - await parentNode.derive([`bip32:${childSegment}`]) + await parentNode.derive([`bip32:${childSegment}` as BIP32Node]) ).neuter(); accounts.push( diff --git a/packages/bitcoin-wallet-snap/tsconfig.json b/packages/bitcoin-wallet-snap/tsconfig.json index 34352b8df..e060c47ac 100644 --- a/packages/bitcoin-wallet-snap/tsconfig.json +++ b/packages/bitcoin-wallet-snap/tsconfig.json @@ -2,19 +2,25 @@ "extends": "../../tsconfig.packages.json", "compilerOptions": { "baseUrl": "./", - "lib": ["ES2021", "DOM"], - "resolveJsonModule": true /* lets us import JSON modules from within TypeScript modules. */, "jsx": "react-jsx", "jsxImportSource": "@metamask/snaps-sdk", + "resolveJsonModule": true, "exactOptionalPropertyTypes": false, "forceConsistentCasingInFileNames": true, "noErrorTruncation": true, "noUncheckedIndexedAccess": true, "skipLibCheck": true, - "module": "ESNext", + "lib": ["ES2023", "DOM"], + "target": "es2023", + "module": "preserve", "moduleResolution": "bundler", "types": ["jest"] }, - "references": [{ "path": "../snap-networks-utils" }], - "include": ["**/*.ts", "**/*.tsx", "locales/*.json"] + "include": [ + "**/*.ts", + "**/*.tsx", + "locales/*.json", + "snap.manifest.json", + "src/**/*.json" + ] } diff --git a/packages/sample-snap/snap.config.ts b/packages/sample-snap/snap.config.ts index 4ed32b8d9..1493daa6c 100644 --- a/packages/sample-snap/snap.config.ts +++ b/packages/sample-snap/snap.config.ts @@ -5,6 +5,9 @@ import { resolve } from 'path'; const config: SnapConfig = { // eslint-disable-next-line no-restricted-globals input: resolve(__dirname, 'src/index.tsx'), + typescript: { + enabled: true, + }, server: { port: 8080, }, diff --git a/packages/sample-snap/snap.manifest.json b/packages/sample-snap/snap.manifest.json index 2e1baf374..ec38e0e59 100644 --- a/packages/sample-snap/snap.manifest.json +++ b/packages/sample-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "7jzuMWjDr1T5dgRV5M6B8ZtNPxPBNmGV2JGWgkvtTdA=", + "shasum": "Sno6Wef4OjbtlPw43N9uwVEHYoNlIjEiAgdEIjqVd4c=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap-networks-utils/src/index.ts b/packages/snap-networks-utils/src/index.ts index a2b21e45a..739d3b53a 100644 --- a/packages/snap-networks-utils/src/index.ts +++ b/packages/snap-networks-utils/src/index.ts @@ -49,6 +49,7 @@ export { isSnapRpcError, normalizeError, } from './utils/errors'; +export { InFlightCoalescer } from './utils/dedupe/InFlightCoalescer'; export type { CreateSnapErrorHandlingOptions, CreateTrackErrorOptions, diff --git a/packages/snap-networks-utils/tsconfig.build.json b/packages/snap-networks-utils/tsconfig.build.json index 02a0eea03..f010fa5ac 100644 --- a/packages/snap-networks-utils/tsconfig.build.json +++ b/packages/snap-networks-utils/tsconfig.build.json @@ -1,10 +1,18 @@ { - "extends": "../../tsconfig.packages.build.json", + "extends": "./tsconfig.json", "compilerOptions": { "baseUrl": "./", + "composite": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "inlineSources": true, + "noEmit": false, + "sourceMap": true, "outDir": "./dist", "rootDir": "./src" }, "references": [], - "include": ["../../types", "./src"] + "include": ["../../types", "./src"], + "exclude": ["**/*.test.ts", "**/tests", "**/jest.config.ts"] } diff --git a/packages/snap-networks-utils/tsconfig.json b/packages/snap-networks-utils/tsconfig.json index 464677940..b0dc5d7d5 100644 --- a/packages/snap-networks-utils/tsconfig.json +++ b/packages/snap-networks-utils/tsconfig.json @@ -5,6 +5,5 @@ "skipLibCheck": true, "types": ["jest"] }, - "references": [], "include": ["../../types", "./src"] } diff --git a/packages/solana-wallet-snap/snap.config.ts b/packages/solana-wallet-snap/snap.config.ts index 0d2268a0f..15321d1dd 100644 --- a/packages/solana-wallet-snap/snap.config.ts +++ b/packages/solana-wallet-snap/snap.config.ts @@ -27,6 +27,9 @@ const environment = { const config: SnapConfig = { input: resolve(__dirname, 'src/index.ts'), + typescript: { + enabled: true, + }, server: { port: 8080, }, diff --git a/packages/solana-wallet-snap/snap.manifest.json b/packages/solana-wallet-snap/snap.manifest.json index a309f3d0b..ff45fdc18 100644 --- a/packages/solana-wallet-snap/snap.manifest.json +++ b/packages/solana-wallet-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "RP8K+BdAavCCQ3ZxXRx/CgH4ipA4Y2K/yCmqQTgHB8w=", + "shasum": "f67A1dy0bXl9jvoMuZ4heLBBs+m6bwaU20/WT30COeU=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/solana-wallet-snap/src/core/handlers/onClientRequest/validation.ts b/packages/solana-wallet-snap/src/core/handlers/onClientRequest/validation.ts index 463962023..5f585c6b3 100644 --- a/packages/solana-wallet-snap/src/core/handlers/onClientRequest/validation.ts +++ b/packages/solana-wallet-snap/src/core/handlers/onClientRequest/validation.ts @@ -398,7 +398,9 @@ export const ValidationResponseStruct = object({ valid: boolean(), errors: array( object({ - code: enums(Object.values(SendErrorCodes)), + code: enums( + Object.values(SendErrorCodes) as [SendErrorCodes, ...SendErrorCodes[]], + ), }), ), }); @@ -423,7 +425,7 @@ export const ComputeFeeRequestStruct = object({ export const ComputeFeeResponseStruct = array( object({ - type: enums(Object.values(FeeType)), + type: enums(Object.values(FeeType) as [FeeType, ...FeeType[]]), asset: AssetStruct, }), ); diff --git a/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.test.ts b/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.test.ts index 695433771..ef15003b0 100644 --- a/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.test.ts +++ b/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.test.ts @@ -10,6 +10,7 @@ import bs58 from 'bs58'; import type { AssetEntity } from '../../../entities'; import { asStrictKeyringAccount } from '../../../entities'; +import type { Caip10Address } from '../../constants/solana'; import { KnownCaip19Id, Network } from '../../constants/solana'; import type { AssetsService, @@ -414,7 +415,7 @@ describe('SolanaKeyring', () => { jsonrpc: '2.0', ...MOCK_SIGN_AND_SEND_TRANSACTION_REQUEST, } as unknown as JsonRpcRequest; - const mockResolvedAddress = `${mockScope}:resolved-address`; + const mockResolvedAddress: Caip10Address = `${mockScope}:resolved-address`; jest .spyOn(mockWalletService, 'resolveAccountAddress') diff --git a/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.ts b/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.ts index 34ab8aa71..54255041a 100644 --- a/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.ts +++ b/packages/solana-wallet-snap/src/core/handlers/onKeyringRequest/Keyring.ts @@ -24,8 +24,8 @@ import type { ExportedAccount, KeyringSnapRpc, } from '@metamask/keyring-api/v2'; -import { UuidStruct } from '@metamask/snap-networks-utils'; import type { Logger } from '@metamask/snap-networks-utils'; +import { UuidStruct } from '@metamask/snap-networks-utils'; import type { CaipAssetType, JsonRpcRequest } from '@metamask/snaps-sdk'; import { InvalidParamsError, diff --git a/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts b/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts index 5a00610bc..423467755 100644 --- a/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts +++ b/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts @@ -37,7 +37,7 @@ const CommaSeparatedListOfStringsStruct = coerce( const EnvStruct = object({ ENVIRONMENT: enums(['local', 'test', 'production']), - LOG_LEVEL: enums(Object.values(LogLevel)), + LOG_LEVEL: enums(Object.values(LogLevel) as [LogLevel, ...LogLevel[]]), RPC_URL_MAINNET_LIST: CommaSeparatedListOfUrlsStruct, RPC_URL_DEVNET_LIST: CommaSeparatedListOfUrlsStruct, RPC_URL_TESTNET_LIST: CommaSeparatedListOfUrlsStruct, diff --git a/packages/solana-wallet-snap/src/core/services/transaction-scan/TransactionScan.ts b/packages/solana-wallet-snap/src/core/services/transaction-scan/TransactionScan.ts index 9931999f6..8f82a5319 100644 --- a/packages/solana-wallet-snap/src/core/services/transaction-scan/TransactionScan.ts +++ b/packages/solana-wallet-snap/src/core/services/transaction-scan/TransactionScan.ts @@ -215,7 +215,7 @@ export class TransactionScanService { symbol: 'symbol' in asset.asset ? asset.asset.symbol : asset.asset_type, name: 'name' in asset.asset ? asset.asset.name : asset.asset_type, - logo: 'logo' in asset.asset ? asset.asset.logo : null, + logo: ('logo' in asset.asset ? asset.asset.logo : null) ?? null, value: asset.in?.value ?? asset.out?.value ?? null, price: asset.in?.usd_price ?? asset.out?.usd_price ?? null, }), @@ -230,7 +230,9 @@ export class TransactionScanService { type: 'type' in result.error_details ? result.error_details.type : null, code: - 'code' in result.error_details ? result.error_details.code : null, + ('code' in result.error_details + ? result.error_details.code + : null) ?? null, } : null, }; diff --git a/packages/solana-wallet-snap/src/core/services/wallet/structs.ts b/packages/solana-wallet-snap/src/core/services/wallet/structs.ts index 2687de0ce..71f6578e0 100644 --- a/packages/solana-wallet-snap/src/core/services/wallet/structs.ts +++ b/packages/solana-wallet-snap/src/core/services/wallet/structs.ts @@ -34,7 +34,9 @@ import { Base58Struct, Base64Struct } from '../../validation/structs'; * @see https://github.com/anza-xyz/wallet-standard/tree/master/packages/core/features/src */ -export const ScopeStringStruct = enums(Object.values(Network)); +export const ScopeStringStruct = enums( + Object.values(Network) as [Network, ...Network[]], +); // Sanitizing structs that transform values during validation const SanitizedSolanaAddressStruct = coerce( diff --git a/packages/solana-wallet-snap/src/core/validation/structs.ts b/packages/solana-wallet-snap/src/core/validation/structs.ts index fe764e7a1..135fe4172 100644 --- a/packages/solana-wallet-snap/src/core/validation/structs.ts +++ b/packages/solana-wallet-snap/src/core/validation/structs.ts @@ -60,9 +60,13 @@ export const GetAccounBalancesResponseStruct = record( export const ListAccountAssetsResponseStruct = array(CaipAssetTypeStruct); -export const SubmitRequestMethodStruct = enums(Object.values(SolMethod)); +export const SubmitRequestMethodStruct = enums( + Object.values(SolMethod) as [SolMethod, ...SolMethod[]], +); -export const NetworkStruct = enums(Object.values(Network)); +export const NetworkStruct = enums( + Object.values(Network) as [Network, ...Network[]], +); export const Curenc = enums([ 'btc', diff --git a/packages/solana-wallet-snap/src/index.ts b/packages/solana-wallet-snap/src/index.ts index 1b0772b6a..6060f0b74 100644 --- a/packages/solana-wallet-snap/src/index.ts +++ b/packages/solana-wallet-snap/src/index.ts @@ -59,12 +59,14 @@ BigNumber.config({ EXPONENTIAL_AT: 16 }); * @param args - The request handler args as object. * @param args.origin - The origin of the request, e.g., the website that * invoked the snap. + * @param args.originMetadata - Metadata reported by the requesting origin. * @param args.request - A validated JSON-RPC request object. * @returns A promise that resolves to the result of the RPC request. * @throws If the request method is not valid for this snap. */ export const onRpcRequest: OnRpcRequestHandler = async ({ origin, + originMetadata, request, }) => { logger.log('[🔄 onRpcRequest]', request.method, request); @@ -84,7 +86,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ } const result = await withCatchAndThrowSnapError(async () => - handler({ origin, request }), + handler({ origin, originMetadata, request }), ); return result ?? null; @@ -179,13 +181,12 @@ export const onCronjob: OnCronjobHandler = async ({ request }) => { _logger.log(request.method, request); const { method } = request; - assert( - method, - enums([ - ...Object.values(CronjobMethod), - ...Object.values(ScheduleBackgroundEventMethod), - ]), - ); + const validMethods = [ + ...Object.values(CronjobMethod), + ...Object.values(ScheduleBackgroundEventMethod), + ]; + + assert(method, enums(validMethods as [string, ...string[]])); const result = await withCatchAndThrowSnapError(async () => { _logger.log('Running cronjob', { method }); @@ -197,10 +198,7 @@ export const onCronjob: OnCronjobHandler = async ({ request }) => { if (!handler) { throw new MethodNotFoundError( - `Cronjob / ScheduleBackgroundEvent method ${String(method)} not found. Available methods: ${[ - ...Object.values(CronjobMethod), - ...Object.values(ScheduleBackgroundEventMethod), - ].join(',')}`, + `Cronjob / ScheduleBackgroundEvent method ${method} not found. Available methods: ${validMethods.toString()}`, ) as unknown as Error; } return handler({ request }); diff --git a/packages/solana-wallet-snap/tsconfig.json b/packages/solana-wallet-snap/tsconfig.json index 11f05f5bf..e060c47ac 100644 --- a/packages/solana-wallet-snap/tsconfig.json +++ b/packages/solana-wallet-snap/tsconfig.json @@ -5,7 +5,7 @@ "jsx": "react-jsx", "jsxImportSource": "@metamask/snaps-sdk", "resolveJsonModule": true, - "exactOptionalPropertyTypes": true, + "exactOptionalPropertyTypes": false, "forceConsistentCasingInFileNames": true, "noErrorTruncation": true, "noUncheckedIndexedAccess": true, @@ -16,6 +16,11 @@ "moduleResolution": "bundler", "types": ["jest"] }, - "references": [{ "path": "../snap-networks-utils" }], - "include": ["**/*.ts", "**/*.tsx", "locales/*.json"] + "include": [ + "**/*.ts", + "**/*.tsx", + "locales/*.json", + "snap.manifest.json", + "src/**/*.json" + ] } diff --git a/packages/stellar-wallet-snap/snap.config.ts b/packages/stellar-wallet-snap/snap.config.ts index 046915b47..f33acfc21 100644 --- a/packages/stellar-wallet-snap/snap.config.ts +++ b/packages/stellar-wallet-snap/snap.config.ts @@ -6,6 +6,9 @@ dotenv(); const config: SnapConfig = { input: resolve(__dirname, 'src/index.ts'), + typescript: { + enabled: true, + }, server: { port: 8080, }, diff --git a/packages/stellar-wallet-snap/snap.manifest.json b/packages/stellar-wallet-snap/snap.manifest.json index 7d6c9f105..18ff6434a 100644 --- a/packages/stellar-wallet-snap/snap.manifest.json +++ b/packages/stellar-wallet-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "QMvShnvrFA65DF39Qs4iC0ZYywBT31wqdBMy/uvBm60=", + "shasum": "eLUwFyKvzK6j3RV0am3G59i2B74yVEf2bU+wnMMcWeE=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/stellar-wallet-snap/src/config.ts b/packages/stellar-wallet-snap/src/config.ts index cec727fae..ec73ce07f 100644 --- a/packages/stellar-wallet-snap/src/config.ts +++ b/packages/stellar-wallet-snap/src/config.ts @@ -84,7 +84,10 @@ const selectedNetworkStruct = coerce( * If the log level is empty or missing, it defaults to silent. */ export const LogLevelStruct = coerce( - defaulted(enums(Object.values(LogLevel)), LogLevel.SILENT), + defaulted( + enums(Object.values(LogLevel) as [LogLevel, ...LogLevel[]]), + LogLevel.SILENT, + ), string(), (value: string) => (value === '' ? undefined : value.toLowerCase()), ); diff --git a/packages/stellar-wallet-snap/src/services/account/AccountService.ts b/packages/stellar-wallet-snap/src/services/account/AccountService.ts index 7eb0a041a..7552ee521 100644 --- a/packages/stellar-wallet-snap/src/services/account/AccountService.ts +++ b/packages/stellar-wallet-snap/src/services/account/AccountService.ts @@ -165,7 +165,7 @@ export class AccountService { const returnAccounts = await batchesAll( rangeIndices, BATCH_DERIVATION_SIZE, - async (index) => { + async (index: number) => { let account = existingAccountsByIndex.get(index); if (account === undefined) { const wallet = await walletResolver(index); @@ -181,7 +181,8 @@ export class AccountService { ); const createdAccounts = returnAccounts.filter( - (account) => !existingAccountsByIndex.has(account.index), + (account: StellarKeyringAccount) => + !existingAccountsByIndex.has(account.index), ); // 4. Save all new accounts diff --git a/packages/stellar-wallet-snap/src/services/asset-metadata/AssetMetadataService.ts b/packages/stellar-wallet-snap/src/services/asset-metadata/AssetMetadataService.ts index b1bf742b9..36ead89c1 100644 --- a/packages/stellar-wallet-snap/src/services/asset-metadata/AssetMetadataService.ts +++ b/packages/stellar-wallet-snap/src/services/asset-metadata/AssetMetadataService.ts @@ -335,7 +335,8 @@ export class AssetMetadataService { assetIds, this.#sepAssetChunkSize, this.#sepAssetBatchSize, - async (chunk) => this.#networkService.getSep41AssetsData(chunk, scope), + async (chunk: KnownCaip19Sep41AssetId[]) => + this.#networkService.getSep41AssetsData(chunk, scope), ); const { assets, missingAssetIds } = @@ -365,7 +366,7 @@ export class AssetMetadataService { const settled = await batchesAllSettled( assetIds, this.#classicAssetBatchSize, - async (assetId) => + async (assetId: KnownCaip19ClassicAssetId) => this.#networkService.getClassicAssetData(assetId, scope), ); diff --git a/packages/stellar-wallet-snap/src/services/network/NetworkService.ts b/packages/stellar-wallet-snap/src/services/network/NetworkService.ts index 9e3393633..a74cd4415 100644 --- a/packages/stellar-wallet-snap/src/services/network/NetworkService.ts +++ b/packages/stellar-wallet-snap/src/services/network/NetworkService.ts @@ -302,7 +302,7 @@ export class NetworkService { const settled = await batchesAllSettled( accountAddresses, batchSize, - async (accountId) => this.loadOnChainAccount(accountId, scope), // Assume the onChainAccount scope is the same as the transaction scope + async (accountId: string) => this.loadOnChainAccount(accountId, scope), // Assume the onChainAccount scope is the same as the transaction scope ); const onChainAccounts: (OnChainAccount | null)[] = []; diff --git a/packages/stellar-wallet-snap/src/services/transaction/TransactionSynchronizeService.ts b/packages/stellar-wallet-snap/src/services/transaction/TransactionSynchronizeService.ts index 3a185e4fa..c8baf1d11 100644 --- a/packages/stellar-wallet-snap/src/services/transaction/TransactionSynchronizeService.ts +++ b/packages/stellar-wallet-snap/src/services/transaction/TransactionSynchronizeService.ts @@ -256,7 +256,7 @@ export class TransactionSynchronizeService { const fetchResults = await batchesAllSettled( context.keyringAccounts, 10, - async (keyringAccount) => { + async (keyringAccount: StellarKeyringAccount) => { const lastScanToken = context.lastScanTokenByAccountId[keyringAccount.id] ?? null; @@ -339,7 +339,7 @@ export class TransactionSynchronizeService { const fetchResults = await batchesAllSettled( transactionIdsToFetch, 10, - async (transactionId) => + async (transactionId: string) => this.#fetchOnChainTransaction(transactionId, context.scope), ); diff --git a/packages/stellar-wallet-snap/tsconfig.json b/packages/stellar-wallet-snap/tsconfig.json index aa6bd53f5..69148854d 100644 --- a/packages/stellar-wallet-snap/tsconfig.json +++ b/packages/stellar-wallet-snap/tsconfig.json @@ -16,6 +16,11 @@ "moduleResolution": "bundler", "types": ["jest"] }, - "references": [{ "path": "../snap-networks-utils" }], - "include": ["**/*.ts", "**/*.tsx", "locales/*.json"] + "include": [ + "**/*.ts", + "**/*.tsx", + "locales/*.json", + "snap.manifest.json", + "tokenlists/*.json" + ] } diff --git a/packages/tron-wallet-snap/snap.config.ts b/packages/tron-wallet-snap/snap.config.ts index abb8f37d1..1b13685e9 100644 --- a/packages/tron-wallet-snap/snap.config.ts +++ b/packages/tron-wallet-snap/snap.config.ts @@ -7,6 +7,9 @@ dotenv(); const config: SnapConfig = { input: resolve(__dirname, 'src/index.ts'), + typescript: { + enabled: true, + }, server: { port: 8080, }, diff --git a/packages/tron-wallet-snap/snap.manifest.json b/packages/tron-wallet-snap/snap.manifest.json index 1a7f6ddd0..a9fc2701f 100644 --- a/packages/tron-wallet-snap/snap.manifest.json +++ b/packages/tron-wallet-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "JeCbAFBIfqDsc+ysNskueF8qdvLOtmMdOmtZASZetr4=", + "shasum": "ywXNBsBG0fniejuwfBWRFL2c2zEFyAJWiqiIhzNKG3Q=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/tron-wallet-snap/src/caching/useCache.test.ts b/packages/tron-wallet-snap/src/caching/useCache.test.ts index 5ceaeb9d8..bfb302204 100644 --- a/packages/tron-wallet-snap/src/caching/useCache.test.ts +++ b/packages/tron-wallet-snap/src/caching/useCache.test.ts @@ -11,7 +11,7 @@ const cacheOptions: CacheOptions = { type WithUseCacheCallback = (payload: { actualExecutionSpy: jest.Mock, Serializable[]>; - cache: ICache; + cache: MockCache; testFunction: () => Promise; cachedTestFunction: () => Promise; cachedTestFunctionWithArgs: (arg1: string, arg2: number) => Promise; @@ -21,6 +21,11 @@ type WithUseCacheCallback = (payload: { }) => Promise; }) => void | Promise; +type MockCache = ICache & { + get: jest.Mock, [string]>; + set: jest.Mock, [string, Serializable, (number | undefined)?]>; +}; + /** * Wraps tests for `useCache` by creating fresh cached functions backed by a * mock cache. @@ -38,7 +43,7 @@ async function withUseCache(testFn: WithUseCacheCallback): Promise { const cache = { get: jest.fn().mockResolvedValue(undefined), set: jest.fn().mockResolvedValue(undefined), - } as unknown as ICache; + } as unknown as MockCache; // Define original functions const testFunction = async (): Promise => actualExecutionSpy(); diff --git a/packages/tron-wallet-snap/src/caching/useCacheUntil.test.ts b/packages/tron-wallet-snap/src/caching/useCacheUntil.test.ts index fe2351ef2..4c00c3127 100644 --- a/packages/tron-wallet-snap/src/caching/useCacheUntil.test.ts +++ b/packages/tron-wallet-snap/src/caching/useCacheUntil.test.ts @@ -13,15 +13,20 @@ const mockNow = 1700000000000; // Fixed timestamp for testing type WithUseCacheUntilCallback = (payload: { actualExecutionSpy: jest.Mock< - Promise>, + Promise>, Serializable[] >; - cache: ICache; + cache: MockCache; testFunction: () => Promise>; cachedTestFunction: () => Promise; - cachedTestFunctionWithArgs: (arg1: string, arg2: number) => Promise; + cachedTestFunctionWithArgs: (arg1: string) => Promise; }) => void | Promise; +type MockCache = ICache & { + get: jest.Mock, [string]>; + set: jest.Mock, [string, Serializable, (number | undefined)?]>; +}; + /** * Wraps tests for `useCacheUntil` by creating fresh cached functions backed by a * mock cache. @@ -37,7 +42,7 @@ async function withUseCacheUntil( // Reset mocks for each test const actualExecutionSpy = jest - .fn>, Serializable[]>() + .fn>, Serializable[]>() .mockResolvedValue({ result: 'test', expiresAt: mockNow + 60000, // Expires in 60 seconds @@ -47,14 +52,15 @@ async function withUseCacheUntil( const cache = { get: jest.fn().mockResolvedValue(undefined), set: jest.fn().mockResolvedValue(undefined), - } as unknown as ICache; + } as unknown as MockCache; // Define original functions const testFunction = async (): Promise> => - actualExecutionSpy(); + (await actualExecutionSpy()) as ResultWithExpiry; const testFunctionWithArgs = async ( arg1: string, - ): Promise> => actualExecutionSpy(arg1); + ): Promise> => + (await actualExecutionSpy(arg1)) as ResultWithExpiry; // Create cached versions const cachedTestFunction = useCacheUntil(testFunction, cache, { @@ -291,7 +297,7 @@ describe('useCacheUntil', () => { it('handles anonymous functions with a default name', async () => { await withUseCacheUntil(async ({ cache, actualExecutionSpy }) => { const anonymousFunction = async (): Promise> => - actualExecutionSpy(); + (await actualExecutionSpy()) as ResultWithExpiry; Object.defineProperty(anonymousFunction, 'name', { value: null }); const cachedAnonymousFunction = useCacheUntil( diff --git a/packages/tron-wallet-snap/src/clients/token-api/TokenApiClient.ts b/packages/tron-wallet-snap/src/clients/token-api/TokenApiClient.ts index f9e7494a3..9269e9539 100644 --- a/packages/tron-wallet-snap/src/clients/token-api/TokenApiClient.ts +++ b/packages/tron-wallet-snap/src/clients/token-api/TokenApiClient.ts @@ -111,7 +111,7 @@ export class TokenApiClient { // Fetch metadata for each chunk const tokenMetadataResponses = ( await Promise.all( - assetTypeChunks.map(async (chunk) => + assetTypeChunks.map(async (chunk: TokenCaipAssetType[]) => this.#fetchTokenMetadataBatch(chunk), ), ) @@ -129,7 +129,8 @@ export class TokenApiClient { */ assetTypes.forEach((assetType) => { const tokenMetadata = tokenMetadataResponses.find( - (item) => item.assetId === assetType, + (item: Infer[number]) => + item.assetId === assetType, ); if (!tokenMetadata) { diff --git a/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts b/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts index 9b65e0389..6c8a07669 100644 --- a/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts +++ b/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts @@ -11,7 +11,7 @@ import { } from '@metamask/keyring-api'; import { getSelectedAccounts } from '@metamask/keyring-snap-sdk'; import type { Logger } from '@metamask/snap-networks-utils'; -import { InFlightCoalescer } from '@metamask/snap-networks-utils/dedupe'; +import { InFlightCoalescer } from '@metamask/snap-networks-utils'; import { assert } from '@metamask/superstruct'; import { hexToBytes } from '@metamask/utils'; import { computeAddress } from 'ethers'; diff --git a/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.test.ts b/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.test.ts index 4413174ea..f24274971 100644 --- a/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.test.ts +++ b/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.test.ts @@ -290,7 +290,7 @@ describe('CoreAssetsAdapter', () => { chainId: Network.Nile, }); mockAssetsProvider.getAccountAssetsByScope.mockImplementation( - async (scope) => { + async (scope: `${string}:${string}`) => { if (scope === Network.Mainnet) { return { [MAINNET_ASSET_ID]: mainnetAsset }; } @@ -328,7 +328,7 @@ describe('CoreAssetsAdapter', () => { it('rejects when any scope request fails', async () => { await withCoreAssetsAdapter(async ({ adapter, mockAssetsProvider }) => { mockAssetsProvider.getAccountAssetsByScope.mockImplementation( - async (scope) => { + async (scope: `${string}:${string}`) => { if (scope === Network.Nile) { throw new Error('nile failed'); } diff --git a/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.ts b/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.ts index dcead6166..5a2382909 100644 --- a/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.ts +++ b/packages/tron-wallet-snap/src/services/assets/adapters/CoreAssetsAdapter.ts @@ -1,4 +1,4 @@ -import type { Caip19AssetId } from '@metamask/assets-controller'; +import type { Asset, Caip19AssetId } from '@metamask/assets-controller'; import { KeyringEvent } from '@metamask/keyring-api'; import type { AccountAssetListUpdatedEvent, @@ -112,7 +112,7 @@ export class CoreAssetsAdapter { accountId, ); - return Object.values(controllerAssets).map((asset) => + return Object.values(controllerAssets).map((asset: Asset) => mapControllerAsset(accountId, asset), ); } @@ -124,7 +124,7 @@ export class CoreAssetsAdapter { this.#getAccountAssetsByScope(Network.Shasta, accountId), ]); - const allUnmappedAssets = [ + const allUnmappedAssets: Asset[] = [ ...Object.values(mainnetAssets), ...Object.values(nileAssets), ...Object.values(shastaAssets), diff --git a/packages/tron-wallet-snap/src/services/config/ConfigProvider.ts b/packages/tron-wallet-snap/src/services/config/ConfigProvider.ts index 0ca3a4b21..cc9ea5955 100644 --- a/packages/tron-wallet-snap/src/services/config/ConfigProvider.ts +++ b/packages/tron-wallet-snap/src/services/config/ConfigProvider.ts @@ -13,7 +13,7 @@ import { Duration } from '@metamask/utils'; import { Network, Networks } from '../../constants'; -const ENVIRONMENT_TO_ACTIVE_NETWORKS = { +const ENVIRONMENT_TO_ACTIVE_NETWORKS: Record = { production: [Network.Mainnet], local: [Network.Mainnet], test: [Network.Mainnet], @@ -27,7 +27,7 @@ const CommaSeparatedListOfUrlsStruct = coerce( const EnvStruct = object({ ENVIRONMENT: enums(['local', 'test', 'production']), - LOG_LEVEL: enums(Object.values(LogLevel)), + LOG_LEVEL: enums(Object.values(LogLevel) as [LogLevel, ...LogLevel[]]), RPC_URL_LIST_MAINNET: CommaSeparatedListOfUrlsStruct, RPC_URL_LIST_NILE_TESTNET: CommaSeparatedListOfUrlsStruct, RPC_URL_LIST_SHASTA_TESTNET: CommaSeparatedListOfUrlsStruct, diff --git a/packages/tron-wallet-snap/tsconfig.json b/packages/tron-wallet-snap/tsconfig.json index aa6bd53f5..1436fad0e 100644 --- a/packages/tron-wallet-snap/tsconfig.json +++ b/packages/tron-wallet-snap/tsconfig.json @@ -16,6 +16,12 @@ "moduleResolution": "bundler", "types": ["jest"] }, - "references": [{ "path": "../snap-networks-utils" }], - "include": ["**/*.ts", "**/*.tsx", "locales/*.json"] + "include": [ + "**/*.ts", + "**/*.tsx", + "locales/*.json", + "messages.json", + "snap.manifest.json", + "src/**/*.json" + ] } diff --git a/scripts/create-package/cli.test.ts b/scripts/create-package/cli.test.ts index 330f9838d..c95ed759a 100644 --- a/scripts/create-package/cli.test.ts +++ b/scripts/create-package/cli.test.ts @@ -44,13 +44,15 @@ describe('create-package/cli', () => { beforeEach(() => { // yargs calls process.exit() with 1 on failure and sometimes 0 on success. // We have to intercept it. - jest.spyOn(process, 'exit').mockImplementation((code?: number) => { - if (code === 1) { - throw new Error('exit: 1'); - } else { - return undefined as never; - } - }); + jest + .spyOn(process, 'exit') + .mockImplementation((code?: number | string | null) => { + if (code === 1) { + throw new Error('exit: 1'); + } else { + return undefined as never; + } + }); // We actually check these. jest.spyOn(console, 'error'); diff --git a/tsconfig.base.json b/tsconfig.base.json index ab31b1bc9..d38882705 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -3,7 +3,6 @@ * This configuration is extended by all other TypeScript configurations. */ "compilerOptions": { - "composite": true, "esModuleInterop": true, "isolatedModules": true, "lib": ["ES2020", "DOM"], diff --git a/tsconfig.build.json b/tsconfig.build.json deleted file mode 100644 index e5a321b17..000000000 --- a/tsconfig.build.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - /** - * Solution-style config for library packages that emit types via `ts-bridge`. - * `create-package` adds new library packages to `references`. Snap packages - * do not use this file; they are built with `mm-snap`. - */ - "references": [ - { - "path": "./packages/snap-networks-utils/tsconfig.build.json" - } - ], - "files": [], - "include": [] -} diff --git a/tsconfig.json b/tsconfig.json index 23df98f6d..d375ac26d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,33 +1,20 @@ { /** - * This configuration is used by the `lint` script in `package.json`, and by editors such as - * VSCode for TypeScript-related features. + * Repository-level configuration used by the `lint` script and editors such as VSCode. */ "extends": "./tsconfig.base.json", "compilerOptions": { + "baseUrl": "./", + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "jsxImportSource": "@metamask/snaps-sdk", + "lib": ["ES2020"], "noEmit": true, + "noErrorTruncation": true, + "noUncheckedIndexedAccess": true, "skipLibCheck": true }, - "references": [ - { - "path": "./packages/bitcoin-wallet-snap" - }, - { - "path": "./packages/sample-snap" - }, - { - "path": "./packages/snap-networks-utils" - }, - { - "path": "./packages/solana-wallet-snap" - }, - { - "path": "./packages/stellar-wallet-snap" - }, - { - "path": "./packages/tron-wallet-snap" - } - ], "files": [], - "include": ["./docs", "./tests", "./scripts"] + "include": ["./docs", "./tests", "./scripts"], + "exclude": ["**/node_modules"] } diff --git a/tsconfig.packages.build.json b/tsconfig.packages.build.json deleted file mode 100644 index e971538b7..000000000 --- a/tsconfig.packages.build.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - /** - * This configuration is extended by the `tsconfig.build.json` configuration in each package. - */ - "extends": "./tsconfig.packages.json", - "compilerOptions": { - "declaration": true, - "declarationMap": true, - "emitDeclarationOnly": true, - "inlineSources": true, - "sourceMap": true, - "skipLibCheck": true - }, - "exclude": ["./jest.config.packages.ts", "**/*.test.ts", "**/jest.config.ts"] -} diff --git a/tsconfig.packages.json b/tsconfig.packages.json index a655abc1f..9600309db 100644 --- a/tsconfig.packages.json +++ b/tsconfig.packages.json @@ -1,18 +1,23 @@ { /** - * This configuration is extended by the `tsconfig.json` configuration in each package. + * Shared settings for package source, editor, and type-checking configurations. */ "extends": "./tsconfig.base.json", "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "noErrorTruncation": true, + "noUncheckedIndexedAccess": true, /** - * Here we ensure that TypeScript resolves `@metamask/*` imports to the - * uncompiled source code for packages that live in this repo. + * Resolve local `@metamask/*` imports to source so editors and TypeScript checks use the + * uncompiled monorepo packages. * * NOTE: This must be synchronized with the `moduleNameMapper` option in * `jest.config.packages.js`. */ "paths": { "@metamask/*": ["../*/src"] - } + }, + "skipLibCheck": true } } diff --git a/tsconfig.scripts.json b/tsconfig.scripts.json index b4adc2c51..52fbb82ee 100644 --- a/tsconfig.scripts.json +++ b/tsconfig.scripts.json @@ -3,10 +3,7 @@ * This configuration is intended for the `scripts/` directory, both for linting and for editor * TypeScript-related features. * - * It's currently not actually used for that purpose, but it will be in a future PR. - * - * This is also extended by the `tsconfig.json` file in `scripts/create-package/`, which _is_ - * actively used to support TypeScript-related editor features in that directory. + * This is also extended by the `tsconfig.json` file in `scripts/create-package/`. */ "extends": "./tsconfig.base.json", "compilerOptions": { @@ -18,6 +15,6 @@ "noErrorTruncation": true, "noUncheckedIndexedAccess": true }, - "include": ["./scripts/**/*.ts"], + "include": ["./scripts/**/*.ts", "./scripts/**/*.mts"], "exclude": ["**/node_modules"] } diff --git a/yarn.lock b/yarn.lock index 9d49d909e..a7cfcbafc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7803,13 +7803,12 @@ __metadata: linkType: hard "comment-json@npm:^4.5.1": - version: 4.5.1 - resolution: "comment-json@npm:4.5.1" + version: 4.6.2 + resolution: "comment-json@npm:4.6.2" dependencies: array-timsort: "npm:^1.0.3" - core-util-is: "npm:^1.0.3" esprima: "npm:^4.0.1" - checksum: 10/3bdd2703f26690537f65ef708d62aae3980dba6fc566e82a71d95511b413a6f5f285af9af0415e4739dc6f363db24225e46f5267c576f249100cdb28c3adb00d + checksum: 10/2f6e79b7ae81a919a0dd5fc2fac84e9ebdaa501a5f3ffe5b9f2fd5dbe94d686d8ee9a6bddf5bae364bce104dbb1c599a9d4184aeb211aaf4a283b8900438d242 languageName: node linkType: hard @@ -7928,7 +7927,7 @@ __metadata: languageName: node linkType: hard -"core-util-is@npm:^1.0.3, core-util-is@npm:~1.0.0": +"core-util-is@npm:~1.0.0": version: 1.0.3 resolution: "core-util-is@npm:1.0.3" checksum: 10/9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99