├── .changeset ├── README.md ├── config.json └── dependencies-GH-2669.md ├── .editorconfig ├── .eslintrc.cjs ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_report.yaml ├── actions │ ├── publish-package │ │ └── action.yml │ └── turbo-build │ │ └── action.yml ├── dependabot.yml ├── mergify.yml └── workflows │ ├── auto-merge.yml │ ├── ci.yml │ ├── dependabot-changeset.yml │ ├── pr-ci.yml │ ├── reusable-ci.yml │ └── update-chain-specs.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc ├── CONTRIBUTING.md ├── DEPLOY-RELEASE.md ├── LICENSE ├── README.md ├── examples ├── light-client-dapp │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── .gitkeep │ ├── src │ │ ├── App.tsx │ │ ├── api │ │ │ ├── createTransaction.ts │ │ │ ├── getClient.ts │ │ │ ├── getObservableClient.ts │ │ │ ├── index.ts │ │ │ ├── submitTransaction$.ts │ │ │ ├── systemAccount$.ts │ │ │ └── transferAllowDeathCallData.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── components │ │ │ ├── ChainSelect.tsx │ │ │ ├── ConnectedAccount.tsx │ │ │ ├── Toast.tsx │ │ │ ├── Transfer.tsx │ │ │ └── index.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useChains.ts │ │ │ ├── useIsMounted.ts │ │ │ ├── useModal.tsx │ │ │ ├── useSystemAccount.ts │ │ │ └── useUnstableProvider.tsx │ │ ├── main.tsx │ │ ├── settings.ts │ │ ├── types.ts │ │ └── vite-env.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── light-client-extension-helpers-dapp │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── chainspecs │ │ │ └── westend-westmint.json │ │ ├── components │ │ │ └── Chain.tsx │ │ ├── containers │ │ │ └── Chains.tsx │ │ ├── hooks │ │ │ ├── useChain.ts │ │ │ ├── useChains.ts │ │ │ ├── useIsMounted.ts │ │ │ └── useProvider.ts │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── light-client-extension-helpers-extension │ ├── .gitignore │ ├── assets │ │ ├── manifest.json │ │ └── options.html │ ├── package.json │ ├── playwright.config.ts │ ├── src │ │ ├── background-smoldot.code-split.ts │ │ ├── background.ts │ │ ├── content.ts │ │ ├── inpage.ts │ │ ├── options.ts │ │ ├── protocol.ts │ │ └── test-data │ │ │ ├── kusama.ts │ │ │ └── westend.ts │ ├── tests │ │ ├── dapp.spec.ts │ │ └── fixtures.ts │ ├── tsconfig.json │ └── tsup.config.ts └── smoldot-discovery-example │ ├── .eslintignore │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── components.json │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── vite.svg │ ├── src │ ├── App.css │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── components │ │ └── ui │ │ │ ├── accordion.tsx │ │ │ ├── alert-dialog.tsx │ │ │ ├── alert.tsx │ │ │ ├── aspect-ratio.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── breadcrumb.tsx │ │ │ ├── button.tsx │ │ │ ├── calendar.tsx │ │ │ ├── card.tsx │ │ │ ├── carousel.tsx │ │ │ ├── chart.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── command.tsx │ │ │ ├── context-menu.tsx │ │ │ ├── dialog.tsx │ │ │ ├── drawer.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── form.tsx │ │ │ ├── hover-card.tsx │ │ │ ├── input-otp.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── menubar.tsx │ │ │ ├── navigation-menu.tsx │ │ │ ├── pagination.tsx │ │ │ ├── popover.tsx │ │ │ ├── progress.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── resizable.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── select.tsx │ │ │ ├── separator.tsx │ │ │ ├── sheet.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── slider.tsx │ │ │ ├── sonner.tsx │ │ │ ├── switch.tsx │ │ │ ├── table.tsx │ │ │ ├── tabs.tsx │ │ │ ├── textarea.tsx │ │ │ ├── toast.tsx │ │ │ ├── toaster.tsx │ │ │ ├── toggle-group.tsx │ │ │ ├── toggle.tsx │ │ │ ├── tooltip.tsx │ │ │ └── use-toast.ts │ ├── global.css │ ├── lib │ │ └── utils.ts │ ├── main.tsx │ └── vite-env.d.ts │ ├── tailwind.config.js │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── package.json ├── packages ├── README.md ├── connect-discovery │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── connect-extension-protocol │ ├── .eslintignore │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── typedoc.json ├── connect-known-chains │ ├── .eslintignore │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── scripts │ │ └── build-js-specs.js │ ├── specs │ │ ├── ksmcc3.json │ │ ├── ksmcc3_asset_hub.json │ │ ├── ksmcc3_bridge_hub.json │ │ ├── ksmcc3_people.json │ │ ├── paseo.json │ │ ├── polkadot.json │ │ ├── polkadot_asset_hub.json │ │ ├── polkadot_bridge_hub.json │ │ ├── polkadot_collectives.json │ │ ├── polkadot_people.json │ │ ├── rococo_v2_2.json │ │ ├── rococo_v2_2_asset_hub.json │ │ ├── rococo_v2_2_bridge_hub.json │ │ ├── westend2.json │ │ ├── westend2_asset_hub.json │ │ ├── westend2_bridge_hub.json │ │ ├── westend2_collectives.json │ │ └── westend_people.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── turbo.json ├── connect │ ├── .eslintignore │ ├── .gitignore │ ├── .npmignore │ ├── .npmrc │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── connector │ │ │ ├── getSpec.ts │ │ │ ├── index.ts │ │ │ ├── smoldot-light.test.ts │ │ │ ├── smoldot-light.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── worker-browser.mts │ │ └── worker.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── typedoc.json ├── discovery │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── light-client-extension-helpers │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── background │ │ │ ├── background-helper.ts │ │ │ ├── createBackgroundRpc.ts │ │ │ ├── json-rpc-provider.ts │ │ │ ├── smoldot-provider.ts │ │ │ └── types.ts │ │ ├── content-script │ │ │ ├── content-script-helper.ts │ │ │ └── types.ts │ │ ├── extension-page │ │ │ ├── extension-page-helper.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── known-chain-specs │ │ │ ├── index.ts │ │ │ ├── ksmcc3.ts │ │ │ ├── paseo.ts │ │ │ ├── polkadot.ts │ │ │ ├── rococo_v2_2.ts │ │ │ └── westend2.ts │ │ ├── protocol.ts │ │ ├── shared │ │ │ ├── constants.ts │ │ │ ├── createBackgroundClientConnectProvider.ts │ │ │ ├── getRandomChainId.ts │ │ │ ├── index.ts │ │ │ └── message-utils.ts │ │ ├── smoldot │ │ │ ├── client.ts │ │ │ ├── index.ts │ │ │ ├── tasks.ts │ │ │ └── types.ts │ │ ├── storage │ │ │ └── index.ts │ │ ├── tx-helper │ │ │ ├── index.ts │ │ │ ├── polkadot-api │ │ │ │ ├── index.ts │ │ │ │ └── tx-helper │ │ │ │ │ ├── README.md │ │ │ │ │ ├── compatibility.ts │ │ │ │ │ ├── create-tx.ts │ │ │ │ │ ├── descriptors.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── signed-extensions │ │ │ │ │ ├── chain │ │ │ │ │ │ ├── CheckGenesis.ts │ │ │ │ │ │ ├── CheckMetadataHash.ts │ │ │ │ │ │ ├── CheckNonce.ts │ │ │ │ │ │ ├── CheckSpecVersion.ts │ │ │ │ │ │ ├── CheckTxVersion.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── internal-types.ts │ │ │ │ │ ├── user │ │ │ │ │ │ ├── ChargeAssetTxPayment.ts │ │ │ │ │ │ ├── ChargeTransactionPayment.ts │ │ │ │ │ │ ├── CheckMortality.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── submit-fns.ts │ │ │ │ │ ├── tx.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils │ │ │ │ │ ├── continue-with.ts │ │ │ │ │ └── index.ts │ │ │ └── types.ts │ │ ├── utils │ │ │ ├── createRpc.ts │ │ │ └── index.ts │ │ └── web-page │ │ │ ├── types │ │ │ ├── LightClientProvider.ts │ │ │ ├── LightClientProviderDiscovery.ts │ │ │ ├── WebPageRpcSpec.ts │ │ │ └── index.ts │ │ │ └── web-page-helper.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── logs-provider │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── mod.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── smoldot-discovery-connector │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsup.config.ts ├── smoldot-discovery │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── types │ │ │ └── index.ts │ ├── tsconfig.build.json │ └── tsconfig.json └── ws-provider │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ └── mod.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsup.config.ts ├── patches └── @polkadot-api__ws-provider.patch ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── projects ├── burnr │ ├── .eslintignore │ ├── .gitignore │ ├── LICENSE │ ├── package.json │ ├── public │ │ └── assets │ │ │ ├── favicons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── browserconfig.xml │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon.ico │ │ │ ├── mstile-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ ├── mstile-310x150.png │ │ │ ├── mstile-310x310.png │ │ │ ├── mstile-70x70.png │ │ │ ├── safari-pinned-tab.svg │ │ │ └── site.webmanifest │ │ │ └── images │ │ │ ├── logo.png │ │ │ ├── logo_substrate.svg │ │ │ └── logo_substrate_onDark.svg │ ├── src │ │ ├── App.tsx │ │ ├── Home.tsx │ │ ├── assets │ │ │ ├── favicons │ │ │ │ ├── android-chrome-192x192.png │ │ │ │ ├── android-chrome-512x512.png │ │ │ │ ├── apple-touch-icon.png │ │ │ │ ├── browserconfig.xml │ │ │ │ ├── favicon-16x16.png │ │ │ │ ├── favicon-32x32.png │ │ │ │ ├── favicon.ico │ │ │ │ ├── mstile-144x144.png │ │ │ │ ├── mstile-150x150.png │ │ │ │ ├── mstile-310x150.png │ │ │ │ ├── mstile-310x310.png │ │ │ │ ├── mstile-70x70.png │ │ │ │ ├── safari-pinned-tab.svg │ │ │ │ └── site.webmanifest │ │ │ └── images │ │ │ │ ├── logo.png │ │ │ │ ├── logo_substrate.svg │ │ │ │ └── logo_substrate_onDark.svg │ │ ├── components │ │ │ ├── AccountBurn.tsx │ │ │ ├── AccountCard.tsx │ │ │ ├── AccountMenu.tsx │ │ │ ├── BalanceValue.tsx │ │ │ ├── Bg.tsx │ │ │ ├── ErrorBoundary.tsx │ │ │ ├── Head.tsx │ │ │ ├── HistoryTable.tsx │ │ │ ├── HistoryTableRow.tsx │ │ │ ├── InputAddress.tsx │ │ │ ├── InputFunds.tsx │ │ │ ├── LogoSubstrate.tsx │ │ │ ├── NavFooter.tsx │ │ │ ├── NavTabs.tsx │ │ │ ├── NodeConnected.tsx │ │ │ ├── PopoverExtrinsic.tsx │ │ │ ├── ReceiveFundsForm.tsx │ │ │ ├── SendFundsForm.tsx │ │ │ ├── ThemeButton.tsx │ │ │ ├── ThemeToggleProvider.tsx │ │ │ └── index.tsx │ │ ├── hooks │ │ │ ├── api │ │ │ │ ├── useApi.ts │ │ │ │ ├── useApiCreate.ts │ │ │ │ ├── useIsMountedRef.ts │ │ │ │ └── useLocalStorage.ts │ │ │ ├── index.tsx │ │ │ └── useBalance.ts │ │ ├── index.d.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── themes │ │ │ ├── index.ts │ │ │ └── substrate │ │ │ │ ├── BrandDeck.pdf │ │ │ │ ├── colors.ts │ │ │ │ ├── dark.ts │ │ │ │ ├── light.ts │ │ │ │ ├── shadows.ts │ │ │ │ └── typography.ts │ │ └── utils │ │ │ ├── constants.ts │ │ │ ├── contexts.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ ├── tsconfig.json │ └── vite.config.js ├── demo │ ├── .eslintignore │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── view.ts │ │ └── vite-env.d.ts │ └── tsconfig.json ├── extension │ ├── .eslintignore │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── assets │ │ ├── chainspecs │ │ │ ├── ksmcc3.json │ │ │ ├── paseo.json │ │ │ ├── polkadot.json │ │ │ ├── rococo_v2_2.json │ │ │ └── westend2.json │ │ ├── icons │ │ │ ├── icon-128.png │ │ │ ├── icon-16.png │ │ │ ├── icon-32.png │ │ │ └── icon-48.png │ │ ├── manifest-v3-chrome.json │ │ ├── manifest-v3-firefox.json │ │ ├── options.html │ │ └── popup.html │ ├── package.json │ ├── playwright.config.ts │ ├── postcss.config.cjs │ ├── readme.md │ ├── scripts │ │ ├── checkExtensionScriptSizes.js │ │ └── generateManifest.js │ ├── src │ │ ├── background │ │ │ ├── heartbeat.ts │ │ │ └── index.ts │ │ ├── components │ │ │ ├── Accordion.tsx │ │ │ ├── Bootnodes.css │ │ │ ├── Bootnodes.tsx │ │ │ ├── BraveModal.tsx │ │ │ ├── IconWeb3.tsx │ │ │ ├── Logo.tsx │ │ │ ├── MenuContent.tsx │ │ │ ├── NetworkTab.tsx │ │ │ ├── Networks.tsx │ │ │ ├── Switch.tsx │ │ │ ├── Title.tsx │ │ │ ├── index.tsx │ │ │ └── theme.tsx │ │ ├── constants.ts │ │ ├── containers │ │ │ ├── Options.tsx │ │ │ ├── Popup.tsx │ │ │ └── index.tsx │ │ ├── content │ │ │ └── index.ts │ │ ├── environment.ts │ │ ├── fonts │ │ │ ├── Web3-Regular.otf │ │ │ ├── Web3-Regular.woff │ │ │ └── Web3-Regular.woff2 │ │ ├── hooks │ │ │ ├── useActiveChains.ts │ │ │ └── useIsMounted.ts │ │ ├── inpage │ │ │ └── index.ts │ │ ├── main.css │ │ ├── options.tsx │ │ ├── popup.tsx │ │ ├── style.css │ │ ├── types │ │ │ └── index.ts │ │ └── vite-env.d.ts │ ├── tailwind.config.json │ ├── tests │ │ ├── demo.spec.ts │ │ └── fixtures.ts │ ├── tsconfig.json │ ├── vite.script.config.js │ └── vite.ui.config.js └── wallet-template │ ├── .eslintignore │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── STEP-BY-STEP-GUIDE.md │ ├── assets │ ├── chainspecs │ │ ├── ksmcc3.json │ │ ├── paseo.json │ │ ├── polkadot.json │ │ ├── rococo_v2_2.json │ │ └── westend2.json │ ├── icons │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-32.png │ │ └── icon-48.png │ ├── img │ │ ├── how-it-works.png │ │ ├── lc-dapp-step-1.png │ │ ├── lc-dapp-step-2.png │ │ ├── lc-dapp-step-3.png │ │ ├── lc-dapp-step-4.png │ │ ├── smoldot-discovery-example.png │ │ ├── step1.png │ │ ├── step2.png │ │ └── step3.png │ ├── manifest-v3-chrome.json │ ├── manifest-v3-firefox.json │ ├── options.html │ └── wallet-popup.html │ ├── components.json │ ├── package.json │ ├── playwright.config.ts │ ├── postcss.config.js │ ├── scripts │ ├── checkExtensionScriptSizes.js │ └── generateManifest.js │ ├── src │ ├── background │ │ ├── createBackgroundRpc.ts │ │ ├── heartbeat.ts │ │ ├── index.ts │ │ ├── keyring.ts │ │ ├── keystore │ │ │ ├── index.ts │ │ │ ├── keystoreV4.test.ts │ │ │ ├── keystoreV4.ts │ │ │ └── types.ts │ │ ├── pjs.ts │ │ ├── rpc │ │ │ ├── chainspec.ts │ │ │ └── types.ts │ │ ├── storage.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── components │ │ ├── Bootnodes.css │ │ ├── Bootnodes.tsx │ │ ├── BraveModal.tsx │ │ ├── IconWeb3.tsx │ │ ├── Layout.tsx │ │ ├── Layout2.tsx │ │ ├── Logo.tsx │ │ ├── MenuContent.tsx │ │ ├── Switch.tsx │ │ ├── Title.tsx │ │ ├── index.tsx │ │ ├── theme.tsx │ │ └── ui │ │ │ ├── accordion.tsx │ │ │ ├── alert-dialog.tsx │ │ │ ├── alert.tsx │ │ │ ├── aspect-ratio.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── breadcrumb.tsx │ │ │ ├── button.tsx │ │ │ ├── calendar.tsx │ │ │ ├── card.tsx │ │ │ ├── carousel.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── command.tsx │ │ │ ├── context-menu.tsx │ │ │ ├── dialog.tsx │ │ │ ├── drawer.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── form.tsx │ │ │ ├── hover-card.tsx │ │ │ ├── input-otp.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── menubar.tsx │ │ │ ├── navigation-menu.tsx │ │ │ ├── pagination.tsx │ │ │ ├── popover.tsx │ │ │ ├── progress.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── resizable.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── select.tsx │ │ │ ├── separator.tsx │ │ │ ├── sheet.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── slider.tsx │ │ │ ├── sonner.tsx │ │ │ ├── switch.tsx │ │ │ ├── table.tsx │ │ │ ├── tabs.tsx │ │ │ ├── textarea.tsx │ │ │ ├── toast.tsx │ │ │ ├── toaster.tsx │ │ │ ├── toggle-group.tsx │ │ │ ├── toggle.tsx │ │ │ ├── tooltip.tsx │ │ │ └── use-toast.ts │ ├── constants.ts │ ├── containers │ │ ├── Options.tsx │ │ ├── WalletPopup.tsx │ │ ├── WalletPopup │ │ │ ├── api │ │ │ │ ├── decodeCallData.ts │ │ │ │ ├── index.ts │ │ │ │ └── rpc.ts │ │ │ ├── components │ │ │ │ ├── BottomNavBar.tsx │ │ │ │ ├── CopyButton.tsx │ │ │ │ ├── DecodedCallData.tsx │ │ │ │ ├── Header.tsx │ │ │ │ ├── NetworkTab.tsx │ │ │ │ ├── ProtectedRoute.tsx │ │ │ │ ├── UserSignedExtensionInputs.tsx │ │ │ │ ├── UserSignedExtensions.tsx │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── useKeyring.tsx │ │ │ └── pages │ │ │ │ ├── Accounts │ │ │ │ ├── AccountDetails.tsx │ │ │ │ ├── Accounts.tsx │ │ │ │ ├── AddAccount.tsx │ │ │ │ ├── ImportAccounts.tsx │ │ │ │ ├── SwitchAccount.tsx │ │ │ │ ├── index.ts │ │ │ │ └── networks.ts │ │ │ │ ├── AddChainByUser.tsx │ │ │ │ ├── ChangePassword.tsx │ │ │ │ ├── CreatePassword.tsx │ │ │ │ ├── Debug.tsx │ │ │ │ ├── Networks.tsx │ │ │ │ ├── Options │ │ │ │ ├── AddChainSpec.tsx │ │ │ │ ├── ChainSpecs.tsx │ │ │ │ └── ListChainSpecs.tsx │ │ │ │ ├── SignRequest.tsx │ │ │ │ ├── UnlockKeyring.tsx │ │ │ │ ├── Welcome.tsx │ │ │ │ └── index.ts │ │ └── index.tsx │ ├── content │ │ └── index.ts │ ├── environment.ts │ ├── fonts │ │ ├── Web3-Regular.otf │ │ ├── Web3-Regular.woff │ │ └── Web3-Regular.woff2 │ ├── hooks │ │ ├── useActiveChains.ts │ │ └── useIsMounted.ts │ ├── inpage │ │ ├── index.ts │ │ ├── pjsInject.ts │ │ └── types.ts │ ├── lib │ │ └── utils.ts │ ├── main.css │ ├── options.tsx │ ├── style.css │ ├── types │ │ ├── UserSignedExtension.ts │ │ └── index.ts │ ├── vite-env.d.ts │ └── wallet-popup.tsx │ ├── tailwind.config.js │ ├── tests │ ├── demo.spec.ts │ ├── fixtures.ts │ ├── utils.ts │ └── wallet.spec.ts │ ├── tsconfig.json │ ├── vite.script.config.js │ ├── vite.ui.config.js │ └── vitest.config.ts ├── tsconfig.base.json ├── tsconfig.build.json ├── turbo.json ├── typedoc.json └── vitest.config.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [ 11 | "@substrate/demo", 12 | "@substrate/burnr", 13 | "light-client-dapp", 14 | "light-client-extension-helpers-dapp", 15 | "light-client-extension-helpers-extension", 16 | "smoldot-discovery-example" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.changeset/dependencies-GH-2669.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@substrate/extension": patch 3 | "@substrate/wallet-template": patch 4 | --- 5 | 6 | chore(deps-dev): bump vite in the npm_and_yarn group 7 | 8 | Bumps the npm_and_yarn group with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). 9 | 10 | 11 | Updates `vite` from 6.0.9 to 6.0.12 12 | - [Release notes](https://github.com/vitejs/vite/releases) 13 | - [Changelog](https://github.com/vitejs/vite/blob/v6.0.12/packages/vite/CHANGELOG.md) 14 | - [Commits](https://github.com/vitejs/vite/commits/v6.0.12/packages/vite) 15 | 16 | --- 17 | updated-dependencies: 18 | - dependency-name: vite 19 | dependency-type: direct:development 20 | dependency-group: npm_and_yarn 21 | ... 22 | 23 | Signed-off-by: dependabot[bot] 24 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | charset = utf-8 10 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | parserOptions: { 5 | tsconfigRootDir: __dirname, 6 | project: ["./packages/*/tsconfig.json", "./projects/*/tsconfig.json"], 7 | }, 8 | settings: { react: { version: "detect" } }, 9 | extends: ["react-app", "prettier"], 10 | rules: { 11 | "import/no-extraneous-dependencies": [ 12 | "error", 13 | { 14 | devDependencies: ["**/*.test.ts", "**/*.spec.ts", "**/*.bench.ts"], 15 | }, 16 | ], 17 | "@typescript-eslint/no-redeclare": "off", 18 | }, 19 | env: { 20 | browser: true, 21 | }, 22 | globals: { 23 | chrome: true, 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /.github/actions/turbo-build/action.yml: -------------------------------------------------------------------------------- 1 | name: Turbo build 2 | inputs: 3 | node-version: 4 | description: Node version 5 | required: true 6 | default: 22.x 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Cache turbo build setup 11 | uses: actions/cache@v3 12 | with: 13 | path: .turbo 14 | key: ${{ runner.os }}-turbo-${{ inputs.node-version }}-build-${{ github.sha }} 15 | restore-keys: | 16 | ${{ runner.os }}-turbo-${{ inputs.node-version }}-build- 17 | - uses: pnpm/action-setup@v2 18 | - name: Use Node.js ${{ inputs.node-version }} 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: ${{ inputs.node-version }} 22 | cache: pnpm 23 | - run: pnpm install 24 | shell: bash 25 | - run: pnpm turbo build test lint --cache-dir=.turbo 26 | shell: bash 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: npm 5 | directory: "/" 6 | labels: 7 | - "automerge" 8 | schedule: 9 | interval: daily 10 | groups: 11 | polkadot-api: 12 | patterns: 13 | - "@polkadot-api/*" 14 | - "polkadot-api" 15 | polkadot-labs: 16 | patterns: 17 | - "@polkadot-labs/*" 18 | pjs: 19 | patterns: 20 | - "@polkadot/*" 21 | radix-ui: 22 | patterns: 23 | - "@radix-ui/*" 24 | 25 | - package-ecosystem: github-actions 26 | directory: '/' 27 | labels: 28 | - "automerge" 29 | schedule: 30 | interval: weekly 31 | -------------------------------------------------------------------------------- /.github/mergify.yml: -------------------------------------------------------------------------------- 1 | queue_rules: 2 | - name: default 3 | queue_conditions: 4 | - check-success=all 5 | - label=automerge 6 | - base=main 7 | - "#changes-requested-reviews-by=0" 8 | - "#approved-reviews-by>=1" 9 | merge_conditions: 10 | - check-success=all 11 | - label=automerge 12 | - base=main 13 | - "#changes-requested-reviews-by=0" 14 | - "#approved-reviews-by>=1" 15 | merge_method: squash 16 | 17 | pull_request_rules: 18 | - name: automatic merge when CI passes on main 19 | conditions: [] 20 | actions: 21 | queue: 22 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-changeset.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot Changeset 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened, synchronize, labeled] 6 | 7 | jobs: 8 | renovate: 9 | name: Update Dependabot PR 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | 13 | steps: 14 | - name: Generate a token 15 | id: gen_token 16 | uses: actions/create-github-app-token@v2 17 | with: 18 | app-id: ${{ secrets.SUBSTRATE_CONNECT_PR_APP_ID }} 19 | private-key: ${{ secrets.SUBSTRATE_CONNECT_PR_APP_KEY }} 20 | owner: ${{ github.repository_owner }} 21 | - uses: actions/checkout@v4.1.7 22 | - name: Update PR 23 | uses: mscharley/dependency-changesets-action@v1.1.5 24 | with: 25 | token: ${{ steps.gen_token.outputs.token }} 26 | use-conventional-commits: false 27 | author-name: GitHub Action 28 | author-email: action@github.com 29 | -------------------------------------------------------------------------------- /.github/workflows/pr-ci.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request CI 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | permissions: read-all 8 | 9 | jobs: 10 | run-ci: 11 | uses: ./.github/workflows/reusable-ci.yml 12 | with: 13 | upload-artifacts: false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | yarn-error.log 4 | dist 5 | # testing 6 | coverage 7 | _site 8 | *.tsbuildinfo 9 | polkadot 10 | polkadot-parachain* 11 | init.sh 12 | .yarn/* 13 | !.yarn/patches 14 | !.yarn/releases 15 | !.yarn/plugins 16 | !.yarn/sdks 17 | !.yarn/versions 18 | .pnp.* 19 | .turbo 20 | .vscode 21 | packages/connect/src/connector/specs/js 22 | substrate-connect_*-source-code.zip 23 | 24 | .tshy 25 | .tshy-build 26 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | COREPACK_INTEGRITY_KEYS=0 corepack pnpm lint-staged 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false 4 | } 5 | -------------------------------------------------------------------------------- /DEPLOY-RELEASE.md: -------------------------------------------------------------------------------- 1 | # Deploying docs and releasing substrate connect 2 | 3 | TODO: This is out of date. Update this to reflect the new release steps once we 4 | get to doing a release. 5 | 6 | ## Deploy Smoldot browser demo to Github Pages 7 | 8 | Before deploying make sure you have a clean working copy with no staged changes. 9 | The deploy script will deploy the last commit on your current branch. 10 | 11 | The deployment will build the smoldot browser demo into the dist folder and 12 | construct a commit containing just that folder with a message containing a 13 | reference to the SHA of the commit it came from and push that to the gh-pages 14 | branch. The dist folder remains ignored by git. 15 | 16 | You can deploy to Github pages like so: 17 | 18 | ```bash 19 | yarn deploy:gh-pages:smoldot-browser-demo 20 | ``` 21 | 22 | ## Deploy Smoldot browser demo to IPFS 23 | 24 | Before deploying make sure you have a Piñata API key and secret and that you 25 | have exported them in your shell environment: 26 | 27 | ```bash 28 | PINATA_API_KEY= 29 | PINATA_API_SECRET= 30 | ``` 31 | 32 | You can then deploy to IPFS like so: 33 | 34 | ```bash 35 | yarn deploy:ipfs:smoldot-browser-demo 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /examples/light-client-dapp/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "plugin:react-hooks/recommended", 8 | ], 9 | ignorePatterns: ["dist", ".eslintrc.cjs"], 10 | parser: "@typescript-eslint/parser", 11 | plugins: ["react-refresh"], 12 | rules: { 13 | "@typescript-eslint/no-unused-vars": [ 14 | "error", 15 | { 16 | args: "all", 17 | argsIgnorePattern: "^_", 18 | caughtErrors: "all", 19 | caughtErrorsIgnorePattern: "^_", 20 | destructuredArrayIgnorePattern: "^_", 21 | varsIgnorePattern: "^_", 22 | ignoreRestSiblings: true, 23 | }, 24 | ], 25 | "react-refresh/only-export-components": [ 26 | "warn", 27 | { allowConstantExport: true }, 28 | ], 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /examples/light-client-dapp/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/light-client-dapp/README.md: -------------------------------------------------------------------------------- 1 | # Light Client DApp Example 2 | 3 | This project is an example of a decentralized application (DApp) using Substrate Connect's light client. It demonstrates how to set up and integrate a light client into a React application using TypeScript and Vite. 4 | 5 | ## Technologies Used 6 | 7 | - **React**: A JavaScript library for building user interfaces. 8 | - **TypeScript**: A strongly typed programming language that builds on JavaScript. 9 | - **Vite**: A build tool that aims to provide a faster and leaner development experience for modern web projects. 10 | 11 | ## Installation 12 | 13 | To get started with the project, follow these steps: 14 | 15 | ```bash 16 | corepack pnpm i 17 | corepack pnpm turbo build 18 | ``` 19 | 20 | Then to run the project 21 | 22 | ```bash 23 | corepack pnpm dev 24 | ``` 25 | -------------------------------------------------------------------------------- /examples/light-client-dapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Light Client DApp 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/light-client-dapp/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/substrate-connect/7c2a06fbe39d78ec0afbd24d86b2c31ad9e43740/examples/light-client-dapp/public/.gitkeep -------------------------------------------------------------------------------- /examples/light-client-dapp/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Transfer, ConnectedAccount, ChainSelect } from "./components" 2 | import { ToastProvider } from "./components" 3 | import { UnstableProviderProvider } from "./hooks/useUnstableProvider" 4 | import { DEFAULT_CHAIN_ID } from "./settings" 5 | 6 | export const App = () => { 7 | return ( 8 | 9 | 10 |
11 |
12 |

Light Client DApp

13 |
14 | 15 | 16 | 17 |
18 |
19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/api/createTransaction.ts: -------------------------------------------------------------------------------- 1 | import type { SS58String } from "@polkadot-api/substrate-bindings" 2 | import { toHex } from "@polkadot-api/utils" 3 | import type { Unstable } from "@substrate/connect-discovery" 4 | import { ss58Decode } from "@polkadot-labs/hdkd-helpers" 5 | 6 | export const createTransaction = ( 7 | provider: Unstable.Provider, 8 | chainId: string, 9 | from: SS58String, 10 | callData: string, 11 | ) => provider.createTx(chainId, toHex(ss58Decode(from)[0]), callData) 12 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/api/getClient.ts: -------------------------------------------------------------------------------- 1 | import { createClient as createClient_ } from "polkadot-api" 2 | import { Unstable } from "@substrate/connect-discovery" 3 | 4 | export const getClient = (provider: Unstable.Provider, chainId: string) => { 5 | const chain = provider.getChains()[chainId] 6 | if (!chain) throw new Error("unknown chain") 7 | return createClient_(chain.connect) 8 | } 9 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/api/getObservableClient.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from "@polkadot-api/substrate-client" 2 | import { getObservableClient as getObservableClient_ } from "@polkadot-api/observable-client" 3 | import { Unstable } from "@substrate/connect-discovery" 4 | 5 | export const getObservableClient = ( 6 | provider: Unstable.Provider, 7 | chainId: string, 8 | ) => { 9 | const chain = provider.getChains()[chainId] 10 | if (!chain) throw new Error("unknown chain") 11 | return getObservableClient_(createClient(chain.connect)) 12 | } 13 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./createTransaction" 2 | export * from "./submitTransaction$" 3 | export * from "./transferAllowDeathCallData" 4 | export * from "./systemAccount$" 5 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/api/submitTransaction$.ts: -------------------------------------------------------------------------------- 1 | import { map } from "rxjs" 2 | import type { Unstable } from "@substrate/connect-discovery" 3 | import { getClient } from "./getClient" 4 | 5 | export const submitTransaction$ = ( 6 | provider: Unstable.Provider, 7 | chainId: string, 8 | tx: string, 9 | ) => 10 | getClient(provider, chainId) 11 | .submitAndWatch(tx) 12 | .pipe(map((txEvent) => ({ tx, txEvent }))) 13 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/substrate-connect/7c2a06fbe39d78ec0afbd24d86b2c31ad9e43740/examples/light-client-dapp/src/assets/.gitkeep -------------------------------------------------------------------------------- /examples/light-client-dapp/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ConnectedAccount" 2 | export * from "./Transfer" 3 | export * from "./ChainSelect" 4 | export * from "./Toast" 5 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./useSystemAccount" 2 | export * from "./useUnstableProvider" 3 | export * from "./useModal" 4 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/hooks/useChains.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | import { useIsMounted } from "./useIsMounted" 3 | import { Unstable } from "@substrate/connect-discovery" 4 | 5 | export const useChains = (provider?: Unstable.Provider) => { 6 | const [chains, setChains] = useState({}) 7 | const isMounted = useIsMounted() 8 | 9 | useEffect(() => { 10 | const chains = provider?.getChains() 11 | if (!isMounted()) return 12 | setChains(chains ?? {}) 13 | }, [provider, isMounted]) 14 | 15 | useEffect( 16 | () => 17 | provider?.addChainsChangeListener((chains) => { 18 | setChains(chains) 19 | }), 20 | [provider], 21 | ) 22 | 23 | return { chains } 24 | } 25 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/hooks/useIsMounted.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef } from "react" 2 | 3 | export const useIsMounted = () => { 4 | const isMounted = useRef(false) 5 | 6 | useEffect(() => { 7 | isMounted.current = true 8 | return () => { 9 | isMounted.current = false 10 | } 11 | }, []) 12 | 13 | return useCallback(() => isMounted.current, []) 14 | } 15 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/hooks/useSystemAccount.ts: -------------------------------------------------------------------------------- 1 | import useSWRSubscription from "swr/subscription" 2 | import { useUnstableProvider } from "./useUnstableProvider" 3 | import { systemAccount$ } from "../api" 4 | 5 | export type SystemAccountStorage = { 6 | consumers: number 7 | data: { 8 | flags: bigint 9 | free: bigint 10 | frozen: bigint 11 | reserved: bigint 12 | } 13 | nonce: number 14 | providers: number 15 | sufficients: number 16 | } 17 | 18 | export const useSystemAccount = () => { 19 | const { provider, chainId, account } = useUnstableProvider() 20 | const { data: systemAccount } = useSWRSubscription( 21 | provider && account 22 | ? ["systemAccount", provider, chainId, account.address] 23 | : null, 24 | ([_, provider, chainId, address], { next }) => { 25 | const subscription = systemAccount$(provider, chainId, address).subscribe( 26 | { 27 | next(systemAccount) { 28 | next(null, systemAccount) 29 | }, 30 | error: next, 31 | }, 32 | ) 33 | return () => subscription.unsubscribe() 34 | }, 35 | ) 36 | return systemAccount 37 | } 38 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/main.tsx: -------------------------------------------------------------------------------- 1 | import "@picocss/pico" 2 | import React from "react" 3 | import ReactDOM from "react-dom/client" 4 | import { App } from "./App" 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/settings.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_CHAIN_ID = 2 | "0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e" // westend 3 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/types.ts: -------------------------------------------------------------------------------- 1 | // import {} from "@substrate/light-client-extension-helpers" 2 | 3 | // // FIXME: use correct type from PolkadotProvider 4 | // export type Account = { 5 | // address: string 6 | // } 7 | 8 | // // FIXME: use correct type from PolkadotProvider 9 | // export type UnstableProvider = { 10 | // getAccounts: (chainId: string) => Promise 11 | // createTx: (chainId: string, from: string, callData: string) => Promise 12 | // } 13 | 14 | // // FIXME: use correct type from PolkadotProvider 15 | // // eslint-disable-next-line @typescript-eslint/ban-types 16 | // export type UnstableOnProvider = {} 17 | -------------------------------------------------------------------------------- /examples/light-client-dapp/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/light-client-dapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@total-typescript/tsconfig/bundler/dom/app", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "jsx": "preserve", 6 | "verbatimModuleSyntax": false, 7 | "paths": { 8 | "@/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["src"] 12 | } 13 | -------------------------------------------------------------------------------- /examples/light-client-dapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.node.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /examples/light-client-dapp/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "noEmit": true 11 | }, 12 | "include": ["vite.config.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /examples/light-client-dapp/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite" 2 | import react from "@vitejs/plugin-react-swc" 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "plugin:react-hooks/recommended", 8 | ], 9 | ignorePatterns: ["dist", ".eslintrc.cjs"], 10 | parser: "@typescript-eslint/parser", 11 | plugins: ["react-refresh"], 12 | rules: { 13 | "react-refresh/only-export-components": [ 14 | "warn", 15 | { allowConstantExport: true }, 16 | ], 17 | "no-extra-semi": 0, 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | extension-dapp 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "light-client-extension-helpers-dapp", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc --noEmit && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@picocss/pico": "^2.0.6", 14 | "@polkadot-api/observable-client": "~0.8.6", 15 | "@polkadot-api/substrate-client": "~0.3.0", 16 | "@substrate/connect-known-chains": "workspace:*", 17 | "@substrate/light-client-extension-helpers": "workspace:*", 18 | "react": "^18.3.1", 19 | "react-dom": "^18.2.0", 20 | "rxjs": "^7.8.1" 21 | }, 22 | "devDependencies": { 23 | "typescript": "5.6.2", 24 | "@types/react": "^18.3.1", 25 | "@types/react-dom": "^18.3.1", 26 | "@typescript-eslint/eslint-plugin": "^8.29.1", 27 | "@typescript-eslint/parser": "^7.11.0", 28 | "@vitejs/plugin-react-swc": "^3.7.2", 29 | "eslint": "^8.57.0", 30 | "eslint-plugin-react-hooks": "^5.0.0", 31 | "eslint-plugin-react-refresh": "^0.4.18", 32 | "vite": "^6.1.6", 33 | "vitest": "^2.1.9" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Chains } from "./containers/Chains" 2 | import { useLightClientProvider } from "./hooks/useProvider" 3 | 4 | function App() { 5 | const { provider } = useLightClientProvider("extension-unique-id") 6 | if (!provider) return null 7 | 8 | return 9 | } 10 | 11 | export default App 12 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/components/Chain.tsx: -------------------------------------------------------------------------------- 1 | import { type RawChain } from "@substrate/light-client-extension-helpers/web-page" 2 | import { FC } from "react" 3 | import { useChain } from "../hooks/useChain" 4 | 5 | type Props = { 6 | chain: RawChain 7 | } 8 | 9 | export const Chain: FC = ({ chain }) => { 10 | const { finalized, blockHeight } = useChain(chain) 11 | return ( 12 |
13 |
{chain.name}
14 | {finalized && blockHeight ? ( 15 | <> 16 |
17 | Latest Finalized Block{" "} 18 | 19 | {formatNumber(blockHeight)} 20 | 21 |
22 |
{finalized}
23 | 24 | ) : ( 25 | synchronizing, please wait... 26 | )} 27 |
28 | ) 29 | } 30 | 31 | const numberFormat = new Intl.NumberFormat() 32 | const formatNumber = (number: number) => numberFormat.format(number) 33 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/hooks/useChain.ts: -------------------------------------------------------------------------------- 1 | import { getObservableClient } from "@polkadot-api/observable-client" 2 | import type { RawChain } from "@substrate/light-client-extension-helpers/web-page" 3 | import { createClient } from "@polkadot-api/substrate-client" 4 | import { useEffect, useState } from "react" 5 | 6 | export const useChain = (chain: RawChain) => { 7 | const [state, setState] = useState<{ 8 | finalized?: string 9 | blockHeight?: number 10 | }>({}) 11 | 12 | useEffect(() => { 13 | const client = getObservableClient(createClient(chain.connect)) 14 | const { unfollow, finalized$ } = client.chainHead$() 15 | const subscription = finalized$.subscribe(({ hash, number }) => 16 | setState({ 17 | finalized: hash, 18 | blockHeight: number, 19 | }), 20 | ) 21 | 22 | return () => { 23 | subscription.unsubscribe() 24 | unfollow() 25 | client.destroy() 26 | } 27 | }, [chain.connect]) 28 | 29 | return state 30 | } 31 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/hooks/useChains.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | RawChain, 3 | LightClientProvider, 4 | } from "@substrate/light-client-extension-helpers/web-page" 5 | import { useEffect, useState } from "react" 6 | import { useIsMounted } from "./useIsMounted" 7 | 8 | export const useChains = (provider: LightClientProvider) => { 9 | const [chains, setChains] = useState>({}) 10 | const isMounted = useIsMounted() 11 | 12 | useEffect(() => { 13 | ;(async () => { 14 | const chains = await provider.getChains() 15 | if (!isMounted()) return 16 | setChains(chains) 17 | })() 18 | }, [provider, isMounted]) 19 | 20 | useEffect( 21 | () => provider.addChainsChangeListener((chains) => setChains(chains)), 22 | [provider], 23 | ) 24 | 25 | return { chains } 26 | } 27 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/hooks/useIsMounted.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef } from "react" 2 | 3 | export const useIsMounted = () => { 4 | const isMounted = useRef(false) 5 | 6 | useEffect(() => { 7 | isMounted.current = true 8 | return () => { 9 | isMounted.current = false 10 | } 11 | }, []) 12 | 13 | return useCallback(() => isMounted.current, []) 14 | } 15 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/hooks/useProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type LightClientProvider, 3 | getLightClientProvider, 4 | } from "@substrate/light-client-extension-helpers/web-page" 5 | import { useEffect, useState } from "react" 6 | import { useIsMounted } from "./useIsMounted" 7 | 8 | const providers = new Map>() 9 | 10 | export const useLightClientProvider = (channelId: string) => { 11 | const [provider, setProvider] = useState() 12 | const isMounted = useIsMounted() 13 | 14 | useEffect(() => { 15 | if (!providers.has(channelId)) 16 | providers.set(channelId, getLightClientProvider(channelId)) 17 | providers.get(channelId)?.then((provider) => { 18 | if (!isMounted()) return 19 | setProvider(provider) 20 | }) 21 | }, [channelId, isMounted]) 22 | 23 | return { provider } 24 | } 25 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/main.tsx: -------------------------------------------------------------------------------- 1 | import "@picocss/pico" 2 | import React from "react" 3 | import ReactDOM from "react-dom/client" 4 | import App from "./App.tsx" 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@total-typescript/tsconfig/bundler/dom/app", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "jsx": "preserve", 6 | "verbatimModuleSyntax": false, 7 | "paths": { 8 | "@/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["src"] 12 | } 13 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.node.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "noEmit": true 11 | }, 12 | "include": ["vite.config.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-dapp/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite" 2 | import react from "@vitejs/plugin-react-swc" 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | build: { 8 | target: "esnext", 9 | }, 10 | }) 11 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /test-results/ 3 | /playwright-report/ 4 | /blob-report/ 5 | /playwright/.cache/ 6 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Test Extension", 4 | "version": "0.0.1", 5 | "description": "Test Extension for @substrate/light-client-extension-helpers", 6 | "permissions": ["storage", "alarms", "tabs", "unlimitedStorage"], 7 | "background": { 8 | "service_worker": "js/background/background.mjs", 9 | "type": "module" 10 | }, 11 | "content_scripts": [ 12 | { 13 | "js": ["js/content.global.js"], 14 | "matches": ["http://*/*", "https://*/*"], 15 | "run_at": "document_start" 16 | } 17 | ], 18 | "options_page": "options.html", 19 | "web_accessible_resources": [ 20 | { 21 | "resources": ["js/inpage.global.js"], 22 | "matches": [""] 23 | } 24 | ], 25 | "content_security_policy": { 26 | "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/assets/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/src/background.ts: -------------------------------------------------------------------------------- 1 | import { register } from "@substrate/light-client-extension-helpers/background" 2 | import { wellKnownChainSpecs } from "@substrate/light-client-extension-helpers/known-chain-specs" 3 | import type { ToContent } from "./protocol" 4 | import { smoldotClient } from "./background-smoldot.code-split" 5 | 6 | const { lightClientPageHelper, addOnAddChainByUserListener } = register({ 7 | smoldotClient, 8 | getWellKnownChainSpecs: async () => 9 | Object.fromEntries( 10 | Object.entries(wellKnownChainSpecs) 11 | // FIXME: remove filter once https://github.com/smol-dot/smoldot/issues/1691 is fixed 12 | .filter( 13 | ([genesisHash]) => 14 | genesisHash !== 15 | "0x6408de7737c59c238890533af25896a2c20608d8b380bb01029acb392781063e", 16 | ), 17 | ), 18 | }) 19 | 20 | addOnAddChainByUserListener(async (inputChain, tabId) => { 21 | if ( 22 | !(await chrome.tabs.sendMessage(tabId, { 23 | origin: "my-extension-background", 24 | type: "onAddChainByUser", 25 | inputChain, 26 | } as ToContent)) 27 | ) 28 | throw new Error("addChainByUser rejected") 29 | 30 | await lightClientPageHelper.persistChain( 31 | inputChain.chainSpec, 32 | inputChain.relayChainGenesisHash, 33 | ) 34 | }) 35 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/src/content.ts: -------------------------------------------------------------------------------- 1 | import { register } from "@substrate/light-client-extension-helpers/content-script" 2 | import type { ToContent } from "./protocol" 3 | 4 | register("extension-unique-id") 5 | 6 | // TODO: inpage script might not be needed 7 | try { 8 | const s = document.createElement("script") 9 | s.type = "module" 10 | s.src = chrome.runtime.getURL("js/inpage.global.js") 11 | s.onload = function () { 12 | // @ts-ignore 13 | this.remove() 14 | } 15 | ;(document.head || document.documentElement).appendChild(s) 16 | } catch (error) { 17 | console.error("error injecting js/inpage.global.js", error) 18 | } 19 | 20 | chrome.runtime.onMessage.addListener((msg: ToContent, sender, sendResponse) => { 21 | if ( 22 | !sender.tab && 23 | msg.origin === "my-extension-background" && 24 | msg.type === "onAddChainByUser" 25 | ) { 26 | sendResponse(confirm(`Confirm addChain ${JSON.stringify(msg.inputChain)}?`)) 27 | } 28 | }) 29 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/src/inpage.ts: -------------------------------------------------------------------------------- 1 | // TODO: check if this injected script is needed 2 | console.log("inpage") 3 | 4 | // @ts-ignore 5 | globalThis.extensionApi = { version: "0.0.1" } 6 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/src/protocol.ts: -------------------------------------------------------------------------------- 1 | import type { InputChain } from "@substrate/light-client-extension-helpers/background" 2 | 3 | export type ToContent = { 4 | origin: "my-extension-background" 5 | type: "onAddChainByUser" 6 | inputChain: InputChain 7 | } 8 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/tests/dapp.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "./fixtures" 2 | 3 | test("sanity", async ({ page }) => { 4 | test.setTimeout(5 * 60 * 1000) 5 | await page.goto("/") 6 | 7 | await expect(page).toHaveTitle(/extension-dapp/) 8 | await expect(page.locator("h1")).toHaveText("Extension Test DApp", { 9 | timeout: 60_000, 10 | }) 11 | 12 | for (const chainName of ["Polkadot", "Kusama", "Westend"]) { 13 | const chain = page.getByTestId(`chain${chainName}`) 14 | await expect(chain).toBeVisible() 15 | const blockHeight = chain.getByTestId("blockHeight") 16 | expect( 17 | +(await blockHeight.getAttribute("data-blockheight", { 18 | timeout: 3 * 60 * 1000, 19 | }))!, 20 | ).toBeGreaterThan(0) 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/tests/fixtures.ts: -------------------------------------------------------------------------------- 1 | import { test as base, chromium, type BrowserContext } from "@playwright/test" 2 | import path from "path" 3 | 4 | export const test = base.extend<{ 5 | context: BrowserContext 6 | extensionId: string 7 | }>({ 8 | context: async ({}, use) => { 9 | const pathToExtension = path.join(__dirname, "../dist") 10 | const context = await chromium.launchPersistentContext("", { 11 | headless: false, 12 | args: [ 13 | ...(!!process.env.CI ? [`--headless=new`] : []), 14 | `--disable-extensions-except=${pathToExtension}`, 15 | `--load-extension=${pathToExtension}`, 16 | ], 17 | }) 18 | await use(context) 19 | await context.close() 20 | }, 21 | extensionId: async ({ context }, use) => { 22 | /* 23 | // for manifest v2: 24 | let [background] = context.backgroundPages() 25 | if (!background) 26 | background = await context.waitForEvent('backgroundpage') 27 | */ 28 | 29 | // for manifest v3: 30 | let [background] = context.serviceWorkers() 31 | if (!background) background = await context.waitForEvent("serviceworker") 32 | 33 | const extensionId = background.url().split("/")[2]! 34 | await use(extensionId) 35 | }, 36 | }) 37 | export const expect = test.expect 38 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@total-typescript/tsconfig/bundler/dom/app", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "jsx": "preserve", 6 | "verbatimModuleSyntax": false, 7 | "paths": { 8 | "@/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["src", "tests"] 12 | } 13 | -------------------------------------------------------------------------------- /examples/light-client-extension-helpers-extension/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup" 2 | 3 | export default defineConfig({ 4 | noExternal: [/(.*)/], 5 | }) 6 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/.eslintignore: -------------------------------------------------------------------------------- 1 | src/components/ui 2 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "plugin:react-hooks/recommended", 8 | ], 9 | ignorePatterns: ["dist", ".eslintrc.cjs"], 10 | parser: "@typescript-eslint/parser", 11 | plugins: ["react-refresh"], 12 | rules: { 13 | "@typescript-eslint/no-unused-vars": [ 14 | "error", 15 | { 16 | args: "all", 17 | argsIgnorePattern: "^_", 18 | caughtErrors: "all", 19 | caughtErrorsIgnorePattern: "^_", 20 | destructuredArrayIgnorePattern: "^_", 21 | varsIgnorePattern: "^_", 22 | ignoreRestSiblings: true, 23 | }, 24 | ], 25 | "react-refresh/only-export-components": [ 26 | "warn", 27 | { allowConstantExport: true }, 28 | ], 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/README.md: -------------------------------------------------------------------------------- 1 | # Smoldot Discovery Example 2 | 3 | This is an example dapp to test your @substrate/smoldot-discovery compatible extension. 4 | Simply run the dapp with `pnpm dev` and if your extension shows up in the list, your extension is compatible. 5 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/global.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @substrate/smoldot-discovery Example 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 2 | 3 | const AspectRatio = AspectRatioPrimitive.Root 4 | 5 | export { AspectRatio } 6 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const badgeVariants = cva( 7 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", 13 | secondary: 14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 15 | destructive: 16 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", 17 | outline: "text-foreground", 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: "default", 22 | }, 23 | }, 24 | ) 25 | 26 | export interface BadgeProps 27 | extends React.HTMLAttributes, 28 | VariantProps {} 29 | 30 | function Badge({ className, variant, ...props }: BadgeProps) { 31 | return ( 32 |
33 | ) 34 | } 35 | 36 | export { Badge, badgeVariants } 37 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/checkbox.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox" 3 | import { Check } from "lucide-react" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const Checkbox = React.forwardRef< 8 | React.ElementRef, 9 | React.ComponentPropsWithoutRef 10 | >(({ className, ...props }, ref) => ( 11 | 19 | 22 | 23 | 24 | 25 | )) 26 | Checkbox.displayName = CheckboxPrimitive.Root.displayName 27 | 28 | export { Checkbox } 29 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 2 | 3 | const Collapsible = CollapsiblePrimitive.Root 4 | 5 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger 6 | 7 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent 8 | 9 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 10 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/hover-card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as HoverCardPrimitive from "@radix-ui/react-hover-card" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const HoverCard = HoverCardPrimitive.Root 7 | 8 | const HoverCardTrigger = HoverCardPrimitive.Trigger 9 | 10 | const HoverCardContent = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 14 | 24 | )) 25 | HoverCardContent.displayName = HoverCardPrimitive.Content.displayName 26 | 27 | export { HoverCard, HoverCardTrigger, HoverCardContent } 28 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | }, 22 | ) 23 | Input.displayName = "Input" 24 | 25 | export { Input } 26 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as LabelPrimitive from "@radix-ui/react-label" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const labelVariants = cva( 8 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", 9 | ) 10 | 11 | const Label = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | 21 | )) 22 | Label.displayName = LabelPrimitive.Root.displayName 23 | 24 | export { Label } 25 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/progress.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as ProgressPrimitive from "@radix-ui/react-progress" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Progress = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, value, ...props }, ref) => ( 10 | 18 | 22 | 23 | )) 24 | Progress.displayName = ProgressPrimitive.Root.displayName 25 | 26 | export { Progress } 27 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as SeparatorPrimitive from "@radix-ui/react-separator" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Separator = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >( 10 | ( 11 | { className, orientation = "horizontal", decorative = true, ...props }, 12 | ref, 13 | ) => ( 14 | 25 | ), 26 | ) 27 | Separator.displayName = SeparatorPrimitive.Root.displayName 28 | 29 | export { Separator } 30 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/slider.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as SliderPrimitive from "@radix-ui/react-slider" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Slider = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => ( 10 | 18 | 19 | 20 | 21 | 22 | 23 | )) 24 | Slider.displayName = SliderPrimitive.Root.displayName 25 | 26 | export { Slider } 27 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | import { useTheme } from "next-themes" 2 | import { Toaster as Sonner } from "sonner" 3 | 4 | type ToasterProps = React.ComponentProps 5 | 6 | const Toaster = ({ ...props }: ToasterProps) => { 7 | const { theme = "system" } = useTheme() 8 | 9 | return ( 10 | 26 | ) 27 | } 28 | 29 | export { Toaster } 30 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/switch.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as SwitchPrimitives from "@radix-ui/react-switch" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Switch = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => ( 10 | 18 | 23 | 24 | )) 25 | Switch.displayName = SwitchPrimitives.Root.displayName 26 | 27 | export { Switch } 28 | -------------------------------------------------------------------------------- /examples/smoldot-discovery-example/src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |