From 9e7903c9d2d96d69be40f15689f9f733cf2a0b62 Mon Sep 17 00:00:00 2001 From: Ulisses Ferreira Date: Fri, 31 Jul 2026 09:20:05 +0100 Subject: [PATCH 1/3] feat: scaffold @metamask/snap-networks-utils package Add an empty shared workspace via create-package so MONO-2 extraction tickets can land as move+import changes. Align template deps with the monorepo and assign Networks CODEOWNERS. WPN-1632 --- .github/CODEOWNERS | 1 + README.md | 1 + packages/snap-networks-utils/CHANGELOG.md | 10 + packages/snap-networks-utils/LICENSE | 6 + packages/snap-networks-utils/LICENSE.APACHE2 | 201 ++++++++++++++++++ packages/snap-networks-utils/LICENSE.MIT | 21 ++ packages/snap-networks-utils/README.md | 15 ++ packages/snap-networks-utils/jest.config.js | 26 +++ packages/snap-networks-utils/package.json | 68 ++++++ .../snap-networks-utils/src/index.test.ts | 9 + packages/snap-networks-utils/src/index.ts | 9 + .../snap-networks-utils/tsconfig.build.json | 10 + packages/snap-networks-utils/tsconfig.json | 8 + packages/snap-networks-utils/typedoc.json | 7 + tsconfig.build.json | 6 +- tsconfig.json | 6 +- yarn.lock | 131 +++++++++++- 17 files changed, 532 insertions(+), 3 deletions(-) create mode 100644 packages/snap-networks-utils/CHANGELOG.md create mode 100644 packages/snap-networks-utils/LICENSE create mode 100644 packages/snap-networks-utils/LICENSE.APACHE2 create mode 100644 packages/snap-networks-utils/LICENSE.MIT create mode 100644 packages/snap-networks-utils/README.md create mode 100644 packages/snap-networks-utils/jest.config.js create mode 100644 packages/snap-networks-utils/package.json create mode 100644 packages/snap-networks-utils/src/index.test.ts create mode 100644 packages/snap-networks-utils/src/index.ts create mode 100644 packages/snap-networks-utils/tsconfig.build.json create mode 100644 packages/snap-networks-utils/tsconfig.json create mode 100644 packages/snap-networks-utils/typedoc.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 67ddf232..25392083 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,4 +7,5 @@ * @MetaMask/core-platform @MetaMask/networks packages/bitcoin-wallet-snap @MetaMask/networks +packages/snap-networks-utils @MetaMask/networks packages/tron-wallet-snap @MetaMask/networks diff --git a/README.md b/README.md index 21df5b4e..e6c0b712 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Each snap in this repository has its own README with installation and usage inst - [`@metamask/bitcoin-wallet-snap`](packages/bitcoin-wallet-snap) +- [`@metamask/snap-networks-utils`](packages/snap-networks-utils) - [`@metamask/tron-wallet-snap`](packages/tron-wallet-snap) diff --git a/packages/snap-networks-utils/CHANGELOG.md b/packages/snap-networks-utils/CHANGELOG.md new file mode 100644 index 00000000..92e90f87 --- /dev/null +++ b/packages/snap-networks-utils/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +[Unreleased]: https://github.com/MetaMask/internal-snaps/ diff --git a/packages/snap-networks-utils/LICENSE b/packages/snap-networks-utils/LICENSE new file mode 100644 index 00000000..2bf58141 --- /dev/null +++ b/packages/snap-networks-utils/LICENSE @@ -0,0 +1,6 @@ +This project is licensed under either of + + * MIT license ([LICENSE.MIT](LICENSE.MIT)) + * Apache License, Version 2.0 ([LICENSE.APACHE2](LICENSE.APACHE2)) + +at your option. \ No newline at end of file diff --git a/packages/snap-networks-utils/LICENSE.APACHE2 b/packages/snap-networks-utils/LICENSE.APACHE2 new file mode 100644 index 00000000..18002eac --- /dev/null +++ b/packages/snap-networks-utils/LICENSE.APACHE2 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 MetaMask + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/snap-networks-utils/LICENSE.MIT b/packages/snap-networks-utils/LICENSE.MIT new file mode 100644 index 00000000..e0278643 --- /dev/null +++ b/packages/snap-networks-utils/LICENSE.MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/snap-networks-utils/README.md b/packages/snap-networks-utils/README.md new file mode 100644 index 00000000..2b929162 --- /dev/null +++ b/packages/snap-networks-utils/README.md @@ -0,0 +1,15 @@ +# `@metamask/snap-networks-utils` + +Shared utilities for MetaMask network snaps + +## Installation + +`yarn add @metamask/snap-networks-utils` + +or + +`npm install @metamask/snap-networks-utils` + +## Contributing + +This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/internal-snaps#readme). diff --git a/packages/snap-networks-utils/jest.config.js b/packages/snap-networks-utils/jest.config.js new file mode 100644 index 00000000..ca084133 --- /dev/null +++ b/packages/snap-networks-utils/jest.config.js @@ -0,0 +1,26 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +const merge = require('deepmerge'); +const path = require('path'); + +const baseConfig = require('../../jest.config.packages'); + +const displayName = path.basename(__dirname); + +module.exports = merge(baseConfig, { + // The display name when running multiple projects + displayName, + + // An object that configures minimum threshold enforcement for coverage results + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}); diff --git a/packages/snap-networks-utils/package.json b/packages/snap-networks-utils/package.json new file mode 100644 index 00000000..51de528f --- /dev/null +++ b/packages/snap-networks-utils/package.json @@ -0,0 +1,68 @@ +{ + "name": "@metamask/snap-networks-utils", + "version": "0.0.0", + "description": "Shared utilities for MetaMask network snaps", + "keywords": [ + "Ethereum", + "MetaMask" + ], + "homepage": "https://github.com/MetaMask/internal-snaps/tree/main/packages/snap-networks-utils#readme", + "bugs": { + "url": "https://github.com/MetaMask/internal-snaps/issues" + }, + "license": "(MIT OR Apache-2.0)", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/internal-snaps.git" + }, + "files": [ + "dist/" + ], + "sideEffects": false, + "main": "./dist/index.cjs", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + }, + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "scripts": { + "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", + "build:all": "ts-bridge --project tsconfig.build.json --verbose --clean", + "build:docs": "typedoc", + "changelog:update": "../../scripts/update-changelog.sh @metamask/snap-networks-utils", + "changelog:validate": "../../scripts/validate-changelog.sh @metamask/snap-networks-utils", + "since-latest-release": "../../scripts/since-latest-release.sh", + "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", + "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache", + "test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose", + "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" + }, + "devDependencies": { + "@metamask/auto-changelog": "^6.1.1", + "@ts-bridge/cli": "^0.6.4", + "@types/jest": "^30.0.0", + "deepmerge": "^4.2.2", + "jest": "30.0.3", + "ts-jest": "^29.4.1", + "tsx": "^4.20.5", + "typedoc": "^0.25.13", + "typedoc-plugin-missing-exports": "^2.0.0", + "typescript": "~5.8.3" + }, + "engines": { + "node": ">=20" + } +} diff --git a/packages/snap-networks-utils/src/index.test.ts b/packages/snap-networks-utils/src/index.test.ts new file mode 100644 index 00000000..bc062d36 --- /dev/null +++ b/packages/snap-networks-utils/src/index.test.ts @@ -0,0 +1,9 @@ +import greeter from '.'; + +describe('Test', () => { + it('greets', () => { + const name = 'Huey'; + const result = greeter(name); + expect(result).toBe('Hello, Huey!'); + }); +}); diff --git a/packages/snap-networks-utils/src/index.ts b/packages/snap-networks-utils/src/index.ts new file mode 100644 index 00000000..6972c117 --- /dev/null +++ b/packages/snap-networks-utils/src/index.ts @@ -0,0 +1,9 @@ +/** + * Example function that returns a greeting for the given name. + * + * @param name - The name to greet. + * @returns The greeting. + */ +export default function greeter(name: string): string { + return `Hello, ${name}!`; +} diff --git a/packages/snap-networks-utils/tsconfig.build.json b/packages/snap-networks-utils/tsconfig.build.json new file mode 100644 index 00000000..02a0eea0 --- /dev/null +++ b/packages/snap-networks-utils/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.packages.build.json", + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist", + "rootDir": "./src" + }, + "references": [], + "include": ["../../types", "./src"] +} diff --git a/packages/snap-networks-utils/tsconfig.json b/packages/snap-networks-utils/tsconfig.json new file mode 100644 index 00000000..025ba2ef --- /dev/null +++ b/packages/snap-networks-utils/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "baseUrl": "./" + }, + "references": [], + "include": ["../../types", "./src"] +} diff --git a/packages/snap-networks-utils/typedoc.json b/packages/snap-networks-utils/typedoc.json new file mode 100644 index 00000000..c9da015d --- /dev/null +++ b/packages/snap-networks-utils/typedoc.json @@ -0,0 +1,7 @@ +{ + "entryPoints": ["./src/index.ts"], + "excludePrivate": true, + "hideGenerator": true, + "out": "docs", + "tsconfig": "./tsconfig.build.json" +} diff --git a/tsconfig.build.json b/tsconfig.build.json index 368c4f39..d9833b84 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -6,7 +6,11 @@ * extended here because the `tsconfig.build.json` file referenced for each package already * (indirectly) extends it. */ - "references": [], + "references": [ + { + "path": "./packages/snap-networks-utils/tsconfig.build.json" + } + ], "files": [], "include": [] } diff --git a/tsconfig.json b/tsconfig.json index 00862e4a..6ac413a8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,11 @@ "compilerOptions": { "noEmit": true }, - "references": [], + "references": [ + { + "path": "./packages/snap-networks-utils" + } + ], "files": [], "include": ["./docs", "./tests", "./scripts"] } diff --git a/yarn.lock b/yarn.lock index 5fd773e5..4249a57f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2275,6 +2275,23 @@ __metadata: languageName: node linkType: hard +"@metamask/snap-networks-utils@workspace:packages/snap-networks-utils": + version: 0.0.0-use.local + resolution: "@metamask/snap-networks-utils@workspace:packages/snap-networks-utils" + dependencies: + "@metamask/auto-changelog": "npm:^6.1.1" + "@ts-bridge/cli": "npm:^0.6.4" + "@types/jest": "npm:^30.0.0" + deepmerge: "npm:^4.2.2" + jest: "npm:30.0.3" + ts-jest: "npm:^29.4.1" + tsx: "npm:^4.20.5" + typedoc: "npm:^0.25.13" + typedoc-plugin-missing-exports: "npm:^2.0.0" + typescript: "npm:~5.8.3" + languageName: unknown + linkType: soft + "@metamask/snaps-cli@npm:^8.4.1": version: 8.4.1 resolution: "@metamask/snaps-cli@npm:8.4.1" @@ -3404,6 +3421,30 @@ __metadata: languageName: node linkType: hard +"@ts-bridge/cli@npm:^0.6.4": + version: 0.6.4 + resolution: "@ts-bridge/cli@npm:0.6.4" + dependencies: + "@ts-bridge/resolver": "npm:^0.2.0" + chalk: "npm:^5.3.0" + cjs-module-lexer: "npm:^1.3.1" + yargs: "npm:^17.7.2" + peerDependencies: + typescript: ">=4.8.0" + bin: + ts-bridge: ./dist/index.js + tsbridge: ./dist/index.js + checksum: 10/257ee0cacec71c1b3cc018825088e06b4bd554ba5fe95bdb98c4c82edd6cd4bcff1054d351e6c7cdfdd3bd2145a055b5d14fa453a6ece761645e42b48b88e9a0 + languageName: node + linkType: hard + +"@ts-bridge/resolver@npm:^0.2.0": + version: 0.2.0 + resolution: "@ts-bridge/resolver@npm:0.2.0" + checksum: 10/d4cfd1f47e9648a5f9c893b1b076adabde3a57cbe81ef823bcbbcc77a122fb6f06d99f40ff48198f8dc766bfc4b3b351d4e87cfcf2db64f7e6db924eb82a5db1 + languageName: node + linkType: hard + "@tybys/wasm-util@npm:^0.10.3": version: 0.10.3 resolution: "@tybys/wasm-util@npm:0.10.3" @@ -4385,6 +4426,13 @@ __metadata: languageName: node linkType: hard +"ansi-sequence-parser@npm:^1.1.0": + version: 1.1.3 + resolution: "ansi-sequence-parser@npm:1.1.3" + checksum: 10/0f298aad5c9429dc71fc85668b4b502a5c0670c6dc1253b6e9ed5fc7d457a05ede5b10fd0d69a33a1435e41c0a841360bec9131053bdce04a2367c475acb97d6 + languageName: node + linkType: hard + "ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" @@ -5335,7 +5383,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:5.6.2": +"chalk@npm:5.6.2, chalk@npm:^5.3.0": version: 5.6.2 resolution: "chalk@npm:5.6.2" checksum: 10/1b2f48f6fba1370670d5610f9cd54c391d6ede28f4b7062dd38244ea5768777af72e5be6b74fb6c6d54cb84c4a2dff3f3afa9b7cb5948f7f022cfd3d087989e0 @@ -5414,6 +5462,13 @@ __metadata: languageName: node linkType: hard +"cjs-module-lexer@npm:^1.3.1": + version: 1.4.3 + resolution: "cjs-module-lexer@npm:1.4.3" + checksum: 10/d2b92f919a2dedbfd61d016964fce8da0035f827182ed6839c97cac56e8a8077cfa6a59388adfe2bc588a19cef9bbe830d683a76a6e93c51f65852062cfe2591 + languageName: node + linkType: hard + "cjs-module-lexer@npm:^2.1.0": version: 2.2.0 resolution: "cjs-module-lexer@npm:2.2.0" @@ -9224,6 +9279,13 @@ __metadata: languageName: node linkType: hard +"jsonc-parser@npm:^3.2.0": + version: 3.3.1 + resolution: "jsonc-parser@npm:3.3.1" + checksum: 10/9b0dc391f20b47378f843ef1e877e73ec652a5bdc3c5fa1f36af0f119a55091d147a86c1ee86a232296f55c929bba174538c2bf0312610e0817a22de131cc3f4 + languageName: node + linkType: hard + "jsonfile@npm:^6.0.1": version: 6.2.1 resolution: "jsonfile@npm:6.2.1" @@ -9363,6 +9425,13 @@ __metadata: languageName: node linkType: hard +"lunr@npm:^2.3.9": + version: 2.3.9 + resolution: "lunr@npm:2.3.9" + checksum: 10/f2f6db34c046f5a767782fe2454e6dd69c75ba3c5cf5c1cb9cacca2313a99c2ba78ff8fa67dac866fb7c4ffd5f22e06684793f5f15ba14bddb598b94513d54bf + languageName: node + linkType: hard + "luxon@npm:^3.2.1, luxon@npm:^3.5.0": version: 3.7.2 resolution: "luxon@npm:3.7.2" @@ -9433,6 +9502,15 @@ __metadata: languageName: node linkType: hard +"marked@npm:^4.3.0": + version: 4.3.0 + resolution: "marked@npm:4.3.0" + bin: + marked: bin/marked.js + checksum: 10/c830bb4cb3705b754ca342b656e8a582d7428706b2678c898b856f6030c134ce2d1e19136efa3e6a1841f7330efbd24963d6bdeddc57d2938e906250f99895d0 + languageName: node + linkType: hard + "math-intrinsics@npm:^1.1.0": version: 1.1.0 resolution: "math-intrinsics@npm:1.1.0" @@ -11377,6 +11455,18 @@ __metadata: languageName: node linkType: hard +"shiki@npm:^0.14.7": + version: 0.14.7 + resolution: "shiki@npm:0.14.7" + dependencies: + ansi-sequence-parser: "npm:^1.1.0" + jsonc-parser: "npm:^3.2.0" + vscode-oniguruma: "npm:^1.7.0" + vscode-textmate: "npm:^8.0.0" + checksum: 10/be3f2444c65bd0c57802026f171cb42ad571d361ee885be0c292b60785f68c70f19b69310f5ffe7f7a93db4c5ef50211e0a0248794bc6bb48d242bc43fe72a62 + languageName: node + linkType: hard + "side-channel-list@npm:^1.0.0": version: 1.0.1 resolution: "side-channel-list@npm:1.0.1" @@ -12250,6 +12340,31 @@ __metadata: languageName: node linkType: hard +"typedoc-plugin-missing-exports@npm:^2.0.0": + version: 2.3.0 + resolution: "typedoc-plugin-missing-exports@npm:2.3.0" + peerDependencies: + typedoc: 0.24.x || 0.25.x + checksum: 10/83ff8affd82fa39a81931e825ef31b51b7470613c71601fde6ff413a5c7571e30734698092a38a437f12c5d3264010696ce9ca806d43485aa11e8208cb4cb323 + languageName: node + linkType: hard + +"typedoc@npm:^0.25.13": + version: 0.25.13 + resolution: "typedoc@npm:0.25.13" + dependencies: + lunr: "npm:^2.3.9" + marked: "npm:^4.3.0" + minimatch: "npm:^9.0.3" + shiki: "npm:^0.14.7" + peerDependencies: + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x + bin: + typedoc: bin/typedoc + checksum: 10/3c82603894b5830c4b027b4f4f9ca70f770b6752c6512a42e780c40cb67fe4c9a144e34a837bb35aab14a125e00a5893e1e6feac1ec86a2add80f46833b279d4 + languageName: node + linkType: hard + "typeforce@npm:^1.11.3, typeforce@npm:^1.18.0": version: 1.18.0 resolution: "typeforce@npm:1.18.0" @@ -12575,6 +12690,20 @@ __metadata: languageName: node linkType: hard +"vscode-oniguruma@npm:^1.7.0": + version: 1.7.0 + resolution: "vscode-oniguruma@npm:1.7.0" + checksum: 10/7da9d21459f9788544b258a5fd1b9752df6edd8b406a19eea0209c6bf76507d5717277016799301c4da0d536095f9ca8c06afd1ab8f4001189090c804ca4814e + languageName: node + linkType: hard + +"vscode-textmate@npm:^8.0.0": + version: 8.0.0 + resolution: "vscode-textmate@npm:8.0.0" + checksum: 10/9fa7d66d6042cb090d116c2d8820d34c8870cfcbaed6e404da89f66b899970ed0ac47b59a2e30fc40a25af5414822bb3ea27974f714e9b91910d69c894be95f7 + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" From 65cf72805c82e238678d3bb3af6431b1508b1b83 Mon Sep 17 00:00:00 2001 From: Ulisses Ferreira Date: Fri, 31 Jul 2026 09:23:07 +0100 Subject: [PATCH 2/3] feat: add example logger to snap-networks-utils Replace the create-package greeter with a minimal shared logger so snaps can import a real module from the scaffold package. WPN-1632 --- packages/snap-networks-utils/CHANGELOG.md | 4 ++ packages/snap-networks-utils/README.md | 20 +++++- packages/snap-networks-utils/package.json | 10 +++ .../snap-networks-utils/src/index.test.ts | 9 --- packages/snap-networks-utils/src/index.ts | 11 +--- .../snap-networks-utils/src/logger.test.ts | 55 ++++++++++++++++ packages/snap-networks-utils/src/logger.ts | 66 +++++++++++++++++++ 7 files changed, 156 insertions(+), 19 deletions(-) delete mode 100644 packages/snap-networks-utils/src/index.test.ts create mode 100644 packages/snap-networks-utils/src/logger.test.ts create mode 100644 packages/snap-networks-utils/src/logger.ts diff --git a/packages/snap-networks-utils/CHANGELOG.md b/packages/snap-networks-utils/CHANGELOG.md index 92e90f87..7d8f35e7 100644 --- a/packages/snap-networks-utils/CHANGELOG.md +++ b/packages/snap-networks-utils/CHANGELOG.md @@ -7,4 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add package scaffold with an example `logger` module for shared network-snap utilities + [Unreleased]: https://github.com/MetaMask/internal-snaps/ diff --git a/packages/snap-networks-utils/README.md b/packages/snap-networks-utils/README.md index 2b929162..64b11ee6 100644 --- a/packages/snap-networks-utils/README.md +++ b/packages/snap-networks-utils/README.md @@ -1,6 +1,6 @@ # `@metamask/snap-networks-utils` -Shared utilities for MetaMask network snaps +Shared utilities for MetaMask network snaps. ## Installation @@ -10,6 +10,24 @@ or `npm install @metamask/snap-networks-utils` +Within this monorepo, depend on the workspace package: + +```bash +yarn workspace @metamask/tron-wallet-snap add @metamask/snap-networks-utils@workspace:^ +``` + +## Usage + +Import the example logger from the package root or the dedicated subpath: + +```typescript +import { logger, createPrefixedLogger } from '@metamask/snap-networks-utils'; +// or: import { logger } from '@metamask/snap-networks-utils/logger'; + +const snapLogger = createPrefixedLogger(logger, '[tron-wallet-snap]'); +snapLogger.info('account synced'); +``` + ## Contributing This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/internal-snaps#readme). diff --git a/packages/snap-networks-utils/package.json b/packages/snap-networks-utils/package.json index 51de528f..0b632fb7 100644 --- a/packages/snap-networks-utils/package.json +++ b/packages/snap-networks-utils/package.json @@ -32,6 +32,16 @@ "default": "./dist/index.cjs" } }, + "./logger": { + "import": { + "types": "./dist/logger.d.mts", + "default": "./dist/logger.mjs" + }, + "require": { + "types": "./dist/logger.d.cts", + "default": "./dist/logger.cjs" + } + }, "./package.json": "./package.json" }, "publishConfig": { diff --git a/packages/snap-networks-utils/src/index.test.ts b/packages/snap-networks-utils/src/index.test.ts deleted file mode 100644 index bc062d36..00000000 --- a/packages/snap-networks-utils/src/index.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import greeter from '.'; - -describe('Test', () => { - it('greets', () => { - const name = 'Huey'; - const result = greeter(name); - expect(result).toBe('Hello, Huey!'); - }); -}); diff --git a/packages/snap-networks-utils/src/index.ts b/packages/snap-networks-utils/src/index.ts index 6972c117..1306de5d 100644 --- a/packages/snap-networks-utils/src/index.ts +++ b/packages/snap-networks-utils/src/index.ts @@ -1,9 +1,2 @@ -/** - * Example function that returns a greeting for the given name. - * - * @param name - The name to greet. - * @returns The greeting. - */ -export default function greeter(name: string): string { - return `Hello, ${name}!`; -} +export type { Logger } from './logger'; +export { createPrefixedLogger, logger, noOpLogger } from './logger'; diff --git a/packages/snap-networks-utils/src/logger.test.ts b/packages/snap-networks-utils/src/logger.test.ts new file mode 100644 index 00000000..8b24491b --- /dev/null +++ b/packages/snap-networks-utils/src/logger.test.ts @@ -0,0 +1,55 @@ +import { logger, createPrefixedLogger, noOpLogger } from './logger'; +import type { Logger } from './logger'; + +describe('logger', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + it.each([ + ['log', 'log'], + ['info', 'info'], + ['warn', 'warn'], + ['error', 'error'], + ['debug', 'debug'], + ] as const)('forwards %s calls to console.%s', (method, consoleMethod) => { + const spy = jest.spyOn(console, consoleMethod).mockImplementation(); + + logger[method]('hello', 42); + + expect(spy).toHaveBeenCalledWith('hello', 42); + }); + + it('prefixes messages with createPrefixedLogger', () => { + const infoSpy = jest.spyOn(console, 'info').mockImplementation(); + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); + const errorSpy = jest.spyOn(console, 'error').mockImplementation(); + const debugSpy = jest.spyOn(console, 'debug').mockImplementation(); + const logSpy = jest.spyOn(console, 'log').mockImplementation(); + const prefixed = createPrefixedLogger(logger, '[snap-networks-utils]'); + + prefixed.log('a'); + prefixed.info('b'); + prefixed.warn('c'); + prefixed.error('d'); + prefixed.debug('e'); + + expect(logSpy).toHaveBeenCalledWith('[snap-networks-utils]', 'a'); + expect(infoSpy).toHaveBeenCalledWith('[snap-networks-utils]', 'b'); + expect(warnSpy).toHaveBeenCalledWith('[snap-networks-utils]', 'c'); + expect(errorSpy).toHaveBeenCalledWith('[snap-networks-utils]', 'd'); + expect(debugSpy).toHaveBeenCalledWith('[snap-networks-utils]', 'e'); + }); + + it('provides a no-op logger for tests', () => { + const noop: Logger = noOpLogger; + + expect(() => { + noop.log('silent'); + noop.info('silent'); + noop.warn('silent'); + noop.error('silent'); + noop.debug('silent'); + }).not.toThrow(); + }); +}); diff --git a/packages/snap-networks-utils/src/logger.ts b/packages/snap-networks-utils/src/logger.ts new file mode 100644 index 00000000..2eca10cd --- /dev/null +++ b/packages/snap-networks-utils/src/logger.ts @@ -0,0 +1,66 @@ +/** + * Minimal console logger shared by network snaps. + * + * This is a scaffold example for `@metamask/snap-networks-utils`. Later MONO-2 + * tickets will expand shared utilities; snaps can start importing from here. + */ + +export type Logger = { + log: (...args: unknown[]) => void; + info: (...args: unknown[]) => void; + warn: (...args: unknown[]) => void; + error: (...args: unknown[]) => void; + debug: (...args: unknown[]) => void; +}; + +/** + * Default logger that forwards to `console`. + */ +export const logger: Logger = { + log: (...args: unknown[]) => { + console.log(...args); + }, + info: (...args: unknown[]) => { + console.info(...args); + }, + warn: (...args: unknown[]) => { + console.warn(...args); + }, + error: (...args: unknown[]) => { + console.error(...args); + }, + debug: (...args: unknown[]) => { + console.debug(...args); + }, +}; + +/** + * Logger that discards all messages. Useful in unit tests. + */ +export const noOpLogger: Logger = { + log: () => undefined, + info: () => undefined, + warn: () => undefined, + error: () => undefined, + debug: () => undefined, +}; + +/** + * Returns a logger that prefixes every message. + * + * @param baseLogger - Logger to wrap. + * @param prefix - Prefix prepended to each call. + * @returns Prefixed logger. + */ +export function createPrefixedLogger( + baseLogger: Logger, + prefix: string, +): Logger { + return { + log: (...args: unknown[]) => baseLogger.log(prefix, ...args), + info: (...args: unknown[]) => baseLogger.info(prefix, ...args), + warn: (...args: unknown[]) => baseLogger.warn(prefix, ...args), + error: (...args: unknown[]) => baseLogger.error(prefix, ...args), + debug: (...args: unknown[]) => baseLogger.debug(prefix, ...args), + }; +} From 0d2501b5d562fb642d5be62f5764e0d4436911cc Mon Sep 17 00:00:00 2001 From: Ulisses Ferreira Date: Fri, 31 Jul 2026 09:26:36 +0100 Subject: [PATCH 3/3] chore: link changelog entry to PR #79 WPN-1632 --- packages/snap-networks-utils/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/snap-networks-utils/CHANGELOG.md b/packages/snap-networks-utils/CHANGELOG.md index 7d8f35e7..839c4308 100644 --- a/packages/snap-networks-utils/CHANGELOG.md +++ b/packages/snap-networks-utils/CHANGELOG.md @@ -9,6 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add package scaffold with an example `logger` module for shared network-snap utilities +- Add package scaffold with an example `logger` module for shared network-snap utilities ([#79](https://github.com/MetaMask/internal-snaps/pull/79)) [Unreleased]: https://github.com/MetaMask/internal-snaps/