{"id":15092937,"url":"https://github.com/subdirectory/subshell","last_synced_at":"2025-04-12T06:31:47.051Z","repository":{"id":39628172,"uuid":"507094583","full_name":"subdirectory/subshell","owner":"subdirectory","description":"Substrate API playground in a Deno 🦕 repl, using polkadot-js extension as remote signer ✍️.  Say goodbye to hardcoded mnemonics / seeds in dev scripts!👋","archived":false,"fork":false,"pushed_at":"2025-01-10T17:00:53.000Z","size":2367,"stargazers_count":19,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-10T16:30:25.257Z","etag":null,"topics":["deno","kusama","moonbeam","polkadot","polkadot-js","repl","subshell","substrate","typescript","walletconnect","xterm-js"],"latest_commit_sha":null,"homepage":"https://subshell.xyz","language":"TypeScript","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/subdirectory.png","metadata":{"files":{"readme":".github/README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-24T17:35:25.000Z","updated_at":"2025-01-10T17:00:58.000Z","dependencies_parsed_at":"2023-02-17T19:16:03.442Z","dependency_job_id":"c56c215a-7986-4b25-9d60-6b601768dcc3","html_url":"https://github.com/subdirectory/subshell","commit_stats":{"total_commits":238,"total_committers":6,"mean_commits":"39.666666666666664","dds":0.5252100840336135,"last_synced_commit":"8b5c2d453ca7f9011575dec1ff34d0409465c80c"},"previous_names":["btwiuse/subshell"],"tags_count":105,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subdirectory%2Fsubshell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subdirectory%2Fsubshell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subdirectory%2Fsubshell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subdirectory%2Fsubshell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/subdirectory","download_url":"https://codeload.github.com/subdirectory/subshell/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248529705,"owners_count":21119561,"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":["deno","kusama","moonbeam","polkadot","polkadot-js","repl","subshell","substrate","typescript","walletconnect","xterm-js"],"created_at":"2024-09-25T11:01:55.005Z","updated_at":"2025-04-12T06:31:47.007Z","avatar_url":"https://github.com/subdirectory.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Subshell [❯_](https://subshell.xyz)\n\n[![SubshellBanner](SubshellBanner.png)](https://subshell.xyz)\n\n\u003c!--\n[![GearShellBanner](GearShellBanner.png)](https://gear.sh)\n--\u003e\n\n[![SubshellModule](https://shield.deno.dev/x/subshell)](https://deno.land/x/subshell)\n[![Github Actions Build](https://github.com/btwiuse/subshell/actions/workflows/ci-release.yml/badge.svg)](https://github.com/btwiuse/subshell/actions/workflows/ci-release.yml)\n[![DockerHub](https://img.shields.io/docker/pulls/btwiuse/subshell.svg)](https://hub.docker.com/r/btwiuse/subshell)\n[![License](https://img.shields.io/github/license/btwiuse/subshell?color=%23000\u0026style=flat-round)](https://github.com/btwiuse/subshell/blob/main/LICENSE)\n[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/btwiuse/subshell)\n\nSubstrate API playground in a Deno 🦕 repl, using Polkadot.js extension wallet\nas remote signer ✍️. Say goodbye to hardcoded mnemonics / seeds in dev scripts\n👋!\n\nSubshell at its core is a TypeScript repl with these preloaded lines:\n\n```typescript\nimport {\n  ApiPromise,\n  WsProvider,\n} from \"https://deno.land/x/polkadot@0.2.45/api/mod.ts\";\n\nconst provider = new WsProvider(`wss://polkadot.api.onfinality.io/public-ws`);\n\nconst api = await ApiPromise.create({ provider });\n```\n\nIn addition, it supports signing with your Polkadot.js wallet extension when\naccessed from the web ui. ✨\n\n## Quick Demo\n\nUse `Subshell.extension.selectAccount()` to show an account selection prompt:\n![Subshell](Subshell_select_account.gif)\n\nCalls to `api.sign`, `tx.signAndSend` are proxied to your browser wallet\nextension:\n\n\u003cdiv align=\"center\"\u003e\n  \u003cvideo src=\"https://user-images.githubusercontent.com/54848194/175913885-4ff3e137-f378-47ab-904e-cc1bfd7347a2.mp4\"\u003e\n\u003c/div\u003e\n\n## Give it a try\n\nVisiting [homepage](https://subshell.xyz) will connect you to Polkadot.\n\nUse one of the following links to connect to a different chain:\\\n[Polkadot](https://subshell.xyz/?rpc=wss%3A%2F%2Fpolkadot.api.onfinality.io%2Fpublic-ws#/console)\n|\n[Kusama](https://subshell.xyz/?rpc=wss%3A%2F%2Fkusama.api.onfinality.io%2Fpublic-ws#/console)\n|\n[Moonbeam](https://subshell.xyz/?rpc=wss%3A%2F%2Fmoonbeam.api.onfinality.io%2Fpublic-ws#/console)\n|\n[Acala](https://subshell.xyz/?rpc=wss%3A%2F%2Facala-polkadot.api.onfinality.io%2Fpublic-ws#/console)\n|\n[Litentry](https://subshell.xyz/?rpc=wss%3A%2F%2Facala-polkadot.api.onfinality.io%2Fpublic-ws#/console)\n|\n[Parallel](https://subshell.xyz/?rpc=wss%3A%2F%2Fparallel.api.onfinality.io%2Fpublic-ws#/console)\n| [Phala](https://subshell.xyz/?rpc=wss%3A%2F%2Fapi.phala.network%2Fws#/console)\n| [Aleph Zero](https://subshell.xyz/?rpc=wss%3A%2F%2Fws.azero.dev#/console) |\n[Darwinia](https://subshell.xyz/?rpc=wss%3A%2F%2Frpc.darwinia.network#/console)\n|\n[ChainX](https://subshell.xyz/?rpc=wss%3A%2F%2Fmainnet.chainx.org%2Fws#/console)\n|\n[Edgeware](https://subshell.xyz/?rpc=wss%3A%2F%2Fedgeware.api.onfinality.io%2Fpublic-ws#/console)\n|\n[NFTMart](https://subshell.xyz/?rpc=wss%3A%2F%2Fmainnet.nftmart.io%2Frpc%2Fws#/console)\n| ...\n\nRead the\n[cheatsheet](https://github.com/btwiuse/subshell/wiki/Subshell-Cheatsheet) to\nget a basic idea of how to use the repl.\n\nMaintainers of Polkadot.js libraries have made a preview release for Deno under\nthe [deno.land/x/polkadot](https://deno.land/x/polkadot) namespace.\n[![PolkadotModule](https://shield.deno.dev/x/polkadot)](https://deno.land/x/polkadot)\n\nYou can import them like this in the Deno repl:\n\n```\nimport { stringToU8a } from 'https://deno.land/x/polkadot@0.2.45/util/mod.ts';\n```\n\nSubshell sessions run in patched\n[denoland/deno](https://github.com/denoland/deno) to provide better repl\nexperience. The frontend is based on\n[polkadot-js/apps](https://github.com/polkadot-js/apps). The modified code will\nbe published soon.\n\n## Motivation\n\nAs a long term *nix user who does distro hopping from time to time, I often see\n(para)chains in the DotSama ecosystem as distros of Parity/Substrate, in the\nsame sense that Arch, Debian, Gentoo, chromeOS and Android are different flavors\nof GNU/Linux.\n\n(Guess which Linux distro I use the most?)\n\nTaking the analogy a step further, in Linux based systems, once you have\nmastered the art of shell scripting, it becomes easy to switch between distros.\n\nLikewise, if you are familiar with the Polkadot.js api, you will quickly learn\nhow to play with new chains based on Substrate when they come out.\n\nFor the Linux kernel, we have a lot of shells: bash, zsh, fish, ash, dash, csh,\nksh, etc. , in which we interactively type commands to perform various kinds of\ntasks.\n\nWhile for Substrate, has there been anything like a shell? Yes,\n[quite a few](#Prior-Art) on the Node.js runtime, but at the same time they all\nfeel somewhat lacking to me.\n\nReasons:\n\n- You cannot add new imports on demand from a Node.js repl. You have to npm\n  install or add them to your local NODE_PATH first.\n- It's painful to deal with cjs / esm incompatibility.\n- Hard coding mnemonics / seeds in scripts could lead to potential leak.\n- None of those projects are actively maintained. Polkadot.js libraries version\n  are out of date\n- Node.js is not cool any more. It got\n  [rejected](https://medium.com/@imior/10-things-i-regret-about-node-js-ryan-dahl-2ba71ff6b4dc)\n  by its original creator.\n\nSubshell is trying to avoid aforementioned problems by leveraging the power of\nDeno, a modern runtime for JavaScript and TypeScript.\n\n## Features\n\nHere are Subshell's advantages over existing Node.js based shells.\n\n### Accessibility\n\n- Available as a web app, no installation required\n- One click away from a drop-in dev terminal in browser\n\n### Compatibility\n\n- Works out of the box with most chains in the DotSama ecosystem\n- Plays nice with existing projects, like\n  [Substrate Playground](https://playground.substrate.dev). For example: use\n  [`https://subshell.xyz/?rpc=wss://btwiuse.playground.substrate.dev/wss`](https://subshell.xyz/?rpc=wss://btwiuse.playground.substrate.dev/wss)\n  to connect to my playground dev node.\n- `--compat` is turned on by default, so you can still use built-in modules from\n  Node.js\n- Added patches to improve the repl experience. The runtime is kept inact. Any\n  Subshell scripts are also valid Deno scripts\n\nIn fact, you can load the Subshell init script in Deno.\n\n```\n$　deno repl --unstable --eval-file=https://deno.land/x/subshell@0.2.45-4/init.ts\n...\nDeno 1.23.2\nexit using ctrl+d or close()\n\u003e api.tx. # Here tab completion won't show up\n```\n\nBut it won't tab complete in some circumstances (see\n[denoland/deno#14967](https://github.com/denoland/deno/issues/14967)). Subshell\nused a custom patch to fix that. Plus you lose the ability to sign messages /\ntransactions with browser wallet extension. So the recommend way is to access\nSubshell from the web ui.\n\n### Customizability\n\n- You can override the init script (soon)\n- Custom types can be added the same way in Polkadot.js Apps\n- You can easily load your custom scripts to decorate the api, in the way you\n  want. For example:\n  [HackathonApi](https://github.com/equilibrium-eosdt/polkadot-hackathon/blob/3ea796b56c410e84077bce54fc1359d75c0bd6d1/test-case/src/chain-ops/api.ts#L22)\n\n### Infinite extensibility\n\n- The decentralized nature of Deno's package import system allows you to load\n  dependencies from url in the repl. You are not limited to\n  [deno.land/std](https://deno.land/std), [deno.land/x](https://deno.land/x).\n  The only limit is your imagination.\n\n### Done right security\n\n- Sign messages / transactions with Polkadot.js wallet extension. Never make\n  keys leave your wallet again!\n- Filesystem / network access can be disabled when you run scripts written by\n  untrusted parties, thanks to\n  [sandboxing in Deno](https://medium.com/deno-the-complete-reference/sandboxing-in-deno-b3d514d88b63)\n\n## How it works\n\nAt first glance, you might think that the Deno repl is running directly inside\nyour browser. That's only an illusion. In fact, there are three parties involved\nin a Subshell session:\n\n- 🦕: Deno (Rust)\n- 🕸️: Relay server (Golang)\n- 🌐: Frontend web ui (TypeScript)\n\n### Communication mechanism\n\nFirst, Deno is running as a remote process on a worker container, inside a Pod\non Kubernetes, with a persistent bidirectional JSON RPC connection over\nWebSocket to the relay server.\n\n🦕⇆🕸️\n\nOnce you open the web ui from your browser, it will similarly establish a\nconnection to the relay.\n\n🌐⇆🕸️\n\nThese two connections are then spliced together by the relay server,\n\n🌐⇆🕸️⇆🦕\n\ncreating an illusion that your browser is directly connected to Deno, full\nduplex:\n\n🌐⇆⇆🦕\n\nIn full duplex communication, both ends can send and receive data to the other\nend at the same time.\n\nSince both ends speak JSON RPC, the browser 🌐 can invoke methods available on\nthe Deno 🦕 side, and vice versa.\n\nYou might ask, when could the browser 🌐 become a server? And how is this\nuseful? That is covered in the next section.\n\n### Remote signer bridge\n\nWhen Subshell starts, the api object is created from the Deno repl context.\n\n#### The signing problem\n\nWith an `api` object, you can query on-chain data using `api.consts.*.*`,\n`api.query.*.*` etc.\n\nBut it becomes clumsy when you want to send transactions with `api.tx.*.*`,\nbecause `api` does not come with a default signer.\n\nWhat if you want to sign data with your own keys?\n\nIn your local dev environment it's fine to create a\n[keyring](https://polkadot.js.org/docs/api/start/keyring/), import your\nmnemonics / seed and set it as the signer:\n\n```\nimport { Keyring } from '@polkadot/api';\n\n// Create a keyring instance\nconst keyring = new Keyring({ type: 'sr25519' });\n\n// Add an account\nconst alice = keyring.addFromUri('//Alice');\n\n// Set default signer\napi.setSigner(alice)\n```\n\nBut keep in mind:\n\n1. Private keys are supposed to be private.\n2. Subshell is running in the cloud.\n3. The cloud is just someone else's computer.\n\nTherefore, you should never import your keys to Subshell.\n\nIs there any approach to secure signing in an untrusted environment?\nFortunately, there is a workaround.\n\nThanks to the work started by **Ian He** in\n[polkadot-js/api#660](https://github.com/polkadot-js/api/issues/660), the\n[Signer](https://github.com/polkadot-js/api/blob/977eb3f9ecb8a2fb57b46b7da7f797b56a9e8bf2/packages/types/src/types/extrinsic.ts#L135-L150)\nis now an interface, and the polkadot.js extension provides\n[an implementation](https://github.com/polkadot-js/extension/blob/b858f6eee12a42f570da2e0ee9b5e8f644a4494b/packages/extension-base/src/page/Signer.ts#L12-L45)\nto it.\n\nWe can expose the implementation through the browser 🌐 side JSON RPC server,\nand use RemoteSignerBridge as the Signer implementation in Deno 🦕 repl context,\nwhere signing requests will be forwarded to the wallet extension via JSON RPC\ncalls.\n\nPseudocode:\n\n```\nclass RemoteSignerBridge implements Signer {\n  signPayload (payload: SignerPayloadJSON) =\u003e Promise\u003cSignerResult\u003e {\n    return jsonRpcClient.signPayload(payload)\n  }\n  signRaw (raw: SignerPayloadRaw) =\u003e Promise\u003cSignerResult\u003e {\n    return jsonRpcClient.signRaw(raw)\n  }\n  ...\n}\n\napi.setSigner(new RemoteSignerBridge())\n```\n\nBy applying this technique, you can safely do `api.sign`,\n`api.tx.*.*.signAndSend` in the remote Deno 🦕 repl, and sign it with the\nPolkadot.js wallet extension in your browser🌐.\n\n## FAQ\n\n### Q: Does it use WASM?\n\n\u003e No, it doesn't. The repl is running remotely in a linux container, not in our\n\u003e browser.\n\n### Q: Can I use MetaMask on Moonbeam and other EVM compatible chains?\n\n\u003e Currently no, but it's on the roadmap.\n\n### Q: Is the relay server 🕸️ component open sourced?\n\n\u003e Yes. It is currently implemented as a module in\n\u003e [btwiuse/k0s](https://github.com/btwiuse/k0s) (Golang). I'm planning on\n\u003e porting it to Deno/TypeScript. I will probably borrow some ideas from\n\u003e [the old paritytech/substrate-telemetry backend](https://github.com/paritytech/substrate-telemetry/tree/a3b6f6a5a19475f1ea73d56a7fa883ec0a66140a/packages/backend/src).\n\n### Q: How can I deploy it locally?\n\n\u003e I will make an all-in-one Docker image that hold everything in one place. It\n\u003e should will be available soon. Stay tuned.\n\n## Prior Art\n\n- https://github.com/halva-suite/halva\n- https://github.com/cennznet/cli\n- https://github.com/compound-finance/gateway/tree/develop/chains\n- https://github.com/cryptolab-network/polkadot-api-cli\n\n## LICENSE\n\n```\nMIT License\n\nCopyright (c) 2022 btwiuse\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubdirectory%2Fsubshell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsubdirectory%2Fsubshell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubdirectory%2Fsubshell/lists"}