{"id":18285923,"url":"https://github.com/exodusmovement/exodus-oss","last_synced_at":"2025-04-05T08:30:37.473Z","repository":{"id":209064203,"uuid":"712721890","full_name":"ExodusMovement/exodus-oss","owner":"ExodusMovement","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-28T12:04:04.000Z","size":1604,"stargazers_count":8,"open_issues_count":15,"forks_count":5,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-28T15:29:21.878Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ExodusMovement.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-01T03:46:21.000Z","updated_at":"2024-10-28T12:02:40.000Z","dependencies_parsed_at":"2024-02-19T14:32:54.654Z","dependency_job_id":"527af6de-ce2b-4933-8326-ed392a30b185","html_url":"https://github.com/ExodusMovement/exodus-oss","commit_stats":null,"previous_names":["exodusmovement/exodus-oss"],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExodusMovement%2Fexodus-oss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExodusMovement%2Fexodus-oss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExodusMovement%2Fexodus-oss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExodusMovement%2Fexodus-oss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ExodusMovement","download_url":"https://codeload.github.com/ExodusMovement/exodus-oss/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223174747,"owners_count":17100272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T13:18:11.611Z","updated_at":"2024-11-05T13:18:12.198Z","avatar_url":"https://github.com/ExodusMovement.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Checks](https://github.com/ExodusMovement/exodus-oss/actions/workflows/checks.yaml/badge.svg?branch=master)](https://github.com/ExodusMovement/exodus-oss/actions/workflows/checks.yaml) [![Version](https://github.com/ExodusMovement/exodus-oss/actions/workflows/version.yaml/badge.svg)](https://github.com/ExodusMovement/exodus-oss/actions/workflows/version.yaml) [![Publish](https://github.com/ExodusMovement/exodus-oss/actions/workflows/publish.yaml/badge.svg)](https://github.com/ExodusMovement/exodus-oss/actions/workflows/publish.yaml) [![CodeQL](https://github.com/ExodusMovement/exodus-oss/actions/workflows/codeql.yml/badge.svg)](https://github.com/ExodusMovement/exodus-oss/actions/workflows/codeql.yml)\n\n# exodus-oss\n\n\u003e [!WARNING]\n\u003e This repo still links out to private documentation. We're working on making those public, but it will take time.\n\nThis is the mono repo that is home to the open source modules of the Exodus eco-system.\n\nBefore you leave your loving aunt and uncle and your comfortable attic on Privet Drive and venture down to fight Voldemort below, we recommend you go to [Hogwarts](https://coda.io/d/Exodus-Wallets-Architecture-and-Best-Practices_dDRDEoXvP_I/Wallets-Architecture_suyd3) and at least learn Lumos.\n\n## Getting started\n\nThis repository uses a modern version of yarn that doesn't support `.npmrc` files anymore. To gain access to Exodus'\nprivate packages, you have to invoke `yarn npm login` and login with your credentials. This has to be done once only.\n\nAfter that, you can install dependencies as usual.\n\n### Migrating an existing module\n\nThis section describes how to migrate an existing module and keep its git commit history.\n\n#### Requirements\n\n- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)\n- [git-filter-repo](https://github.com/newren/git-filter-repo/blob/main/INSTALL.md)\n\nGH SSH authentication [has to be configured](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/about-ssh) or alternatively the `--https` flag has to be used.\n\n#### Usage\n\nInstall `@exodus/migrate` globally (`npm i -g @exodus/migrate`), run `exodus-migrate` and specify the path to the repository, or subdirectory within the repository.\n\nFor the latter you can simply navigate to the subdirectory in the GH UI and copy the URL from your browser's\naddress bar. If the subdirectory does not contain a `package.json`, a basic `package.json` will be created on your\nbehalf. More info can be found in the [`@exodus/migrate` repository](https://github.com/ExodusMovement/exodus-migrate)\n\nExamples:\n\n```sh\n# from a repository URL\nexodus-migrate --url https://github.com/ExodusMovement/some-other-repo --target-dir modules/auto-enable-assets --scope @exodus --rename-tags\n\n\n# from a subdirectory within a repository (can also be from a different branch than master)\nexodus-migrate --url https://github.com/ExodusMovement/some-other-repo/tree/master/src/_local_modules/enabled-assets --target-dir modules/auto-enable-assets --scope @exodus --rename-tags\n```\n\nThe script will replace the `repository`, `homepage`, and `bugs.url` properties in `package.json` to point to hydra\nand set the homepage to the module's folder on master.\n\n2. You should check for potentially broken badges in your README.md, no longer required ci folders,\n   eslint configs, .gitignore files, and lockfiles on package level. `yarn postmigrate` can help to identify unwanted\n   files and create new config files to extend the root configuration in this repository. If the last commit affects files inside the imported package's folder, `yarn postmigrate` will be able to determine the package automatically. Otherwise you can supply the module path manually: `yarn postmigrate modules/orders-monitor`.\n\n3. Many `devDependencies` may no longer be required as they are hoisted to avoid duplication and use the same\n   versions across all modules. Prune what you can from your imported module.\n\n4. The changes cannot be merged using the GH UI without losing the history. Merging has to be done locally to `master`\n   as fast-forward merge. This only works if no other PR has been merged in-between. Using the `--ff-only` flag will\n   make git abort should a fast-forward merge not be possible. All the work was in vain then and you have to start over\n   from `1.` Better be fast this time!\n\n```bash\n  git checkout master\n  git merge $IMPORT_BRANCH --ff-only\n```\n\n5. Last, push to master directly.\n\nNote: if your package is missing them you will most likely need to add `babel.config.js` and `jest.config.js`. `yarn postmigrate` also offers to add them (see 2.)\n\n### Creating a new module\n\nDifferent templates are available to scaffold a module.\n\n#### Library\n\nTo generate a library, use the following:\n\n```\nyarn generate:library my-library\n```\n\nThis will create a basic scaffold under the folder `./libraries/my-library`.\n\n#### Module\n\nTo generate a module, use the following and select the language you'd like to use in the interactive\nprompt that comes up:\n\n```\nyarn generate:module my-module\n```\n\nThis will create a folder `./modules/my-module` in your desired target language. It has a basic test setup and\nlogging pre-configured.\n\n## Development\n\nWhile developing a package in this monorepo, you may want to test it in an app, e.g. your mobile dapp. Unfortunately we can't use `npm link` because mobile's packager `metro` doesn't support symlinks (yet). However, we have a similar tool here to help you sync your changes to the client repos before you publish a new version.\n\nTo link your module to a client repo, run:\n\n```\nyarn run -T sync module-name,other-module-name /path/to/client-repo\n```\n\nThis will start a watch process that syncs the specified modules to `src/node_modules` in that repo. If you need them synced elsewhere, specify a different path as the 2nd argument.\n\nExamples\n\n```\nyarn run -T sync module-name,other-module-name ../my-app\n```\n\n### Test\n\nExamples:\n\n```\n# test one library\nyarn test --scope @exodus/fiat-client\n```\n\n### Build\n\nIf your module needs transpiling (i.e. Babel or Typescript) before publishing, make sure to add\na `build` script to the `package.json` of the module.\n\nExamples:\n\n```\n# build all\nyarn build\n\n# build one library\nyarn build --scope @exodus/fiat-client\n```\n\n### Pack\n\nLerna uses npm/yarn pack and does not allow to specify a custom folder for packing, i.e.\nthe module's root where `package.json` resides is used for packing. This is less than ideal\nfor modules that require transpilation (i.e. Typescript modules) and do not re-export everything\nfrom the entrypoint. Without further steps, imports would have to include the dist folder name such as\n`@exodus/networking-spec/lib/shared`.\n\nOne option to achieve a clean import structure anyway, is to copy the build output to the top\nlevel before packing. The lifecycle script `prepack` can be used for that.\n\nFor further information on the topic please refer to [this GH issue](https://github.com/lerna/lerna/issues/901)\n\n### Version\n\nTo version your packages, either:\n\n- merge a PR with eligible commit type. The following don't trigger a release: `chore`, `docs`, `test`, `ci`\n- run `yarn release` and select the package(s) you want to release\n- run `yarn release` and supply packages as a positional argument: `yarn release networking-mobile,kyc,storage-mobile`\n- run [the version workflow](https://github.com/ExodusMovement/exodus-oss/actions/workflows/version.yaml) directly through the GH UI.\n\nAll of these derive version bumps from the conventional commit history and create a release PR, labeled with `publish-on-merge`. Make sure that the checks on the release PR pass, especially when releasing packages that depend on other packages from this repository.\n\nFor more options to `yarn release`, see the [CLI docs](https://github.com/ExodusMovement/lerna-release-action/tree/master/cli).\n\n### Publish\n\nAll packages that received a version bump in the previous step are automatically published to npm after merging\nthe release PR. The tags listed in the PR body will be added to the merge commit.\n\nInitial versions can be published by manually executing [the publish workflow](https://github.com/ExodusMovement/exodus-oss/actions/workflows/publish.yaml). All packages with versions not currently present in the registry will be published. If unclear how to run the publish workfow, please follow [these](https://user-images.githubusercontent.com/2863630/203893329-f0eca8d0-4f8c-4ccb-abc2-65bfd819fa61.png) instructions.\n\n### Commit messages\n\nCommit messages and PR titles should follow the [conventional commits specification](https://www.conventionalcommits.org/en/v1.0.0-beta.4/#specification). Breaking changes are denoted with a bang (`!`) before the colon (`:`) in the commit message and will result in a major version bump.\n\n\u003e feat!: all roads lead to Gotham\n\nIf your PR only affects a section of a package, you may use a scope. Please refrain from using scopes for package names as they will show up in the `CHANGELOG.md` and the scope is redundant there. PRs are labelled with the package names they affect, so it also doesn't add any value in the GH UI.\n\n🟩 Good\n\n\u003e feat(redux): add hardware wallet account selector\n\n🟥 Bad\n\n\u003e feat(wallet-accounts): add hardware wallet account selector\n\n### Dependencies\n\n#### Breaking changes\n\nOccasionally, it is necessary to introduce a breaking change. Fixing downstream packages may only require a patch or minor, and not always warrant a breaking change. The solution is to create a PR chain. Changes that are breaking from a consumer perspective are isolated in the first PR, and non-breaking downstream errors are fixed in follow-up PRs. To avoid failing checks on master for an extended period, the chain should not be merged manually. Instead, apply the label `action/merge-chain` to the tip of the PR chain. It will merge the first PR, rebase the following PR onto master, and continue on merging until the entire chain is merged.\n\n#### Inter-package\n\nIf your package requires referencing one of the packages maintained in this mono repo and you want\nto consume the latest unpublished changes without having to set a specific version, you have to\nmanually add that dependency to `package.json` and set the version to `*`. This manual step is\ncurrently required because of an incompatibility between more recent yarn versions (berry) and\nlerna.\n\nLatest code changes are automatically reflected in the import and versioning/publishing\ntakes care of keeping the version in the module's `package.json` up-to-date.\n\n##### Typescript\n\nFor TS modules, a path mapping to resolve the import correctly from the `src`\nfolder has to be added. This can be done in the top level `tsconfig.json`:\n\n```json5\n{\n  // ...\n  compilerOptions: {\n    // ...\n    paths: {\n      // ...\n      '@exodus/networking-spec': ['./modules/networking-spec/src'],\n      '@exodus/networking-spec/*': ['./modules/networking-spec/src/*'],\n    },\n  },\n}\n```\n\nThe jest config for these modules, then also has to define a custom `moduleNameMapper`\nthat can be created from the paths definitions in our tsconfig to avoid duplication:\n\n```js\nmodule.exports = {\n  moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {\n    prefix: '\u003crootDir\u003e/../../',\n  }),\n}\n```\n\nA full example can be found [here](./modules/networking-node/jest.config.js)\n\nPlease note that referencing files outside/above the module's directory, will cause tsc to nest\nits build output in `module-name/src` and copy the locally referenced dependency to `outDir`.\nMake sure an adequate `prepack` script is provided to cleanup and prepare the build output before packing.\n\n## CI\n\nThis repo uses sophisticated caching courtesy of nx and Github Actions. When changing non-module-local\nconfiguration/code, you may want to clear the cache in the CI to force checks to re-run. You can do so\nby running `yarn cache:delete` or use the [GH page](https://github.com/ExodusMovement/exodus-oss/actions/caches) for\nmanaging caches. The CLI client has the advantage of being able to purge all caches for a given branch. This is\ncurrently not supported in the UI.\n\n## Conventions\n\nFirst see [general conventions](https://coda.io/d/Engineering-Handbook_dWMI1pUBpME/Recipes-Patterns-Anti-Patterns_suk6k).\n\n### Libraries vs Features vs API slices vs Modules vs Atoms vs Plugins\n\nRefer to our [Lego manual](https://coda.io/d/Engineering-Handbook_dWMI1pUBpME/2-Libraries-modules-atoms-plugins_suw41#_luEGz) to understand key concepts/differences in our architecture.\n\n### Modules\n\n#### Async Initialization\n\nIf your module requires some async initialization, e.g. to load data from storage or an API, expose a public `load()` method, and call it the `load` and `unlock` application lifecycle hooks.\n\n```js\nload = async () =\u003e {\n  this.#cache = await fetchival(this.#someServerUrl).get()\n}\n```\n\n#### Consuming/Producing Data\n\nYour module may need to consume data from `storage`, `fusion`, `remoteConfig` and/or other modules like `walletAccounts`, `blockchainMetadata`, etc.\n\nIn all of these cases, you should prefer accepting an `atom` for that piece of data rather than any of those modules. This lets your module avoid worrying about the specifics of where a value is coming from and instead have a simple API for retrieving and monitoring that value (`{ get, observe, set? }`). It will also make your module much easier to test.\n\nSimilarly, modules should produce/export data by writing it to atoms.\n\n#### Configuration\n\nIf your module accepts some static configuration, e.g. `{ someServerUrl, maxSlippage }`, accept that as an option called `config` in your module's constructor.\n\nIf you're using Exodus's `@exodus/dependency-injection` or `@exodus/headless` to wire up the dependency tree, config values will be auto-magically binded for you from the passed global config by module id:\n\n```js\nimport createHeadless from '@exodus/headless'\nimport createPreprocessors from '@exodus/dependency-preprocessors'\n\nconst config = {\n  feri: {\n    likesSandwiches: true,\n    maxCachacaCapacity: Number.MAX_SAFE_INTEGER + 1,\n  },\n}\n\nconst exodus = createHeadless({ adapters, config })\nexodus.register({\n  definition: {\n    id: 'feri',\n    factory: createFeri, // will get called as `createFeri({ config: config.feri })`\n    dependencies: ['config'],\n  },\n})\n\nexodus.resolve()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexodusmovement%2Fexodus-oss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexodusmovement%2Fexodus-oss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexodusmovement%2Fexodus-oss/lists"}