create-miden-app 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/package.json +1 -1
  2. package/template/.claude/commands/review-security.md +67 -0
  3. package/template/.claude/settings.json +1 -7
  4. package/template/.claude/settings.local.json +24 -0
  5. package/template/.claude/skills/frontend-pitfalls/SKILL.md +28 -31
  6. package/template/.claude/skills/frontend-source-guide/SKILL.md +14 -14
  7. package/template/.claude/skills/miden-concepts/SKILL.md +4 -2
  8. package/template/.claude/skills/react-sdk-patterns/SKILL.md +294 -28
  9. package/template/.claude/skills/signer-integration/SKILL.md +22 -3
  10. package/template/.claude/skills/testing-patterns/SKILL.md +201 -40
  11. package/template/.claude/skills/vite-wasm-setup/SKILL.md +20 -14
  12. package/template/.claude/skills/web-client-usage/SKILL.md +454 -0
  13. package/template/.env.example +15 -2
  14. package/template/.mcp.json +9 -0
  15. package/template/CLAUDE.md +49 -16
  16. package/template/README.md +85 -19
  17. package/template/package.json +5 -4
  18. package/template/public/packages/counter_account.masp +0 -0
  19. package/template/public/packages/increment_note.masp +0 -0
  20. package/template/src/__tests__/fixtures/accounts.ts +17 -6
  21. package/template/src/__tests__/fixtures/index.ts +1 -0
  22. package/template/src/__tests__/mocks/miden-sdk-react.ts +18 -1
  23. package/template/src/__tests__/patterns/mutation-hook.test.tsx +2 -2
  24. package/template/src/__tests__/patterns/provider-setup.test.tsx +2 -0
  25. package/template/src/components/AppContent.tsx +33 -3
  26. package/template/{create-miden-app/template/src/components/Counter.tsx → src/components/ConfiguredCounter.tsx} +7 -4
  27. package/template/src/components/Counter.tsx +12 -41
  28. package/template/src/components/__tests__/AppContent.test.tsx +192 -4
  29. package/template/src/components/__tests__/ConfiguredCounter.test.tsx +116 -0
  30. package/template/src/components/__tests__/Counter.test.tsx +24 -94
  31. package/template/src/config.ts +26 -6
  32. package/template/src/hooks/__tests__/useIncrementCounter.test.tsx +257 -0
  33. package/template/src/hooks/useIncrementCounter.ts +109 -50
  34. package/template/src/providers.tsx +20 -24
  35. package/template/vite.config.ts +1 -1
  36. package/template/vitest.config.ts +1 -2
  37. package/template/yarn.lock +761 -688
  38. package/template/create-miden-app/template/.claude/hooks/typecheck.sh +0 -27
  39. package/template/create-miden-app/template/.claude/settings.json +0 -17
  40. package/template/create-miden-app/template/.claude/skills/frontend-pitfalls/SKILL.md +0 -189
  41. package/template/create-miden-app/template/.claude/skills/frontend-source-guide/SKILL.md +0 -163
  42. package/template/create-miden-app/template/.claude/skills/miden-concepts/SKILL.md +0 -108
  43. package/template/create-miden-app/template/.claude/skills/react-sdk-patterns/SKILL.md +0 -294
  44. package/template/create-miden-app/template/.claude/skills/signer-integration/SKILL.md +0 -158
  45. package/template/create-miden-app/template/.claude/skills/vite-wasm-setup/SKILL.md +0 -128
  46. package/template/create-miden-app/template/.env.example +0 -5
  47. package/template/create-miden-app/template/CLAUDE.md +0 -116
  48. package/template/create-miden-app/template/README.md +0 -61
  49. package/template/create-miden-app/template/eslint.config.js +0 -23
  50. package/template/create-miden-app/template/index.html +0 -13
  51. package/template/create-miden-app/template/package.json +0 -34
  52. package/template/create-miden-app/template/public/vite.svg +0 -1
  53. package/template/create-miden-app/template/src/App.tsx +0 -10
  54. package/template/create-miden-app/template/src/assets/miden.svg +0 -3
  55. package/template/create-miden-app/template/src/assets/react.svg +0 -1
  56. package/template/create-miden-app/template/src/components/AppContent.css +0 -45
  57. package/template/create-miden-app/template/src/components/AppContent.tsx +0 -50
  58. package/template/create-miden-app/template/src/components/Counter.css +0 -27
  59. package/template/create-miden-app/template/src/config.ts +0 -21
  60. package/template/create-miden-app/template/src/hooks/useIncrementCounter.ts +0 -136
  61. package/template/create-miden-app/template/src/index.css +0 -75
  62. package/template/create-miden-app/template/src/lib/miden.ts +0 -9
  63. package/template/create-miden-app/template/src/main.tsx +0 -10
  64. package/template/create-miden-app/template/src/providers.tsx +0 -31
  65. package/template/create-miden-app/template/src/vite-env.d.ts +0 -1
  66. package/template/create-miden-app/template/tsconfig.app.json +0 -32
  67. package/template/create-miden-app/template/tsconfig.json +0 -7
  68. package/template/create-miden-app/template/tsconfig.node.json +0 -24
  69. package/template/create-miden-app/template/vite.config.ts +0 -17
  70. package/template/create-miden-app/template/yarn.lock +0 -1697
@@ -1,294 +0,0 @@
1
- ---
2
- name: react-sdk-patterns
3
- description: Complete guide to building Miden frontends with @miden-sdk/react hooks. Covers MidenProvider setup, all query hooks (useAccounts, useAccount, useNotes, useSyncState, useAssetMetadata), all mutation hooks (useCreateWallet, useSend, useMultiSend, useMint, useConsume, useSwap, useTransaction, useCreateFaucet), transaction stages, signer integration, and utility functions. Use when writing, editing, or reviewing Miden React frontend code.
4
- ---
5
-
6
- # Miden React SDK Patterns
7
-
8
- ## SDK Choice
9
-
10
- ALWAYS use `@miden-sdk/react` hooks. Only fall back to raw `@miden-sdk/miden-sdk` WebClient via `useMidenClient()` for operations not covered by hooks. The React SDK handles WASM safety (runExclusive), state management (Zustand), auto-sync, and transaction stage tracking automatically.
11
-
12
- ## MidenProvider Configuration
13
-
14
- ```tsx
15
- import { MidenProvider } from "@miden-sdk/react";
16
-
17
- <MidenProvider
18
- config={{
19
- rpcUrl: "devnet", // "devnet" | "testnet" | "localhost" | custom URL
20
- prover: "devnet", // "local" | "devnet" | "testnet" | custom URL
21
- autoSyncInterval: 15000, // ms, set to 0 to disable. Default: 15000
22
- noteTransportUrl: "...", // optional: for private note delivery
23
- }}
24
- loadingComponent={<Loading />} // shown during WASM init
25
- errorComponent={<Error />} // shown on init failure (receives Error prop)
26
- >
27
- <App />
28
- </MidenProvider>
29
- ```
30
-
31
- | Network | rpcUrl | Use When |
32
- |---------|--------|----------|
33
- | Devnet | `"devnet"` | Development, testing with fake tokens |
34
- | Testnet | `"testnet"` | Pre-production testing |
35
- | Localhost | `"localhost"` | Local node at `http://localhost:57291` |
36
-
37
- ## Query Hooks
38
-
39
- All return `{ data, isLoading, error, refetch }`.
40
-
41
- ### useAccounts()
42
- ```tsx
43
- const { data: accounts } = useAccounts();
44
- // accounts.wallets — regular wallet accounts
45
- // accounts.faucets — token faucet accounts
46
- // accounts.all — everything (AccountHeader[])
47
- ```
48
-
49
- ### useAccount(accountId: string)
50
- ```tsx
51
- const { data: account } = useAccount(accountId);
52
- // account.account — Account object (.id, .nonce, .bech32id())
53
- // account.assets — AssetBalance[] (assetId, amount, symbol?, decimals?)
54
- // account.getBalance(faucetId) — bigint balance for specific token
55
- ```
56
-
57
- ### useNotes(filter?)
58
- ```tsx
59
- const { data: notes } = useNotes();
60
- // notes.notes — InputNoteRecord[]
61
- // notes.consumableNotes — ConsumableNoteRecord[]
62
- // notes.noteSummaries — NoteSummary[] (id, assets, sender)
63
- // notes.consumableNoteSummaries — NoteSummary[]
64
-
65
- // Filter by account:
66
- const { data } = useNotes({ accountId: "0x..." });
67
- // Filter by status:
68
- const { data } = useNotes({ status: "committed" });
69
- ```
70
-
71
- ### useSyncState()
72
- ```tsx
73
- const { syncHeight, isSyncing, lastSyncTime, sync, error } = useSyncState();
74
- await sync(); // Manual sync
75
- ```
76
-
77
- ### useAssetMetadata(faucetId: string | string[])
78
- ```tsx
79
- const { data: metadata } = useAssetMetadata(faucetId);
80
- // metadata.symbol — "TEST"
81
- // metadata.decimals — 8
82
- ```
83
-
84
- ### useTransactionHistory(options?)
85
- ```tsx
86
- const { records, record, status, isLoading } = useTransactionHistory({ id: txId });
87
- // status: "pending" | "committed" | "discarded" | null
88
- ```
89
-
90
- ## Mutation Hooks
91
-
92
- All return `{ mutate, data, isLoading, stage, error, reset }`.
93
-
94
- **Transaction stages**: `"idle"` → `"executing"` → `"proving"` → `"submitting"` → `"complete"`
95
-
96
- ### useCreateWallet()
97
- ```tsx
98
- const { mutate: createWallet, isLoading } = useCreateWallet();
99
- const account = await createWallet({
100
- storageMode: "private", // "private" | "public" | "network". Default: "private"
101
- mutable: true, // Default: true
102
- authScheme: 0, // 0 = RpoFalcon512, 1 = EcdsaK256Keccak. Default: 0
103
- });
104
- ```
105
-
106
- ### useCreateFaucet()
107
- ```tsx
108
- const { mutate: createFaucet } = useCreateFaucet();
109
- const faucet = await createFaucet({
110
- tokenSymbol: "TEST",
111
- decimals: 8, // Default: 8
112
- maxSupply: 1000000n, // bigint!
113
- storageMode: "public", // Default: "private"
114
- });
115
- ```
116
-
117
- ### useSend()
118
- ```tsx
119
- const { mutate: send, stage } = useSend();
120
- await send({
121
- from: senderAccountId,
122
- to: recipientAccountId,
123
- assetId: faucetId, // token faucet ID
124
- amount: 1000n, // bigint!
125
- noteType: "private", // "private" | "public". Default: "private"
126
- recallHeight: 100, // optional: sender can reclaim after this block
127
- timelockHeight: 50, // optional: recipient can consume after this block
128
- });
129
- ```
130
-
131
- ### useMultiSend()
132
- ```tsx
133
- const { mutate: multiSend } = useMultiSend();
134
- await multiSend({
135
- from: senderAccountId,
136
- assetId: faucetId,
137
- recipients: [
138
- { to: recipient1, amount: 500n },
139
- { to: recipient2, amount: 300n },
140
- ],
141
- noteType: "private",
142
- });
143
- ```
144
-
145
- ### useMint()
146
- ```tsx
147
- const { mutate: mint } = useMint();
148
- await mint({
149
- targetAccountId: recipientId,
150
- faucetId: myFaucetId,
151
- amount: 10000n, // bigint!
152
- noteType: "public",
153
- });
154
- ```
155
-
156
- ### useConsume()
157
- ```tsx
158
- const { mutate: consume } = useConsume();
159
- await consume({
160
- accountId: myAccountId,
161
- noteIds: [noteId1, noteId2],
162
- });
163
- ```
164
-
165
- ### useSwap()
166
- ```tsx
167
- const { mutate: swap } = useSwap();
168
- await swap({
169
- accountId: myAccountId,
170
- offeredFaucetId: tokenA,
171
- offeredAmount: 100n,
172
- requestedFaucetId: tokenB,
173
- requestedAmount: 50n,
174
- noteType: "private",
175
- paybackNoteType: "private",
176
- });
177
- ```
178
-
179
- ### useTransaction() — Escape Hatch
180
- ```tsx
181
- const { mutate: execute } = useTransaction();
182
-
183
- // With pre-built TransactionRequest:
184
- await execute({ accountId, request: txRequest });
185
-
186
- // With factory function (gets access to client):
187
- await execute({
188
- accountId,
189
- request: (client) => client.newSwapTransactionRequest(/* ... */),
190
- });
191
- ```
192
-
193
- ### useWaitForCommit()
194
- ```tsx
195
- const { mutate: waitForCommit } = useWaitForCommit();
196
- await waitForCommit({
197
- transactionId: result.transactionId,
198
- timeoutMs: 10000, // Default: 10000
199
- intervalMs: 1000, // Default: 1000
200
- });
201
- ```
202
-
203
- ### useWaitForNotes()
204
- ```tsx
205
- const { mutate: waitForNotes } = useWaitForNotes();
206
- await waitForNotes({
207
- accountId: myAccountId,
208
- minCount: 1, // Default: 1
209
- timeoutMs: 10000,
210
- });
211
- ```
212
-
213
- ## Transaction Progress UI
214
-
215
- ```tsx
216
- function SendButton({ from, to, assetId, amount }) {
217
- const { mutate: send, stage, isLoading, error } = useSend();
218
-
219
- return (
220
- <div>
221
- <button onClick={() => send({ from, to, assetId, amount })} disabled={isLoading}>
222
- {isLoading ? `${stage}...` : "Send"}
223
- </button>
224
- {error && <p>Error: {error.message}</p>}
225
- </div>
226
- );
227
- }
228
- ```
229
-
230
- ## Signer Integration
231
-
232
- ### Local Keystore (Default)
233
- No signer provider needed. Keys are managed in the browser via IndexedDB.
234
-
235
- ### External Signers
236
- Wrap MidenProvider with a signer provider. Three pre-built options:
237
- - `ParaSignerProvider` from `@miden-sdk/para` — EVM wallets
238
- - `TurnkeySignerProvider` from `@miden-sdk/miden-turnkey-react` — passkey auth
239
- - `MidenFiSignerProvider` from `@miden-sdk/wallet-adapter-react` — MidenFi wallet
240
-
241
- ```tsx
242
- // Example: Para signer wrapping MidenProvider
243
- import { ParaSignerProvider } from "@miden-sdk/para";
244
- <ParaSignerProvider apiKey="..." environment="PRODUCTION">
245
- <MidenProvider config={...}><App /></MidenProvider>
246
- </ParaSignerProvider>
247
- ```
248
-
249
- ### useSigner() — Unified Interface
250
- ```tsx
251
- const { isConnected, connect, disconnect, name } = useSigner();
252
- ```
253
-
254
- ### Custom Signer
255
- Implement `SignerContextValue` interface via `SignerContext.Provider`. Requires: `name`, `storeName` (unique per user for DB isolation), `accountConfig`, `signCb`, `connect`, `disconnect`. See `frontend-source-guide` skill for source references.
256
-
257
- ## Utility Functions
258
-
259
- ```tsx
260
- import { formatAssetAmount, parseAssetAmount, getNoteSummary, formatNoteSummary, toBech32AccountId } from "@miden-sdk/react";
261
-
262
- formatAssetAmount(1000000n, 8) // "0.01"
263
- parseAssetAmount("0.01", 8) // 1000000n
264
- const summary = getNoteSummary(note); // { id, assets, sender }
265
- formatNoteSummary(summary); // "1.5 TEST"
266
- toBech32AccountId("0x1234..."); // "miden1qy35..."
267
- ```
268
-
269
- ## Direct Client Access
270
-
271
- ```tsx
272
- const client = useMidenClient(); // throws if not ready
273
- const { runExclusive } = useMiden();
274
-
275
- // For operations not covered by hooks:
276
- await runExclusive(async (client) => {
277
- const header = await client.getBlockHeaderByNumber(100);
278
- });
279
- ```
280
-
281
- ## Type Imports
282
-
283
- ```tsx
284
- import type {
285
- MidenConfig, QueryResult, MutationResult, TransactionStage,
286
- AccountsResult, AccountResult, AssetBalance, NotesResult, NoteSummary,
287
- SendOptions, MultiSendOptions, MintOptions, ConsumeOptions, SwapOptions,
288
- CreateWalletOptions, CreateFaucetOptions, ExecuteTransactionOptions,
289
- TransactionResult, SyncState, WaitForCommitOptions, WaitForNotesOptions,
290
- Account, AccountId, InputNoteRecord, ConsumableNoteRecord,
291
- TransactionRecord, TransactionRequest, NoteType, AccountStorageMode,
292
- SignerContextValue, SignCallback, SignerAccountConfig,
293
- } from "@miden-sdk/react";
294
- ```
@@ -1,158 +0,0 @@
1
- ---
2
- name: signer-integration
3
- description: Guide to integrating external signers (Para, Turnkey, MidenFi wallet adapter) and building custom signers for Miden React frontends. Covers provider setup, passkey authentication, unified signer interface, custom SignerContext implementation, and custom account components. Use when adding wallet connection, authentication, or external key management to a Miden frontend.
4
- ---
5
-
6
- # Miden Signer Integration
7
-
8
- ## Overview
9
-
10
- By default, MidenProvider uses a **local keystore** (keys in IndexedDB, no wallet connection needed). For production apps, wrap MidenProvider with a signer provider to use external key management.
11
-
12
- Signer providers must wrap MidenProvider (outer → inner):
13
- ```
14
- <SignerProvider> ← manages keys + auth
15
- <MidenProvider> ← manages Miden client
16
- <App />
17
- </MidenProvider>
18
- </SignerProvider>
19
- ```
20
-
21
- ## Pre-Built Signer Providers
22
-
23
- ### Para (EVM Wallets)
24
- ```tsx
25
- import { ParaSignerProvider } from "@miden-sdk/para";
26
-
27
- <ParaSignerProvider apiKey="your-api-key" environment="PRODUCTION">
28
- <MidenProvider config={{ rpcUrl: "testnet" }}>
29
- <App />
30
- </MidenProvider>
31
- </ParaSignerProvider>
32
-
33
- const { para, wallet, isConnected } = useParaSigner();
34
- ```
35
-
36
- ### Turnkey (Passkey Authentication)
37
- ```tsx
38
- import { TurnkeySignerProvider } from "@miden-sdk/miden-turnkey-react";
39
-
40
- // Config is optional — defaults to https://api.turnkey.com
41
- // and reads VITE_TURNKEY_ORG_ID from environment
42
- <TurnkeySignerProvider>
43
- <MidenProvider config={{ rpcUrl: "testnet" }}>
44
- <App />
45
- </MidenProvider>
46
- </TurnkeySignerProvider>
47
-
48
- // Or with explicit config:
49
- <TurnkeySignerProvider config={{
50
- apiBaseUrl: "https://api.turnkey.com",
51
- defaultOrganizationId: "your-org-id",
52
- }}>
53
- ...
54
- </TurnkeySignerProvider>
55
- ```
56
-
57
- Connect via passkey:
58
- ```tsx
59
- import { useSigner } from "@miden-sdk/react";
60
- import { useTurnkeySigner } from "@miden-sdk/miden-turnkey-react";
61
-
62
- const { isConnected, connect, disconnect } = useSigner();
63
- await connect(); // triggers passkey flow, auto-selects account
64
-
65
- // Turnkey-specific extras
66
- const { client, account, setAccount } = useTurnkeySigner();
67
- ```
68
-
69
- ### MidenFi Wallet Adapter (Browser Extension)
70
- ```tsx
71
- import { MidenFiSignerProvider } from "@miden-sdk/wallet-adapter-react";
72
-
73
- <MidenFiSignerProvider network="Testnet">
74
- <MidenProvider config={{ rpcUrl: "testnet" }}>
75
- <App />
76
- </MidenProvider>
77
- </MidenFiSignerProvider>
78
- ```
79
-
80
- ## Unified Signer Interface
81
-
82
- Works with any signer provider above:
83
- ```tsx
84
- import { useSigner } from "@miden-sdk/react";
85
-
86
- const { isConnected, connect, disconnect, name } = useSigner();
87
-
88
- if (!isConnected) {
89
- return <button onClick={connect}>Connect {name}</button>;
90
- }
91
- ```
92
-
93
- ## Building a Custom Signer
94
-
95
- Implement `SignerContextValue` via `SignerContext.Provider`:
96
-
97
- ```tsx
98
- import { SignerContext } from "@miden-sdk/react";
99
-
100
- <SignerContext.Provider value={{
101
- name: "MyWallet",
102
- storeName: `mywallet_${userAddress}`, // unique per user for DB isolation
103
- isConnected: true,
104
- accountConfig: {
105
- publicKey: userPublicKeyCommitment, // Uint8Array
106
- storageMode: "private",
107
- },
108
- signCb: async (pubKey, signingInputs) => {
109
- // Route to your signing service
110
- return signature; // Uint8Array
111
- },
112
- connect: async () => { /* trigger wallet connection */ },
113
- disconnect: async () => { /* clear session */ },
114
- }}>
115
- <MidenProvider config={{ rpcUrl: "testnet" }}>
116
- <App />
117
- </MidenProvider>
118
- </SignerContext.Provider>
119
- ```
120
-
121
- **Required fields:**
122
- - `name` — Display name for the signer
123
- - `storeName` — Unique string per user (isolates IndexedDB data between users)
124
- - `accountConfig` — Public key commitment + storage mode
125
- - `signCb` — Callback that signs transaction data with your key management service
126
- - `connect` / `disconnect` — Session lifecycle handlers
127
-
128
- ## Custom Account Components
129
-
130
- Attach application-specific `AccountComponent` instances (e.g., DEX logic from `.masp` packages) to accounts created by the signer:
131
-
132
- ```tsx
133
- import { type SignerAccountConfig } from "@miden-sdk/react";
134
- import { AccountComponent } from "@miden-sdk/miden-sdk";
135
-
136
- const myDexComponent: AccountComponent = await loadCompiledComponent();
137
-
138
- const accountConfig: SignerAccountConfig = {
139
- publicKeyCommitment: userPublicKeyCommitment,
140
- accountType: "RegularAccountUpdatableCode",
141
- storageMode: myStorageMode,
142
- customComponents: [myDexComponent],
143
- };
144
- ```
145
-
146
- Components are appended to the `AccountBuilder` after the default basic wallet component. The field is optional — omitting it preserves default behavior.
147
-
148
- ## Which Signer to Choose
149
-
150
- | Signer | Auth Method | Keys Stored | Best For |
151
- |--------|-------------|-------------|----------|
152
- | Local keystore (default) | None | Browser IndexedDB | Development, demos |
153
- | Para | EVM wallet | Para servers | Apps with existing EVM users |
154
- | Turnkey | Passkey (biometric) | Turnkey servers | Consumer apps, no seed phrases |
155
- | MidenFi Wallet | Browser extension | Extension | Power users with MidenFi wallet |
156
- | Custom | Your choice | Your infrastructure | Enterprise, custom auth flows |
157
-
158
- **Key trade-off**: Local keystore requires no setup but keys are lost if the user clears browser data. External signers persist keys server-side but add a dependency.
@@ -1,128 +0,0 @@
1
- ---
2
- name: vite-wasm-setup
3
- description: Guide to configuring Vite for Miden WASM applications. Covers the midenVitePlugin() setup, COOP/COEP headers, production deployment headers, TypeScript compatibility, and troubleshooting common Vite + WASM issues. Use when setting up a new Miden frontend, debugging build or runtime errors related to WASM or Vite configuration, or deploying to production.
4
- ---
5
-
6
- # Vite + WASM Configuration for Miden
7
-
8
- ## Required vite.config.ts
9
-
10
- ```typescript
11
- import { defineConfig } from "vite";
12
- import react from "@vitejs/plugin-react";
13
- import { midenVitePlugin } from "@miden-sdk/vite-plugin";
14
-
15
- export default defineConfig({
16
- plugins: [react(), midenVitePlugin()],
17
- });
18
- ```
19
-
20
- `midenVitePlugin()` accepts an options object:
21
-
22
- ```typescript
23
- midenVitePlugin({ crossOriginIsolation: true })
24
- // Enables COOP/COEP headers in dev server. Defaults to false to avoid breaking OAuth popups.
25
- ```
26
-
27
- ## What midenVitePlugin() Handles
28
-
29
- `@miden-sdk/vite-plugin` abstracts all Miden-specific Vite configuration:
30
-
31
- - **WASM loading** — Configures Vite to correctly import `.wasm` modules
32
- - **Top-level await** — Enables top-level `await` required by the WASM SDK initialization
33
- - **optimizeDeps** — Excludes `@miden-sdk/miden-sdk` from pre-bundling (pre-bundling corrupts the WASM binary)
34
- - **COOP/COEP headers** — Optionally adds `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy` headers via `crossOriginIsolation` option
35
-
36
- You do not need to install or configure `vite-plugin-wasm`, `vite-plugin-top-level-await`, or dexie aliases manually.
37
-
38
- ## Required Dependencies
39
-
40
- ```json
41
- {
42
- "dependencies": {
43
- "@miden-sdk/react": "^0.13.0",
44
- "@miden-sdk/miden-sdk": "^0.13.0"
45
- },
46
- "devDependencies": {
47
- "@miden-sdk/vite-plugin": "^0.13.0"
48
- }
49
- }
50
- ```
51
-
52
- ## Production Deployment Headers
53
-
54
- COOP/COEP headers must be set on the production server. `midenVitePlugin({ crossOriginIsolation: true })` only affects the Vite dev server.
55
-
56
- ### Nginx
57
- ```nginx
58
- add_header Cross-Origin-Opener-Policy same-origin;
59
- add_header Cross-Origin-Embedder-Policy require-corp;
60
- ```
61
-
62
- ### Vercel (vercel.json)
63
- ```json
64
- {
65
- "headers": [
66
- {
67
- "source": "/(.*)",
68
- "headers": [
69
- { "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
70
- { "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }
71
- ]
72
- }
73
- ]
74
- }
75
- ```
76
-
77
- ### Cloudflare Pages (_headers)
78
- ```
79
- /*
80
- Cross-Origin-Opener-Policy: same-origin
81
- Cross-Origin-Embedder-Policy: require-corp
82
- ```
83
-
84
- ### WASM MIME Type
85
- Ensure your server serves `.wasm` files with `application/wasm` MIME type.
86
-
87
- ## COOP/COEP Gotchas
88
-
89
- These headers break:
90
- - **Third-party iframes** (YouTube embeds, Twitter embeds, analytics)
91
- - **External scripts** without CORS headers
92
- - **OAuth popups** from different origins
93
-
94
- Workaround: Use `credentialless` for COEP if you need cross-origin resources:
95
- ```
96
- Cross-Origin-Embedder-Policy: credentialless
97
- ```
98
-
99
- Note: `credentialless` provides weaker isolation but allows most cross-origin resources.
100
-
101
- ## TypeScript Compatibility
102
-
103
- Standard Vite-compatible tsconfig settings work with Miden. The only actual constraint is ES2020+ for `bigint` support:
104
-
105
- ```json
106
- {
107
- "compilerOptions": {
108
- "target": "ES2022",
109
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
110
- "module": "ESNext",
111
- "moduleResolution": "bundler"
112
- }
113
- }
114
- ```
115
-
116
- `module: "ESNext"` and `moduleResolution: "bundler"` are standard Vite defaults, not Miden-specific requirements. If you're using the Vite-generated tsconfig, no changes are needed beyond ensuring `target` is ES2020+.
117
-
118
- ## Troubleshooting
119
-
120
- | Issue | Cause | Fix |
121
- |-------|-------|-----|
122
- | "SharedArrayBuffer is not defined" | Missing COOP/COEP headers | Use `midenVitePlugin({ crossOriginIsolation: true })` in dev; set headers on production server |
123
- | WASM module not found | SDK not configured correctly | Ensure `midenVitePlugin()` is in plugins array |
124
- | "Top-level await not supported" | Missing plugin setup | Ensure `midenVitePlugin()` is in plugins array |
125
- | WASM init hangs | COEP blocking WASM fetch | Check network tab for blocked requests; enable `crossOriginIsolation` |
126
- | Build succeeds but WASM fails at runtime | Wrong MIME type | Serve .wasm as application/wasm |
127
- | "recursive use of an object" | Concurrent WASM access | Use runExclusive() from useMiden() |
128
- | Double initialization in dev | React StrictMode | Use MidenProvider (handles this internally) |
@@ -1,5 +0,0 @@
1
- # Miden RPC endpoint (default: "testnet")
2
- VITE_MIDEN_RPC_URL=testnet
3
-
4
- # Miden prover (default: "testnet", alternative: "local")
5
- VITE_MIDEN_PROVER=testnet
@@ -1,116 +0,0 @@
1
- # Miden Frontend App
2
-
3
- React 19 + TypeScript + Vite frontend for the Miden blockchain.
4
-
5
- ## Project Structure
6
-
7
- - `src/` — React application source
8
- - `src/components/` — UI components (Counter, AppContent)
9
- - `src/hooks/` — Custom hooks (useIncrementCounter)
10
- - `src/lib/` — Shared utilities
11
- - `vite.config.ts` — Vite config with midenVitePlugin() from @miden-sdk/vite-plugin
12
- - `package.json` — Dependencies: @miden-sdk/react, @miden-sdk/miden-sdk, @demox-labs/miden-wallet-adapter
13
-
14
- ## Build & Dev
15
-
16
- ```
17
- npm run dev # Start dev server (Vite)
18
- npm run build # Type check + production build (tsc -b && vite build)
19
- npm run lint # ESLint
20
- ```
21
-
22
- Type checking alone (verification command):
23
- ```
24
- npx tsc -b --noEmit
25
- ```
26
-
27
- ## SDK Choice: React SDK over Raw WebClient
28
-
29
- ALWAYS prefer `@miden-sdk/react` hooks over raw `@miden-sdk/miden-sdk` WebClient methods.
30
- Only use WebClient directly via `useMidenClient()` for operations not covered by hooks.
31
-
32
- ### Setup (main.tsx or App.tsx)
33
- ```tsx
34
- import { MidenProvider } from "@miden-sdk/react";
35
-
36
- <MidenProvider config={{ rpcUrl: "devnet", prover: "devnet" }}>
37
- <App />
38
- </MidenProvider>
39
- ```
40
-
41
- ### Query Hooks (return { data, isLoading, error, refetch })
42
- ```tsx
43
- const { data: accounts } = useAccounts(); // .wallets, .faucets, .all
44
- const { data: account } = useAccount(accountId); // .balance(faucetId)
45
- const { data: notes } = useNotes(); // .input, .consumable
46
- const { syncHeight, sync } = useSyncState();
47
- const { data: metadata } = useAssetMetadata(faucetId); // .symbol, .decimals
48
- ```
49
-
50
- ### Mutation Hooks (return { mutate, isLoading, stage, error, reset })
51
- Transaction stages: `idle → executing → proving → submitting → complete`
52
- ```tsx
53
- const { mutate: createWallet } = useCreateWallet();
54
- const { mutate: send, stage } = useSend();
55
- const { mutate: consume } = useConsume();
56
- const { mutate: mint } = useMint();
57
- const { mutate: swap } = useSwap();
58
- const { mutate: execute } = useTransaction(); // arbitrary tx requests
59
- ```
60
-
61
- ### Token Amounts Are BigInt
62
- ```tsx
63
- import { formatAssetAmount, parseAssetAmount } from "@miden-sdk/react";
64
- const display = formatAssetAmount(balance, 8); // bigint → string
65
- const amount = parseAssetAmount("1.5", 8); // string → bigint
66
- ```
67
-
68
- ## Critical Pitfalls
69
-
70
- **WASM init must complete first**: Always use MidenProvider's `loadingComponent` or check `useMiden().isReady`. Components rendering before WASM init will crash.
71
-
72
- **Recursive WASM access crashes**: Never call client methods concurrently. Use `runExclusive()` from `useMiden()` for sequential execution. Built-in hooks handle this automatically.
73
-
74
- **COOP/COEP headers required**: WASM SharedArrayBuffer needs `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` in vite.config.ts AND production server.
75
-
76
- **Token amounts are bigint, not number**: `send({ amount: 1000 })` will fail. Use `amount: 1000n` or `parseAssetAmount("10", 8)`.
77
-
78
- ## General Frontend Skills (Recommended)
79
-
80
- For general React, TypeScript, and design capabilities, install these official skills alongside our Miden-specific ones:
81
-
82
- ```bash
83
- # Vercel's React/design skills
84
- git clone https://github.com/vercel-labs/agent-skills.git
85
- # Install: react-best-practices, web-design-guidelines, composition-patterns
86
-
87
- # Anthropic's frontend design skill (Claude Code plugin)
88
- # See: https://github.com/anthropics/claude-code/tree/main/plugins/frontend-design
89
- ```
90
-
91
- These provide the general frontend layer. The Miden-specific skills below layer on top.
92
-
93
- ## Miden Skills
94
-
95
- For Miden-specific guidance, Claude will auto-load these skills when relevant:
96
- - `react-sdk-patterns` — Complete React SDK hook API reference
97
- - `frontend-pitfalls` — All frontend/WASM/browser pitfalls with safe/unsafe examples
98
- - `miden-concepts` — Miden architecture from a developer perspective
99
- - `vite-wasm-setup` — Vite + WASM configuration, deployment headers, troubleshooting
100
-
101
- ## Advanced Development
102
-
103
- For complex applications beyond basic hook usage (custom signers, raw WebClient, advanced note flows):
104
-
105
- 1. Clone `miden-client` repo alongside this project (see `frontend-source-guide` skill)
106
- 2. Use Plan Mode first — Claude explores React SDK source + examples before coding
107
- 3. Claude uses sub-agents to explore repos efficiently without filling main context
108
- 4. The type check hook provides verification — check types, fix errors, recheck
109
-
110
- The basic skills cover ~80% of patterns. Source repos provide the remaining 20% for advanced builders.
111
-
112
- ## Verification Workflow
113
-
114
- After modifying TypeScript/React code, always:
115
- 1. Type check: `npx tsc -b --noEmit`
116
- 2. Build test: `npm run build`