From dca05101ecb5b9164193314512a9ce3bf97236bd Mon Sep 17 00:00:00 2001 From: Nejc Drobnic Date: Sat, 4 Apr 2026 14:02:51 +0200 Subject: [PATCH 1/4] chore: clean up completed plans, fix license copyright, update READMEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove 6 completed plan files (testing, CI, modernization, readme-examples, integration-testing, bitbit-wallet-standard). Update roadmap to reflect implemented milestones. Set LICENSE copyright to 2026 Nejc Drobnič. Update all package READMEs to match current codebase: rename satsConnect to xverse, add walletStandard connector docs, add missing token hooks/actions, fix config API (network not networks), add @mbga/kit README. Co-Authored-By: Claude Opus 4.6 (1M context) --- LICENSE | 2 +- README.md | 7 +- packages/connectors/README.md | 27 +++- packages/core/README.md | 18 +++ packages/kit/README.md | 108 +++++++++++++ packages/react/README.md | 20 ++- plans/README.md | 10 +- plans/bitbit-wallet-standard-support.md | 118 -------------- plans/ci-github-actions.md | 205 ----------------------- plans/integration-testing.md | 206 ------------------------ plans/modernization.md | 165 ------------------- plans/readme-and-examples.md | 193 ---------------------- plans/roadmap.md | 50 +++--- plans/testing-plan.md | 107 ------------ 14 files changed, 198 insertions(+), 1038 deletions(-) create mode 100644 packages/kit/README.md delete mode 100644 plans/bitbit-wallet-standard-support.md delete mode 100644 plans/ci-github-actions.md delete mode 100644 plans/integration-testing.md delete mode 100644 plans/modernization.md delete mode 100644 plans/readme-and-examples.md delete mode 100644 plans/testing-plan.md diff --git a/LICENSE b/LICENSE index 261eeb9..9e0c8c3 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2026 Nejc Drobnič Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 93767e3..f112e68 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,11 @@ pnpm add mbga @mbga/connectors @tanstack/react-query ```ts import { createConfig, sparkMainnet } from 'mbga' -import { satsConnect } from 'mbga/connectors' +import { xverse } from 'mbga/connectors' export const config = createConfig({ - networks: [sparkMainnet], - connectors: [satsConnect()], + network: sparkMainnet, + connectors: [xverse()], }) ``` @@ -92,6 +92,7 @@ pnpm create mbga | [`mbga`](./packages/react) | React Hooks for Spark | | [`@mbga/core`](./packages/core) | VanillaJS library for Spark | | [`@mbga/connectors`](./packages/connectors) | Collection of wallet connectors for MBGA | +| [`@mbga/kit`](./packages/kit) | Pre-built React UI components for wallet connection | | [`@mbga/test`](./packages/test) | Test utilities for MBGA | | [`@mbga/flashnet`](./packages/flashnet) | Flashnet authentication and orchestration | | [`create-mbga`](./packages/create-mbga) | Scaffold a new MBGA project | diff --git a/packages/connectors/README.md b/packages/connectors/README.md index ab34875..c6ebeea 100644 --- a/packages/connectors/README.md +++ b/packages/connectors/README.md @@ -14,23 +14,26 @@ Each connector has its own peer dependency -- install only what you need: | Connector | Peer dependency | Install | |-----------|----------------|---------| -| `satsConnect` | `sats-connect` | `npm install sats-connect` | +| `xverse` | `sats-connect` | `npm install sats-connect` | | `sparkSdk` | `@buildonspark/spark-sdk` | `npm install @buildonspark/spark-sdk` | +| `walletStandard` | `@wallet-standard/core` | `npm install @wallet-standard/core` | ## Connectors -### `satsConnect` +### `xverse` Connects to Xverse and other wallets that implement the [sats-connect](https://docs.xverse.app/sats-connect) protocol. This is the primary connector for browser-based wallet interactions. +> **Note:** The previous `satsConnect` export is a deprecated alias for `xverse`. + ```ts -import { satsConnect } from '@mbga/connectors' +import { xverse } from '@mbga/connectors' import { createConfig, sparkMainnet } from '@mbga/core' const config = createConfig({ network: sparkMainnet, connectors: [ - satsConnect(), + xverse(), ], }) ``` @@ -53,6 +56,22 @@ const config = createConfig({ }) ``` +### `walletStandard` + +Connects to any wallet that implements the [Wallet Standard](https://github.com/wallet-standard/wallet-standard) with `spark:*` features. Automatically discovers compatible wallets at runtime. + +```ts +import { walletStandard } from '@mbga/connectors' +import { createConfig, sparkMainnet } from '@mbga/core' + +const config = createConfig({ + network: sparkMainnet, + connectors: [ + walletStandard(), + ], +}) +``` + ## Custom Connectors You can create custom connectors using `createConnector` from `@mbga/core`: diff --git a/packages/core/README.md b/packages/core/README.md index d033633..322b36d 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -84,6 +84,20 @@ const config = createConfig({ | `estimateFee` | Estimate the fee for a payment | | `signMessage` | Sign a message with BIP-322 | +### Tokens + +| Action | Description | +|--------|-------------| +| `getTokenBalance` | Get a token balance | +| `sendToken` | Send a token transfer | + +### Wallet (continued) + +| Action | Description | +|--------|-------------| +| `getTransactions` | List transaction history | +| `switchConnection` | Switch the active connection | + ### Watchers | Action | Description | @@ -109,6 +123,8 @@ import { ... } from '@mbga/core/internal' | `detectPaymentDestination` | Detect if a string is a Lightning invoice, Bitcoin address, or Spark address | | `serialize` / `deserialize` | JSON serialization helpers | | `deepEqual` | Deep equality comparison | +| `formatSats` / `parseSats` | Satoshi formatting and parsing | +| `formatTokenAmount` / `parseTokenAmount` | Token amount formatting with decimal support | ## Related Packages @@ -116,6 +132,8 @@ import { ... } from '@mbga/core/internal' |---------|-------------| | [`mbga`](../react) | React hooks wrapping this library | | [`@mbga/connectors`](../connectors) | Wallet connector implementations | +| [`@mbga/kit`](../kit) | Pre-built React UI components for wallet connection | +| [`@mbga/flashnet`](../flashnet) | Flashnet authentication and orchestration | | [`create-mbga`](../create-mbga) | CLI to scaffold a new MBGA project | ## License diff --git a/packages/kit/README.md b/packages/kit/README.md new file mode 100644 index 0000000..70cce93 --- /dev/null +++ b/packages/kit/README.md @@ -0,0 +1,108 @@ +# @mbga/kit + +Pre-built React UI components for connecting [Spark](https://www.spark.info/) wallets. Drop-in ConnectButton, wallet selection modal, and account management -- styled or headless. + +## Installation + +```bash +npm install @mbga/kit +pnpm add @mbga/kit +yarn add @mbga/kit +``` + +Peer dependencies: `react`, `react-dom`, `@tanstack/react-query`. + +## Quick Start + +```tsx +import { KitProvider, ConnectButton } from '@mbga/kit' +import { createConfig, sparkMainnet } from '@mbga/core' +import { xverse } from '@mbga/connectors' + +const config = createConfig({ + network: sparkMainnet, + connectors: [xverse()], +}) + +function App() { + return ( + + + + ) +} +``` + +`KitProvider` wraps `MbgaProvider` and `QueryClientProvider` internally -- no extra setup needed. + +## Components + +### Styled + +| Component | Description | +|-----------|-------------| +| `KitProvider` | Context provider (config, theming, modal state) | +| `ConnectButton` | Connect/disconnect button with connected state display | +| `ConnectModal` | Modal with wallet list for selecting a connector | +| `AccountModal` | Connected account info (address, balance, disconnect) | + +### Headless + +Unstyled variants that expose render props for full customization: + +```tsx +import { ConnectButtonHeadless } from '@mbga/kit' + + + {({ isConnected, address, connect, disconnect }) => ( + // your custom UI + )} + +``` + +| Component | Description | +|-----------|-------------| +| `ConnectButtonHeadless` | Render-prop connect/disconnect button | +| `ConnectModalHeadless` | Render-prop wallet selection modal | +| `AccountModalHeadless` | Render-prop account info | +| `Modal` | Generic modal primitive (overlay, open/close) | + +Headless components are also available via the `@mbga/kit/headless` sub-path export. + +## Theming + +Built-in light and dark themes, customizable via CSS variables: + +```tsx +import { KitProvider, darkTheme } from '@mbga/kit' + + + + +``` + +| Export | Description | +|--------|-------------| +| `lightTheme` | Default light theme | +| `darkTheme` | Dark theme | +| `resolveTheme` | Merge a partial theme with defaults | +| `themeToStyleVars` | Convert a theme object to CSS custom properties | + +## Utilities + +| Export | Description | +|--------|-------------| +| `truncateAddress` | Shorten an address for display | +| `copyToClipboard` | Copy text to clipboard | + +## Related Packages + +| Package | Description | +|---------|-------------| +| [`mbga`](../react) | React hooks for Spark | +| [`@mbga/core`](../core) | Framework-agnostic core library | +| [`@mbga/connectors`](../connectors) | Wallet connector implementations | + +## License + +Apache-2.0 diff --git a/packages/react/README.md b/packages/react/README.md index afff2ce..818e828 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -7,9 +7,9 @@ Powered by [TanStack Query](https://tanstack.com/query) for caching, deduplicati ## Installation ```bash -npm install mbga @mbga/connectors sats-connect @tanstack/react-query -pnpm add mbga @mbga/connectors sats-connect @tanstack/react-query -yarn add mbga @mbga/connectors sats-connect @tanstack/react-query +npm install mbga @mbga/connectors @tanstack/react-query +pnpm add mbga @mbga/connectors @tanstack/react-query +yarn add mbga @mbga/connectors @tanstack/react-query ``` ## Quick Start @@ -18,12 +18,12 @@ yarn add mbga @mbga/connectors sats-connect @tanstack/react-query ```ts // src/mbga.ts -import { satsConnect } from 'mbga/connectors' +import { xverse } from 'mbga/connectors' import { createConfig, sparkMainnet } from 'mbga' export const config = createConfig({ network: sparkMainnet, - connectors: [satsConnect()], + connectors: [xverse()], }) ``` @@ -98,6 +98,14 @@ function Wallet() { | `useEstimateFee` | Estimate the fee for a payment | | `useSignMessage` | Sign a message with BIP-322 | +### Tokens + +| Hook | Description | +|------|-------------| +| `useTokenList` | Fetch the token registry | +| `useTokenBalance` | Query a token balance | +| `useSendToken` | Send a token transfer | + ## Sub-path Exports ```ts @@ -128,6 +136,8 @@ The provider handles hydration automatically -- no extra setup needed. |---------|-------------| | [`@mbga/core`](../core) | Framework-agnostic core (use this for non-React apps) | | [`@mbga/connectors`](../connectors) | Wallet connector implementations | +| [`@mbga/kit`](../kit) | Pre-built React UI components for wallet connection | +| [`@mbga/flashnet`](../flashnet) | Flashnet authentication and orchestration | | [`create-mbga`](../create-mbga) | CLI to scaffold a new MBGA project | ## License diff --git a/plans/README.md b/plans/README.md index 985644a..9ed07db 100644 --- a/plans/README.md +++ b/plans/README.md @@ -4,14 +4,12 @@ This directory contains detailed plans, TODOs, and roadmaps for the MBGA project ## Contents +- [todos.md](./todos.md) - Actionable TODO list - [roadmap.md](./roadmap.md) - Feature roadmap and milestones - [wallet-connectors.md](./wallet-connectors.md) - Planned wallet connector integrations -- [testing-plan.md](./testing-plan.md) - Comprehensive testing strategy -- [integration-testing.md](./integration-testing.md) - How to test wallet connectors are working -- [ci-github-actions.md](./ci-github-actions.md) - GitHub Actions CI with Blacksmith runners & Codecov -- [readme-and-examples.md](./readme-and-examples.md) - README structure and usage examples -- [modernization.md](./modernization.md) - Modernization plan for the WAGMI-derived codebase -- [todos.md](./todos.md) - Actionable TODO list +- [considerations.md](./considerations.md) - Future considerations and potential pitfalls +- [ui/](./ui/) - `@mbga/kit` UI component plans +- [flashnet-orchestra/](./flashnet-orchestra/) - Flashnet AMM & Orchestra plugin research ## Versioning & Releases diff --git a/plans/bitbit-wallet-standard-support.md b/plans/bitbit-wallet-standard-support.md deleted file mode 100644 index a6b4800..0000000 --- a/plans/bitbit-wallet-standard-support.md +++ /dev/null @@ -1,118 +0,0 @@ -# Plan: Add BitBit Wallet-Standard Connector - -## Context - -MBGA needs to support the BitBit browser extension wallet, which implements the `@wallet-standard/core` spec with features under the `spark:*` namespace. This adds a third connector alongside `satsConnect` (Xverse) and `sparkSdk` (programmatic SDK). - -## Files to Create - -### 1. `packages/connectors/src/bitbit.ts` — Connector implementation - -Follow the `satsConnect.ts` pattern exactly: - -- **Static type**: `bitbit.type = 'bitbit' as const` -- **Parameters**: `BitBitParameters = { network?: string }` (defaults to `'mainnet'`) -- **Provider type**: `Wallet` from `@wallet-standard/core` -- **Internal state**: `walletInstance: Wallet | undefined`, `connectedAccount: string | undefined` -- **Factory**: `createConnector((config) => ({...}))` - -**Connector properties:** -- `id: 'bitbit'`, `name: 'BitBit'`, `type: bitbit.type` - -**Methods to implement:** - -| Method | Maps to | Notes | -|--------|---------|-------| -| `setup()` | no-op | Matching satsConnect pattern | -| `connect()` | `spark:connect` | Lazy-import `@wallet-standard/core`, call `getWallets().get()`, find wallet with `spark:connect` feature, call `connect({ network })`, extract addresses, cache first account, emit `connect` event | -| `disconnect()` | `spark:disconnect` | Call feature if wallet exists, clear state, emit `disconnect` | -| `getAccounts()` | cached state | Return `[connectedAccount]` or `[]` | -| `getProvider()` | wallet discovery | Return `walletInstance`, attempt discovery if not cached, throw if not found | -| `isAuthorized()` | `getAccounts()` | `accounts.length > 0`, catch returns false | -| `getBalance()` | `spark:getBalance` | Call `getBalance()`, extract BTC sats, return `{ value: bigint, formatted, symbol: 'BTC' }` | -| `sendPayment()` | `spark:transferBitcoin` | Require `amount`, call `transferBitcoin({ account, recipient, amount: string(sats) })`, return `{ id }` | -| `signMessage()` | `spark:signMessage` | Call `signMessage({ account, message })`, return `{ signature }` | -| `onAccountsChanged()` | emitter | Emit `change` or `disconnect` if empty | -| `onDisconnect()` | emitter | Clear state, emit `disconnect` | - -**Methods NOT implemented** (BitBit doesn't expose these): -- `createInvoice`, `waitForPayment`, `getTransaction`, `estimateFee` - -**Key design decisions:** -- Feature access uses type assertions (wallet-standard features are `Record`) -- `connectedAccount` cached because BitBit's `spark:*` features require `account` param -- `sendPayment` only maps to `spark:transferBitcoin` — BitBit does not expose separate Lightning/on-chain features -- `spark:transferBitcoin` takes `amount` as a string (sats) per the BitBit API docs - -### 2. `packages/connectors/src/bitbit.test.ts` — Tests - -Mock `@wallet-standard/core` using `vi.mock()` (same pattern as satsConnect mocking `sats-connect`): - -```typescript -const mockConnect = vi.fn() -const mockDisconnect = vi.fn() -const mockGetBalance = vi.fn() -const mockTransferBitcoin = vi.fn() -const mockSignMessage = vi.fn() - -const mockWallet = { - features: { - 'spark:connect': { connect: mockConnect }, - 'spark:disconnect': { disconnect: mockDisconnect }, - 'spark:getBalance': { getBalance: mockGetBalance }, - 'spark:transferBitcoin': { transferBitcoin: mockTransferBitcoin }, - 'spark:signMessage': { signMessage: mockSignMessage }, - }, -} - -vi.mock('@wallet-standard/core', () => ({ - getWallets: () => ({ get: () => [mockWallet] }), -})) -``` - -**Test sections** (mirror satsConnect.test.ts): -- `metadata` — id, name, type, static .type -- `setup` — resolves without error -- `connect` — returns accounts, emits event, throws when wallet not found, throws on rejection, handles empty addresses -- `disconnect` — calls spark:disconnect, emits event, works without prior connect, clears state -- `getAccounts` — returns cached account, empty when not connected -- `getProvider` — returns wallet, throws when not found -- `isAuthorized` — true when connected, false when not -- `getBalance` — returns formatted balance, throws when not connected, handles zero -- `sendPayment` — calls spark:transferBitcoin, throws when amount missing, throws when not connected -- `signMessage` — calls spark:signMessage, throws when not connected -- `event handlers` — onAccountsChanged, onDisconnect - -## Files to Modify - -### 3. `packages/connectors/src/exports/index.ts` — Add barrel export - -Add: -```typescript -export { - type BitBitParameters, - bitbit, -} from '../bitbit.js' -``` - -### 4. `packages/connectors/package.json` — Add dependency - -- `peerDependencies`: `"@wallet-standard/core": ">=1.0.0"` -- `peerDependenciesMeta`: `"@wallet-standard/core": { "optional": true }` -- `devDependencies`: `"@wallet-standard/core": "^1.1.0"` (install via pnpm) -- `keywords`: add `"bitbit"`, `"wallet-standard"` - -## Implementation Order - -1. Install `@wallet-standard/core` in `packages/connectors` -2. Create `bitbit.ts` -3. Create `bitbit.test.ts` -4. Update `exports/index.ts` -5. Verify: `pnpm check:types`, `pnpm test`, `pnpm build` - -## Verification - -- `pnpm test` — all bitbit tests pass, existing tests unaffected -- `pnpm check:types` — no type errors -- `pnpm check` — biome lint/format passes -- `pnpm build` — builds successfully, `bitbit` exported from dist diff --git a/plans/ci-github-actions.md b/plans/ci-github-actions.md deleted file mode 100644 index 530fc48..0000000 --- a/plans/ci-github-actions.md +++ /dev/null @@ -1,205 +0,0 @@ -# CI/CD Plan: GitHub Actions with Blacksmith Runners & Codecov - -## Overview - -Use [Blacksmith](https://blacksmith.sh) runners for faster CI (bare-metal ARM64 runners) -and [Codecov](https://codecov.io) for coverage tracking. - -## Workflow: `.github/workflows/ci.yml` - -```yaml -name: CI - -on: - push: - branches: [main] - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - lint: - name: Lint & Format - runs-on: blacksmith-2vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v4 - - - uses: useblacksmith/setup-node@v5 - with: - node-version: 22 - cache: pnpm - - - run: pnpm install --frozen-lockfile - - - name: Biome check - run: pnpm check - - typecheck: - name: Type Check - runs-on: blacksmith-2vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v4 - - - uses: useblacksmith/setup-node@v5 - with: - node-version: 22 - cache: pnpm - - - run: pnpm install --frozen-lockfile - - - name: TypeScript check - run: pnpm check:types - - test: - name: Test - runs-on: blacksmith-2vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v4 - - - uses: useblacksmith/setup-node@v5 - with: - node-version: 22 - cache: pnpm - - - run: pnpm install --frozen-lockfile - - - name: Run tests with coverage - run: pnpm test -- --run --coverage - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage/lcov.info - flags: unittests - fail_ci_if_error: false - - build: - name: Build - runs-on: blacksmith-2vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v4 - - - uses: useblacksmith/setup-node@v5 - with: - node-version: 22 - cache: pnpm - - - run: pnpm install --frozen-lockfile - - - name: Build all packages - run: pnpm build -``` - -## Codecov Configuration: `codecov.yml` - -```yaml -codecov: - require_ci_to_pass: true - -coverage: - precision: 2 - round: down - range: "60...90" - - status: - project: - default: - target: auto - threshold: 2% - if_ci_failed: error - patch: - default: - target: 80% - threshold: 5% - - ignore: - - "packages/test/**" - - "packages/*/dist/**" - - "**/*.test.ts" - - "**/*.test-d.ts" - - "plans/**" - - "playgrounds/**" - -comment: - layout: "reach,diff,flags,files" - behavior: default - require_changes: true - -flags: - unittests: - paths: - - packages/core/src/ - - packages/connectors/src/ - - packages/react/src/ - carryforward: true -``` - -## Vitest Coverage Configuration - -Update `vitest.config.ts` to generate lcov coverage: - -```typescript -export default defineConfig({ - test: { - coverage: { - provider: 'v8', - reporter: process.env.CI ? ['lcov'] : ['text', 'json', 'html'], - exclude: [ - '**/dist/**', - '**/*.test.ts', - '**/*.test-d.ts', - 'packages/test/**', - 'plans/**', - ], - }, - // ... existing projects config - }, -}) -``` - -Required dev dependency at root: -``` -pnpm add -Dw @vitest/coverage-v8 -``` - -## Setup Steps - -1. **Blacksmith**: Sign up at blacksmith.sh, connect GitHub org, configure runner labels -2. **Codecov**: Sign up at codecov.io, connect `quantumlyy/mbga` repo, get `CODECOV_TOKEN` -3. **GitHub Secrets**: Add `CODECOV_TOKEN` to repo secrets -4. **Create files**: - - `.github/workflows/ci.yml` - - `codecov.yml` (root) -5. **Update vitest.config.ts** with coverage config -6. **Add `@vitest/coverage-v8`** to root dev dependencies -7. **Add badges** to README.md - -## Optional: Additional Workflows - -### PR Size Check (`.github/workflows/pr-size.yml`) -Warn if PR is too large (helps keep reviews manageable). - -### Bundle Size (`.github/workflows/bundle-size.yml`) -Track package bundle sizes on PRs using `size-limit`. - -### Release (`.github/workflows/release.yml`) -Automated npm publishing via changesets (future, when ready for npm). - -## Blacksmith Runner Notes - -- Use `blacksmith-2vcpu-ubuntu-2404` for standard jobs -- Use `blacksmith-4vcpu-ubuntu-2404` for heavier jobs (build, E2E tests) -- Blacksmith provides bare-metal ARM64 runners with better cache performance -- `useblacksmith/setup-node@v5` replaces `actions/setup-node@v4` for optimized Node.js setup -- pnpm caching works the same as with GitHub-hosted runners diff --git a/plans/integration-testing.md b/plans/integration-testing.md deleted file mode 100644 index 9475c88..0000000 --- a/plans/integration-testing.md +++ /dev/null @@ -1,206 +0,0 @@ -# Integration Testing Plan for Wallet Connectors - -How to verify that our web wallet connectors/integrations are properly working and being used. - -## 1. Mock Connector Testing (Automated - CI) - -Already scaffolded in `@mbga/test`. These tests run in CI without any real wallet. - -### What to test -- Full lifecycle: `connect` -> `getBalance` -> `sendPayment` -> `disconnect` -- State transitions: `disconnected` -> `connecting` -> `connected` -> `disconnected` -- Reconnect flow: connect, simulate page reload (recreate config with storage), verify reconnect -- Error paths: connection refused, user rejected, timeout, provider unavailable -- Multiple connectors registered, connecting to one at a time -- Event emissions: `connect`, `disconnect`, `change`, `error` events fire correctly - -### How -```typescript -// Example: full lifecycle test with mock connector -const config = createConfig({ - network: sparkMainnet, - connectors: [mock({ accounts: ['sp1abc...'] })], -}) - -// Connect -const result = await connect(config, { connector: config.connectors[0]! }) -expect(config.state.status).toBe('connected') -expect(result.accounts).toEqual(['sp1abc...']) - -// Disconnect -await disconnect(config) -expect(config.state.status).toBe('disconnected') -``` - -## 2. Sats-Connect Connector Testing (Semi-Automated) - -### Unit tests with mocked sats-connect module -Mock the `sats-connect` default export at the module level to simulate wallet responses -without a real browser extension. - -```typescript -vi.mock('sats-connect', () => ({ - default: { - request: vi.fn().mockImplementation((method, params) => { - if (method === 'getAccounts') { - return { status: 'success', result: [{ address: 'sp1test...', purpose: 'payment' }] } - } - if (method === 'wallet_renouncePermissions') { - return { status: 'success', result: null } - } - return { status: 'error', error: { code: -1, message: 'Unknown method' } } - }), - }, -})) -``` - -### Test scenarios -- [ ] `connect()` calls `wallet.request('getAccounts', ...)` and extracts addresses -- [ ] `connect()` with user rejection returns error with correct code -- [ ] `disconnect()` calls `wallet_renouncePermissions` -- [ ] `getAccounts()` returns addresses from provider -- [ ] `isAuthorized()` returns true when connected, false when not -- [ ] `onAccountsChanged` fires change event -- [ ] `onDisconnect` fires disconnect event -- [ ] Dynamic import of `sats-connect` only happens on first use (lazy loading) - -## 3. Real Wallet Manual Testing (Pre-Release QA) - -### Test environment setup -1. Create a minimal test dapp (Vite + React) in `playgrounds/vite-react/` -2. Configure with `createConfig({ network: sparkTestnet, connectors: [satsConnect()] })` -3. Build UI with connect/disconnect buttons, balance display, send form -4. Deploy to a testnet-facing URL or run locally - -### Manual test checklist per connector - -#### sats-connect / Xverse -- [ ] Install Xverse browser extension -- [ ] Click "Connect" -> wallet popup appears -- [ ] Approve connection -> accounts populated, status = connected -- [ ] Page shows connected address -- [ ] Refresh page -> auto-reconnects (if storage persisted) -- [ ] Click "Disconnect" -> status = disconnected, wallet notified -- [ ] Reject connection -> error state shown, status = disconnected -- [ ] Connect -> close wallet popup (not reject) -> handles gracefully - -#### LayerzWallet (when connector built) -- [ ] Install LayerzWallet browser extension -- [ ] Same checklist as above -- [ ] Verify Spark-specific operations work (not just generic Bitcoin) - -### What to verify in each test -1. **Connection**: Wallet popup appears, accounts returned, state updates -2. **Persistence**: Refresh page, connector reconnects from storage -3. **Disconnection**: Clean disconnect, state resets, wallet notified -4. **Error handling**: Rejection, timeout, extension not installed -5. **Multiple connectors**: Two connectors registered, user can choose which -6. **React hooks**: `useConnect`, `useDisconnect`, `useConnection` all reflect state correctly - -## 4. Playwright E2E Testing (Automated Browser Tests) - -### Setup -- Use Playwright with a real Chromium browser -- Load a test extension that simulates wallet behavior (mock extension) -- Or use Playwright's `context.addInitScript` to inject a mock provider on `window` - -### Example: Mock injected provider -```typescript -// In Playwright test -await page.addInitScript(() => { - window.__MOCK_SATS_CONNECT__ = { - request: async (method, params) => { - if (method === 'getAccounts') { - return { status: 'success', result: [{ address: 'sp1mock...', purpose: 'payment' }] } - } - return { status: 'success', result: null } - } - } -}) -``` - -### Test scenarios -- [ ] Load dapp -> connectors list shows available wallets -- [ ] Click connect -> mock wallet responds -> UI shows connected state -- [ ] Connected state persists in localStorage -- [ ] Disconnect -> UI returns to disconnected state -- [ ] No wallet installed -> appropriate error/message shown - -## 5. Monitoring & Analytics (Production) - -### How to verify connectors are being used in production - -#### Event tracking -Emit analytics events at key lifecycle points: -- `mbga.connect.attempt` - User clicked connect (with connector id) -- `mbga.connect.success` - Connection succeeded -- `mbga.connect.error` - Connection failed (with error type) -- `mbga.disconnect` - User disconnected -- `mbga.reconnect.success` - Auto-reconnect on page load -- `mbga.reconnect.failure` - Auto-reconnect failed - -#### Implementation approach -Add an optional `onEvent` callback to `createConfig`: -```typescript -const config = createConfig({ - network: sparkMainnet, - connectors: [satsConnect()], - onEvent: (event) => { - // Send to PostHog, Amplitude, etc. - analytics.track(event.name, event.data) - }, -}) -``` - -#### Health metrics to track -- Connect success rate per connector -- Average time to connect -- Reconnect success rate -- Most common error types -- Connector distribution (which wallets users prefer) - -## 6. Connector Conformance Test Suite - -A standardized test suite that any connector must pass before being added to `@mbga/connectors`. - -### Required tests -```typescript -function testConnectorConformance(createConnectorFn: CreateConnectorFn) { - it('has required properties', () => { - const connector = createConnectorFn({ emitter, storage }) - expect(connector.id).toBeTruthy() - expect(connector.name).toBeTruthy() - expect(connector.type).toBeTruthy() - expect(typeof connector.connect).toBe('function') - expect(typeof connector.disconnect).toBe('function') - expect(typeof connector.getAccounts).toBe('function') - expect(typeof connector.getProvider).toBe('function') - expect(typeof connector.isAuthorized).toBe('function') - expect(typeof connector.onAccountsChanged).toBe('function') - expect(typeof connector.onDisconnect).toBe('function') - }) - - it('connect returns accounts array', async () => { - const connector = createConnectorFn({ emitter, storage }) - const result = await connector.connect() - expect(Array.isArray(result.accounts)).toBe(true) - expect(result.accounts.length).toBeGreaterThan(0) - expect(typeof result.accounts[0]).toBe('string') - }) - - it('disconnect does not throw', async () => { - const connector = createConnectorFn({ emitter, storage }) - await connector.connect() - await expect(connector.disconnect()).resolves.not.toThrow() - }) - - it('isAuthorized reflects connection state', async () => { - const connector = createConnectorFn({ emitter, storage }) - expect(await connector.isAuthorized()).toBe(false) - await connector.connect() - expect(await connector.isAuthorized()).toBe(true) - await connector.disconnect() - expect(await connector.isAuthorized()).toBe(false) - }) -} -``` diff --git a/plans/modernization.md b/plans/modernization.md deleted file mode 100644 index aa77db9..0000000 --- a/plans/modernization.md +++ /dev/null @@ -1,165 +0,0 @@ -# Codebase Modernization Plan - -The initial scaffold is derived from WAGMI's architecture patterns. This document tracks -planned modernization efforts to bring the codebase up to current best practices and -diverge from WAGMI's historical decisions where appropriate. - -## 1. Module System: Drop `.js` Extensions in TypeScript Imports - -### Problem -Throughout the codebase, imports use `.js` extensions: -```typescript -import { createConnector } from './connectors/createConnector.js' -import { createEmitter } from './createEmitter.js' -``` - -This is a WAGMI convention stemming from Node.js ESM requiring explicit file extensions. -While technically correct for `"moduleResolution": "NodeNext"`, it feels dated and creates -friction: -- Editors and refactoring tools don't always handle `.js` → `.ts` resolution well -- It's visually confusing to reference `.js` when the source files are `.ts` -- Most modern bundlers (Vite, esbuild, Rollup) resolve extensionless imports fine - -### Plan -- [ ] Switch `moduleResolution` to `"bundler"` in `tsconfig.base.json` -- [ ] Remove all `.js` extensions from TypeScript imports across all packages -- [ ] Update build pipeline to use a bundler (tsup or unbuild) instead of raw `tsc` -- [ ] Verify all exports still resolve correctly for consumers -- [ ] Update `"module"` to `"ESNext"` or keep `"NodeNext"` depending on bundler choice - -### Trade-offs -- **Pro**: Cleaner imports, better DX, standard TypeScript experience -- **Con**: Consumers using Node.js ESM natively (without a bundler) would need a bundler step -- **Decision**: Since this is primarily consumed via React apps (always bundled), this is fine - -## 2. Build System: Switch from `tsc` to `tsup` or `unbuild` - -### Problem -Currently packages build with raw `tsc`, producing only ESM. This has limitations: -- No CJS output (limits compatibility) -- No bundling/tree-shaking at the package level -- Slow builds as the project grows -- No automatic declaration bundling - -### Plan -- [ ] Adopt `tsup` (or `unbuild`) as the build tool for all packages -- [ ] Configure dual ESM + CJS output -- [ ] Enable declaration bundling (`--dts`) to produce single `.d.ts` files -- [ ] Add source maps -- [ ] Benchmark build times vs current `tsc` approach -- [ ] Update package.json `exports` to include `require` and `import` conditions - -### Configuration Template -```typescript -// tsup.config.ts -import { defineConfig } from 'tsup' - -export default defineConfig({ - entry: ['src/exports/index.ts', 'src/exports/actions.ts'], - format: ['esm', 'cjs'], - dts: true, - sourcemap: true, - clean: true, - splitting: true, - treeshake: true, -}) -``` - -## 3. State Management: Evaluate Alternatives to Zustand - -### Current State -We use zustand 5.0 with persist and subscribeWithSelector middleware, matching WAGMI's approach. - -### Considerations -- Zustand is solid and well-maintained - no urgent need to change -- Potential alternatives worth monitoring: - - **Jotai** - Atomic state model, might be simpler for our use case - - **Nanostores** - Tiny footprint, framework-agnostic by design - - **Native signals** (TC39 proposal) - If/when this lands -- [ ] Evaluate if zustand's middleware pattern is the right fit as features grow -- [ ] Consider whether a simpler EventEmitter + Map approach could replace zustand for our specific use case (we don't use most of zustand's features) - -### Decision: Keep zustand for now, revisit at Phase 2 - -## 4. Type System Improvements - -### Simplify Utility Types -WAGMI has accumulated complex utility types (`Compute`, `ExactPartial`, `OneOf`, etc.). -Some of these are needed, others add complexity without clear benefit. - -- [ ] Audit all utility types in `types/utils.ts` -- [ ] Remove unused types -- [ ] Replace `Compute` with inline `{ [K in keyof T]: T[K] }` where it improves readability -- [ ] Consider using `Simplify` from `type-fest` instead of rolling our own -- [ ] Add type-level tests (`*.test-d.ts`) for all public types - -### Stronger Connector Typing -- [ ] Make connector `getProvider()` return type more specific (not just `unknown`) -- [ ] Type the `request()` method with a discriminated union of method names and params -- [ ] Explore using branded types for addresses (Bitcoin address vs Lightning address) - -## 5. Dependency Modernization - -### Current Dependencies to Watch -| Package | Current | Notes | -|---------|---------|-------| -| `eventemitter3` | 5.0.1 | Consider `mitt` (200B) or native EventTarget | -| `zustand` | 5.0.0 | Keep updated, evaluate at Phase 2 | -| `use-sync-external-store` | 1.4.0 | May be removable with React 19's `useSyncExternalStore` built-in | -| `@tanstack/react-query` | ^5.x | Keep updated | - -### Planned Changes -- [ ] Replace `eventemitter3` with `mitt` (saves ~3KB, simpler API) -- [ ] Drop `use-sync-external-store` shim once we require React 19+ -- [ ] Evaluate `valibot` (used by sats-connect) as our validation library -- [ ] Add `type-fest` for common utility types - -## 6. Code Quality & Tooling - -### Linting/Formatting -- [ ] Ensure Biome covers all files (currently configured) -- [ ] Add `biome check` to pre-commit hook -- [ ] Consider enabling `noBarrelFile` globally (we currently suppress it for entrypoints) - -### CI/CD Pipeline -- [ ] GitHub Actions workflow: lint, type-check, test, build -- [ ] Automated npm publishing via changesets -- [ ] Bundle size tracking (size-limit) -- [ ] Renovate/Dependabot for dependency updates - -### Documentation -- [ ] JSDoc comments on all public APIs -- [ ] Auto-generated API docs (TypeDoc or similar) -- [ ] VitePress documentation site (like wagmi.sh) - -## 7. Architecture Divergences from WAGMI - -Things we intentionally do differently: - -### No Chain Abstraction -WAGMI's `chains` array and chain switching is designed for multi-chain EVM. We use a single -`network` (mainnet/testnet) since Spark is one network. This simplifies: -- Config creation (no transport mapping per chain) -- Connection state (no chainId tracking) -- No `switchChain` action needed - -### No ABI/Contract System -WAGMI has extensive ABI encoding, contract read/write, and multicall support. We don't need -any of this since Spark doesn't use smart contracts in the EVM sense. - -### Payment-First Actions -Instead of `sendTransaction` with hex data, we have: -- `sendPayment` - Lightning/Spark payments -- `createInvoice` - Generate payment requests -- `waitForPayment` - Subscribe to incoming payments - -These are higher-level abstractions matching how Bitcoin/Lightning apps actually work. - -### Simpler Connector Interface -Our connectors don't need: -- `switchChain` - Single network -- `getChainId` - No chains -- `rdns` / EIP-6963 - Bitcoin wallets don't use this standard (yet) -- `getClient` - No viem client concept - -This makes writing new connectors significantly simpler than WAGMI connectors. diff --git a/plans/readme-and-examples.md b/plans/readme-and-examples.md deleted file mode 100644 index 58483e6..0000000 --- a/plans/readme-and-examples.md +++ /dev/null @@ -1,193 +0,0 @@ -# README & Usage Examples Plan - -## README.md Structure - -### Header -- Project name + tagline: "MBGA - React Hooks for Spark" -- Badges: npm version, CI status, codecov, license -- One-sentence description: "Type-safe React hooks and vanilla JS actions for connecting to Spark wallets" - -### Quick Start -```tsx -import { createConfig, MbgaProvider, sparkMainnet } from 'mbga' -import { satsConnect } from 'mbga/connectors' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' - -const config = createConfig({ - network: sparkMainnet, - connectors: [satsConnect()], -}) - -const queryClient = new QueryClient() - -function App() { - return ( - - - - - - ) -} - -function WalletConnect() { - const { connect, connectors } = useConnect() - const { disconnect } = useDisconnect() - const { isConnected, accounts } = useConnection() - - if (isConnected) { - return ( -
-

Connected: {accounts[0]}

- -
- ) - } - - return ( -
- {connectors.map((connector) => ( - - ))} -
- ) -} -``` - -### Installation -```bash -pnpm add mbga @tanstack/react-query -# or -npm install mbga @tanstack/react-query -``` - -### Sections to include -1. **Features** - Bullet list: type-safe, SSR-ready, multiple connectors, React hooks, vanilla JS core -2. **Packages** - Table of `@mbga/core`, `@mbga/connectors`, `mbga` with descriptions -3. **Configuration** - `createConfig` options (network, connectors, storage, ssr) -4. **Hooks reference** - Brief table of all hooks with one-line descriptions -5. **Core actions** - Brief table of vanilla JS actions for non-React usage -6. **Connectors** - List of available connectors and how to use each -7. **TypeScript** - Note on type inference, `Register` interface for augmentation -8. **Contributing** - Link to CONTRIBUTING.md (future) -9. **License** - MIT - -## Usage Examples - -### Example 1: Basic Connect/Disconnect (`examples/basic/`) -Minimal Vite + React app showing connect and disconnect flow. - -### Example 2: Display Balance (`examples/balance/`) -```tsx -function Balance() { - const { data, isLoading, error } = useBalance() - - if (isLoading) return

Loading balance...

- if (error) return

Error: {error.message}

- if (!data) return null - - return

Balance: {data.formatted} {data.symbol}

-} -``` - -### Example 3: Send Payment (`examples/send-payment/`) -```tsx -function SendPayment() { - const { sendPayment, isPending, isSuccess, error } = useSendPayment() - - const handleSend = () => { - sendPayment({ - to: 'sp1recipient...', - amount: 1000n, // 1000 sats - }) - } - - return ( -
- - {isSuccess &&

Payment sent!

} - {error &&

Error: {error.message}

} -
- ) -} -``` - -### Example 4: Sign Message (`examples/sign-message/`) -```tsx -function SignMessage() { - const { signMessage, data, isPending } = useSignMessage() - - return ( -
- - {data &&

Signature: {data.signature}

} -
- ) -} -``` - -### Example 5: Vanilla JS (No React) (`examples/vanilla/`) -```typescript -import { createConfig, connect, disconnect, getConnection } from '@mbga/core' -import { satsConnect } from '@mbga/connectors' -import { sparkMainnet } from '@mbga/core' - -const config = createConfig({ - network: sparkMainnet, - connectors: [satsConnect()], -}) - -// Connect -const { accounts } = await connect(config, { - connector: config.connectors[0]!, -}) -console.log('Connected:', accounts) - -// Check connection -const connection = getConnection(config) -console.log('Status:', connection.status) - -// Disconnect -await disconnect(config) -``` - -### Example 6: SSR / Next.js (`examples/nextjs/`) -```tsx -// app/providers.tsx -'use client' - -import { createConfig, MbgaProvider, sparkMainnet } from 'mbga' -import { satsConnect } from 'mbga/connectors' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { useState } from 'react' - -const config = createConfig({ - network: sparkMainnet, - connectors: [satsConnect()], - ssr: true, -}) - -export function Providers({ children }: { children: React.ReactNode }) { - const [queryClient] = useState(() => new QueryClient()) - - return ( - - - {children} - - - ) -} -``` - -## Implementation Order -1. Write README.md with quick start and hook/action reference tables -2. Create `examples/basic/` as a working Vite + React playground -3. Add remaining examples as the core actions get implemented -4. Add Next.js example once SSR is tested diff --git a/plans/roadmap.md b/plans/roadmap.md index 2a61045..c4888dc 100644 --- a/plans/roadmap.md +++ b/plans/roadmap.md @@ -12,46 +12,46 @@ - [x] @mbga/test: Mock connector and initial tests ### Milestone 1.1 - Working Wallet Connection -- [ ] Integrate actual Spark SDK for balance queries and payment sending -- [ ] Complete sats-connect connector with real wallet interaction -- [ ] End-to-end wallet connect/disconnect flow working in browser -- [ ] Persistent sessions (reconnect on page reload) -- [ ] Error handling with user-friendly messages +- [x] Integrate actual Spark SDK for balance queries and payment sending +- [x] Complete sats-connect connector with real wallet interaction +- [x] End-to-end wallet connect/disconnect flow working in browser +- [x] Persistent sessions (reconnect on page reload) +- [x] Error handling with user-friendly messages ### Milestone 1.2 - Core Actions Fully Implemented -- [ ] getBalance: Fetch real BTC/sats balance from Spark -- [ ] sendPayment: Support Lightning invoices (BOLT11), on-chain, and Spark-native transfers -- [ ] signMessage: BIP-322 message signing -- [ ] getTransaction: Look up transaction by ID -- [ ] waitForPayment: Subscribe to incoming payment events -- [ ] createInvoice: Generate Lightning/Spark invoices +- [x] getBalance: Fetch real BTC/sats balance from Spark +- [x] sendPayment: Support Lightning invoices (BOLT11), on-chain, and Spark-native transfers +- [x] signMessage: BIP-322 message signing +- [x] getTransaction: Look up transaction by ID +- [x] waitForPayment: Subscribe to incoming payment events +- [x] createInvoice: Generate Lightning/Spark invoices ## Phase 2: Advanced Features ### Milestone 2.0 - Multi-Wallet & Account Management -- [ ] Multiple simultaneous wallet connections -- [ ] Account switching within a single connector +- [x] Multiple simultaneous wallet connections +- [x] Account switching within a single connector - [ ] Multi-account balance aggregation - [ ] Connection prioritization and fallbacks ### Milestone 2.1 - Token & Asset Support -- [ ] Spark token balance queries (if Spark supports tokens/assets) -- [ ] Token transfer actions -- [ ] Token metadata fetching +- [x] Spark token balance queries (if Spark supports tokens/assets) +- [x] Token transfer actions +- [x] Token metadata fetching - [ ] NFT / Ordinals support via connectors that support it ### Milestone 2.2 - Transaction Management -- [ ] Transaction history queries +- [x] Transaction history queries - [ ] Transaction status polling/subscriptions -- [ ] Fee estimation +- [x] Fee estimation - [ ] PSBT (Partially Signed Bitcoin Transaction) support - [ ] Batch transactions / multi-send ### Milestone 2.3 - Developer Experience -- [ ] CLI tool (`create-mbga`) for scaffolding new projects -- [ ] Playground / example apps (Next.js, Vite) -- [ ] Comprehensive documentation site -- [ ] TypeScript type inference improvements +- [x] CLI tool (`create-mbga`) for scaffolding new projects +- [x] Playground / example apps (Next.js, Vite) +- [x] Comprehensive documentation site +- [x] TypeScript type inference improvements - [ ] DevTools browser extension ## Phase 3: Ecosystem Expansion @@ -66,15 +66,15 @@ - [ ] Spark-specific features (state channels, instant finality) - [ ] Flashnet swap operations - [ ] Clawback support for reversible transfers -- [ ] Spark SDK direct connector (@buildonspark/spark-sdk) +- [x] Spark SDK direct connector (@buildonspark/spark-sdk) - [ ] Monitor other wallets for Spark support and add connectors as available ### Milestone 3.2 - Enterprise & Production -- [ ] SSR/SSG support for all frameworks +- [x] SSR/SSG support for all frameworks - [ ] CDN-hosted UMD bundle - [ ] Performance benchmarks and optimization - [ ] Security audit -- [ ] Semantic versioning with changesets +- [x] Semantic versioning with changesets - [ ] npm publish automation ## Phase 4: Ecosystem Maturity diff --git a/plans/testing-plan.md b/plans/testing-plan.md deleted file mode 100644 index 0423f8b..0000000 --- a/plans/testing-plan.md +++ /dev/null @@ -1,107 +0,0 @@ -# MBGA Testing Plan - -## Testing Pyramid - -### Unit Tests (Highest Priority) -Tests for individual functions in isolation. - -#### @mbga/core -- [ ] `createConfig` - Config creation with various options, SSR mode, storage options -- [ ] `createConfig` - Connector setup and registration -- [ ] `createEmitter` - Event emission, subscription, unsubscription, once -- [ ] `createStorage` - Set/get/remove items, prefix handling, serialization -- [ ] `createStorage` - noopStorage, getDefaultStorage -- [ ] `createConnector` - Factory function produces valid connector shape -- [ ] `connect` - Happy path, already connected error, connector not found -- [ ] `disconnect` - Happy path, disconnect specific connector, disconnect last connection -- [ ] `reconnect` - Reconnect from stored connector ID, no stored ID, unauthorized -- [ ] `getBalance` - Not connected error, address parameter handling -- [ ] `sendPayment` - Not connected error, parameter validation -- [ ] `signMessage` - Not connected error, address resolution -- [ ] `getConnection` - Connected state, disconnected state, all status flags -- [ ] `getConnections` - Empty list, multiple connections -- [ ] `getConnectors` - Returns registered connectors -- [ ] `watchConnection` - Callback fires on state change, unsubscribe works -- [ ] `watchConnections` - Callback fires on connection add/remove -- [ ] `watchConnectors` - Callback fires on connector list change -- [ ] Error classes - Correct names, messages, inheritance -- [ ] Utility functions - deepEqual, serialize, deserialize, uid - -#### @mbga/connectors -- [ ] `satsConnect` - Creates valid connector, correct id/name/type -- [ ] `satsConnect` - Connect flow (mocked sats-connect module) -- [ ] `satsConnect` - Disconnect flow -- [ ] `satsConnect` - getAccounts returns addresses -- [ ] `satsConnect` - isAuthorized check -- [ ] `satsConnect` - Error handling on failed connection -- [ ] `satsConnect` - Account change events - -#### mbga (React) -- [ ] `MbgaProvider` - Provides config to children -- [ ] `MbgaProvider` - Throws without config -- [ ] `useConfig` - Returns config from context -- [ ] `useConfig` - Throws outside provider -- [ ] `useConfig` - Accepts config parameter override -- [ ] `useConnect` - Mutation lifecycle (idle -> pending -> success) -- [ ] `useConnect` - Error handling -- [ ] `useConnect` - Exposes connectors list -- [ ] `useDisconnect` - Mutation lifecycle -- [ ] `useConnection` - Reflects connection state changes -- [ ] `useConnection` - Status flags (isConnected, isConnecting, etc.) -- [ ] `useBalance` - Query lifecycle, caching -- [ ] `useSendPayment` - Mutation lifecycle -- [ ] `useSignMessage` - Mutation lifecycle -- [ ] `useConnectors` - Syncs with external store -- [ ] `useReconnect` - Auto-reconnect flow - -### Integration Tests -Tests that exercise multiple units together. - -- [ ] Full connect -> getBalance -> sendPayment -> disconnect flow -- [ ] Multiple connector registration and switching -- [ ] Storage persistence across config recreation (simulating page reload) -- [ ] SSR hydration with initial state -- [ ] React provider with multiple hooks consuming same config -- [ ] Concurrent connection attempts -- [ ] Reconnect after storage-persisted session - -### E2E Tests (Future) -Tests with real browser and wallet extensions. - -- [ ] Connect with Xverse (sats-connect) in Chromium -- [ ] Connect with Leather wallet -- [ ] Connect with Unisat wallet -- [ ] Full payment flow with testnet wallet -- [ ] Multi-wallet connection in same session -- [ ] Session persistence across page navigations - -## Test Infrastructure - -### Current Setup -- **Runner**: Vitest 3.x -- **Environments**: Node (core, connectors), happy-dom (react) -- **Mock Connector**: `@mbga/test` package with `mock()` connector - -### Planned Additions -- [ ] Browser testing with Playwright for React hooks -- [ ] Snapshot testing for serialized state -- [ ] Type-level tests (test-d.ts files) for TypeScript inference -- [ ] Performance benchmarks for state updates -- [ ] Coverage reporting (aim for >80% on core) -- [ ] CI integration with GitHub Actions -- [ ] Wallet mock server (like prool in WAGMI) for simulating wallet responses -- [ ] Visual regression tests for any UI components - -### Mocking Strategy -1. **Wallet providers**: Mock at the `sats-connect` module level using vitest `vi.mock()` -2. **Storage**: Use `noopStorage` or in-memory storage for tests -3. **Network requests**: Mock Spark SDK/API responses -4. **React**: Use `@testing-library/react` with custom render that wraps in MbgaProvider + QueryClientProvider - -## Test Conventions -- Test files live next to source: `foo.ts` -> `foo.test.ts` -- Type tests use `.test-d.ts` extension -- Each test file focuses on one module/function -- Use `describe` blocks to group related tests -- Prefer `it('does X when Y')` naming pattern -- Shared test setup in `@mbga/test` package From 34177edbb120cdfee64c2f204fcb81e0e56753b5 Mon Sep 17 00:00:00 2001 From: Nejc Drobnic Date: Sat, 4 Apr 2026 14:17:28 +0200 Subject: [PATCH 2/4] fix(docs): correct kit quick start, walletStandard docs, and react install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - KitProvider requires MbgaProvider parent, not a config prop — fix quick start to show correct nesting - walletStandard connector requires a wallet arg; document the walletStandardDiscovery plugin for auto-discovery instead - Restore sats-connect in react install command (peer dep of xverse) Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/connectors/README.md | 11 ++++++----- packages/kit/README.md | 18 +++++++++++++----- packages/react/README.md | 8 +++++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/packages/connectors/README.md b/packages/connectors/README.md index c6ebeea..c02c9eb 100644 --- a/packages/connectors/README.md +++ b/packages/connectors/README.md @@ -58,17 +58,18 @@ const config = createConfig({ ### `walletStandard` -Connects to any wallet that implements the [Wallet Standard](https://github.com/wallet-standard/wallet-standard) with `spark:*` features. Automatically discovers compatible wallets at runtime. +Wraps a [Wallet Standard](https://github.com/wallet-standard/wallet-standard) `Wallet` instance into an MBGA connector. Supports `standard:connect`/`disconnect`/`events` and Spark-specific features (`spark:connect`, `spark:getBalance`, etc.). + +Typically you won't create these manually -- use the `walletStandardDiscovery` plugin to auto-discover and register compatible wallets at runtime: ```ts -import { walletStandard } from '@mbga/connectors' +import { xverse, walletStandardDiscovery } from '@mbga/connectors' import { createConfig, sparkMainnet } from '@mbga/core' const config = createConfig({ network: sparkMainnet, - connectors: [ - walletStandard(), - ], + connectors: [xverse()], + plugins: [walletStandardDiscovery()], }) ``` diff --git a/packages/kit/README.md b/packages/kit/README.md index 70cce93..c0c8be3 100644 --- a/packages/kit/README.md +++ b/packages/kit/README.md @@ -15,25 +15,33 @@ Peer dependencies: `react`, `react-dom`, `@tanstack/react-query`. ## Quick Start ```tsx +import { MbgaProvider } from 'mbga' import { KitProvider, ConnectButton } from '@mbga/kit' import { createConfig, sparkMainnet } from '@mbga/core' import { xverse } from '@mbga/connectors' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' const config = createConfig({ network: sparkMainnet, connectors: [xverse()], }) +const queryClient = new QueryClient() + function App() { return ( - - - + + + + + + + ) } ``` -`KitProvider` wraps `MbgaProvider` and `QueryClientProvider` internally -- no extra setup needed. +`KitProvider` must be placed inside a `MbgaProvider`. It handles theming and modal state for the kit components. ## Components @@ -41,7 +49,7 @@ function App() { | Component | Description | |-----------|-------------| -| `KitProvider` | Context provider (config, theming, modal state) | +| `KitProvider` | Context provider (theming, modal state). Must be inside `MbgaProvider`. | | `ConnectButton` | Connect/disconnect button with connected state display | | `ConnectModal` | Modal with wallet list for selecting a connector | | `AccountModal` | Connected account info (address, balance, disconnect) | diff --git a/packages/react/README.md b/packages/react/README.md index 818e828..125a7f1 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -7,11 +7,13 @@ Powered by [TanStack Query](https://tanstack.com/query) for caching, deduplicati ## Installation ```bash -npm install mbga @mbga/connectors @tanstack/react-query -pnpm add mbga @mbga/connectors @tanstack/react-query -yarn add mbga @mbga/connectors @tanstack/react-query +npm install mbga @mbga/connectors sats-connect @tanstack/react-query +pnpm add mbga @mbga/connectors sats-connect @tanstack/react-query +yarn add mbga @mbga/connectors sats-connect @tanstack/react-query ``` +> `sats-connect` is a peer dependency of `@mbga/connectors` required by the `xverse` connector. + ## Quick Start ### 1. Create a config From df512b7af2ea858719fb14cf8e14829570df5943 Mon Sep 17 00:00:00 2001 From: Nejc Drobnic Date: Sat, 4 Apr 2026 14:18:52 +0200 Subject: [PATCH 3/4] chore: update repo references from quantumlyy/mbga to refrakts/mbga Rename all GitHub URLs, repository fields, badge links, codecov slugs, and docs site references to the new org. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/CONTRIBUTING.md | 2 +- .github/workflows/test.yml | 2 +- NEXT_TASK.md | 2 +- README.md | 8 ++++---- packages/connectors/package.json | 2 +- packages/core/package.json | 2 +- packages/create-mbga/package.json | 2 +- packages/flashnet/package.json | 2 +- packages/kit/package.json | 2 +- packages/react/package.json | 2 +- packages/react/src/errors/context.ts | 2 +- site/pages/examples/index.mdx | 8 ++++---- site/pages/frameworks/nextjs.mdx | 2 +- site/pages/frameworks/vite.mdx | 2 +- site/pages/index.mdx | 8 ++++---- site/vocs.config.ts | 10 +++++----- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1e1c883..9f00aa8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -16,7 +16,7 @@ Thanks for your interest in contributing to MBGA! Please take a moment to review Clone the repo and install dependencies: ```bash -git clone https://github.com/quantumlyy/mbga.git +git clone https://github.com/refrakts/mbga.git cd mbga pnpm install ``` diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 92b5d5b..7467ece 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,7 +33,7 @@ jobs: uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} - slug: Quantumlyy/mbga + slug: refrakts/mbga files: ./coverage/lcov.info flags: unittests fail_ci_if_error: true diff --git a/NEXT_TASK.md b/NEXT_TASK.md index 340c930..d3c07b8 100644 --- a/NEXT_TASK.md +++ b/NEXT_TASK.md @@ -14,7 +14,7 @@ Requires auth above; atomic swaps between BTC/Lightning/Spark and other assets v ## Prompt ``` -Work on the quantumlyy/mbga repo. +Work on the refrakts/mbga repo. Your current task: **Flashnet swaps and clawbacks** diff --git a/README.md b/README.md index f112e68..3c985b1 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ Reactive primitives for Spark apps. [![npm version](https://img.shields.io/npm/v/mbga)](https://www.npmjs.com/package/mbga) -[![license](https://img.shields.io/npm/l/mbga)](https://github.com/quantumlyy/mbga/blob/main/LICENSE) -[![codecov](https://codecov.io/gh/quantumlyy/mbga/graph/badge.svg?token=4UcviQKuL6)](https://codecov.io/gh/quantumlyy/mbga) +[![license](https://img.shields.io/npm/l/mbga)](https://github.com/refrakts/mbga/blob/main/LICENSE) +[![codecov](https://codecov.io/gh/refrakts/mbga/graph/badge.svg?token=4UcviQKuL6)](https://codecov.io/gh/refrakts/mbga) ## Features @@ -99,11 +99,11 @@ pnpm create mbga ## Community -- [GitHub Discussions](https://github.com/quantumlyy/mbga/discussions) — ask questions and share ideas +- [GitHub Discussions](https://github.com/refrakts/mbga/discussions) — ask questions and share ideas ## Contributing -Contributions are welcome! Please read the [Contributing Guide](https://github.com/quantumlyy/mbga/blob/main/.github/CONTRIBUTING.md) before submitting a pull request. +Contributions are welcome! Please read the [Contributing Guide](https://github.com/refrakts/mbga/blob/main/.github/CONTRIBUTING.md) before submitting a pull request. ## Acknowledgments diff --git a/packages/connectors/package.json b/packages/connectors/package.json index a6fe79d..dd7a6af 100644 --- a/packages/connectors/package.json +++ b/packages/connectors/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/quantumlyy/mbga.git", + "url": "https://github.com/refrakts/mbga.git", "directory": "packages/connectors" }, "scripts": { diff --git a/packages/core/package.json b/packages/core/package.json index 1e82cf2..9e0fb0e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/quantumlyy/mbga.git", + "url": "https://github.com/refrakts/mbga.git", "directory": "packages/core" }, "scripts": { diff --git a/packages/create-mbga/package.json b/packages/create-mbga/package.json index 15839f8..0ec751a 100644 --- a/packages/create-mbga/package.json +++ b/packages/create-mbga/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "git+https://github.com/quantumlyy/mbga.git", + "url": "git+https://github.com/refrakts/mbga.git", "directory": "packages/create-mbga" }, "type": "module", diff --git a/packages/flashnet/package.json b/packages/flashnet/package.json index 12f633d..4a54293 100644 --- a/packages/flashnet/package.json +++ b/packages/flashnet/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/quantumlyy/mbga.git", + "url": "https://github.com/refrakts/mbga.git", "directory": "packages/flashnet" }, "scripts": { diff --git a/packages/kit/package.json b/packages/kit/package.json index 4a40358..5baa0cd 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/quantumlyy/mbga.git", + "url": "https://github.com/refrakts/mbga.git", "directory": "packages/kit" }, "scripts": { diff --git a/packages/react/package.json b/packages/react/package.json index 1375ffc..3934621 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/quantumlyy/mbga.git", + "url": "https://github.com/refrakts/mbga.git", "directory": "packages/react" }, "scripts": { diff --git a/packages/react/src/errors/context.ts b/packages/react/src/errors/context.ts index 3ed536a..ee90b69 100644 --- a/packages/react/src/errors/context.ts +++ b/packages/react/src/errors/context.ts @@ -8,7 +8,7 @@ export class MbgaProviderNotFoundError extends BaseError { constructor() { super( '`useMbga` must be used within `MbgaProvider`.\n\n' + - 'Docs: https://github.com/quantumlyy/mbga', + 'Docs: https://github.com/refrakts/mbga', ) } } diff --git a/site/pages/examples/index.mdx b/site/pages/examples/index.mdx index 3759880..b7f8099 100644 --- a/site/pages/examples/index.mdx +++ b/site/pages/examples/index.mdx @@ -10,11 +10,11 @@ Working example apps demonstrating MBGA in different frameworks. A minimal React app with wallet connection, balance display, payments, invoice creation, message signing, and fee estimation. -**Source:** [examples/vite-react](https://github.com/quantumlyy/mbga/tree/main/examples/vite-react) +**Source:** [examples/vite-react](https://github.com/refrakts/mbga/tree/main/examples/vite-react) ```bash # Run locally -git clone https://github.com/quantumlyy/mbga.git +git clone https://github.com/refrakts/mbga.git cd mbga pnpm install pnpm dev:vite @@ -37,11 +37,11 @@ pnpm dev:vite SSR-compatible setup using Next.js App Router with `'use client'` directives and SSR-safe storage. -**Source:** [examples/nextjs](https://github.com/quantumlyy/mbga/tree/main/examples/nextjs) +**Source:** [examples/nextjs](https://github.com/refrakts/mbga/tree/main/examples/nextjs) ```bash # Run locally -git clone https://github.com/quantumlyy/mbga.git +git clone https://github.com/refrakts/mbga.git cd mbga pnpm install pnpm dev:next diff --git a/site/pages/frameworks/nextjs.mdx b/site/pages/frameworks/nextjs.mdx index 60d20a8..76f4ccf 100644 --- a/site/pages/frameworks/nextjs.mdx +++ b/site/pages/frameworks/nextjs.mdx @@ -72,4 +72,4 @@ All component files using MBGA hooks must include `'use client'` at the top. ## Example -See the full [Next.js example](https://github.com/quantumlyy/mbga/tree/main/examples/nextjs) for an App Router setup. +See the full [Next.js example](https://github.com/refrakts/mbga/tree/main/examples/nextjs) for an App Router setup. diff --git a/site/pages/frameworks/vite.mdx b/site/pages/frameworks/vite.mdx index 8a0a110..3eb8d38 100644 --- a/site/pages/frameworks/vite.mdx +++ b/site/pages/frameworks/vite.mdx @@ -54,4 +54,4 @@ export default function App() { ## Example -See the full [Vite + React example](https://github.com/quantumlyy/mbga/tree/main/examples/vite-react) for a complete working app with wallet connection, balance display, payments, invoices, and message signing. +See the full [Vite + React example](https://github.com/refrakts/mbga/tree/main/examples/vite-react) for a complete working app with wallet connection, balance display, payments, invoices, and message signing. diff --git a/site/pages/index.mdx b/site/pages/index.mdx index 7b88474..949aadf 100644 --- a/site/pages/index.mdx +++ b/site/pages/index.mdx @@ -17,7 +17,7 @@ import { HomePage } from 'vocs'
Build Bitcoin apps with lightweight, composable, and type-safe modules that interface with Spark
Get started - GitHub + GitHub
@@ -131,9 +131,9 @@ mbga supports all these features out-of-the-box: Check out the following places for more mbga-related content: -- Join the [discussions on GitHub](https://github.com/quantumlyy/mbga/discussions) -- Check out the [example apps](https://github.com/quantumlyy/mbga/tree/main/examples) -- Read the [contributing guide](https://github.com/quantumlyy/mbga/blob/main/.github/CONTRIBUTING.md) +- Join the [discussions on GitHub](https://github.com/refrakts/mbga/discussions) +- Check out the [example apps](https://github.com/refrakts/mbga/tree/main/examples) +- Read the [contributing guide](https://github.com/refrakts/mbga/blob/main/.github/CONTRIBUTING.md) diff --git a/site/vocs.config.ts b/site/vocs.config.ts index c0ce67c..7aecd70 100644 --- a/site/vocs.config.ts +++ b/site/vocs.config.ts @@ -11,12 +11,12 @@ export default defineConfig({ titleTemplate: '%s – MBGA', accentColor: 'light-dark(#f7931a, #ffc517)', editLink: { - link: 'https://github.com/quantumlyy/mbga/edit/main/site/pages/:path', + link: 'https://github.com/refrakts/mbga/edit/main/site/pages/:path', text: 'Suggest changes to this page', }, mcp: { enabled: true, - sources: [McpSource.github({ name: 'mbga', repo: 'quantumlyy/mbga' })], + sources: [McpSource.github({ name: 'mbga', repo: 'refrakts/mbga' })], }, topNav: [ { @@ -31,11 +31,11 @@ export default defineConfig({ items: [ { text: 'Changelog', - link: 'https://github.com/quantumlyy/mbga/blob/main/CHANGELOG.md', + link: 'https://github.com/refrakts/mbga/blob/main/CHANGELOG.md', }, { text: 'Contributing', - link: 'https://github.com/quantumlyy/mbga/blob/main/.github/CONTRIBUTING.md', + link: 'https://github.com/refrakts/mbga/blob/main/.github/CONTRIBUTING.md', }, ], }, @@ -50,5 +50,5 @@ export default defineConfig({ '/examples': sidebar, '/acknowledgments': sidebar, }, - socials: [{ icon: 'github', link: 'https://github.com/quantumlyy/mbga' }], + socials: [{ icon: 'github', link: 'https://github.com/refrakts/mbga' }], }) From 861918f82c92643f891e38237ce77d7e2c5b0d15 Mon Sep 17 00:00:00 2001 From: Nejc Drobnic Date: Sat, 4 Apr 2026 14:33:05 +0200 Subject: [PATCH 4/4] fix(docs): fix kit install deps and theming example - List all required packages in install command (mbga, @mbga/core, @mbga/connectors, sats-connect, @tanstack/react-query) - Fix theming example: use theme="dark" string (not darkTheme object), show customTheme prop, remove nonexistent config prop Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/kit/README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/kit/README.md b/packages/kit/README.md index c0c8be3..85a40ee 100644 --- a/packages/kit/README.md +++ b/packages/kit/README.md @@ -5,13 +5,11 @@ Pre-built React UI components for connecting [Spark](https://www.spark.info/) wa ## Installation ```bash -npm install @mbga/kit -pnpm add @mbga/kit -yarn add @mbga/kit +npm install @mbga/kit mbga @mbga/core @mbga/connectors sats-connect @tanstack/react-query +pnpm add @mbga/kit mbga @mbga/core @mbga/connectors sats-connect @tanstack/react-query +yarn add @mbga/kit mbga @mbga/core @mbga/connectors sats-connect @tanstack/react-query ``` -Peer dependencies: `react`, `react-dom`, `@tanstack/react-query`. - ## Quick Start ```tsx @@ -79,12 +77,12 @@ Headless components are also available via the `@mbga/kit/headless` sub-path exp ## Theming -Built-in light and dark themes, customizable via CSS variables: +Built-in light and dark themes, with optional CSS variable overrides: ```tsx -import { KitProvider, darkTheme } from '@mbga/kit' +import { KitProvider } from '@mbga/kit' - + ```