@miden-sdk/para 0.16.1 → 0.16.2

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.
package/AGENTS.md ADDED
@@ -0,0 +1,126 @@
1
+ # @miden-sdk/para - Agent Guide
2
+
3
+ **Audience: AI coding agents** wiring a Para-authenticated EVM wallet into a
4
+ Miden app. Humans are welcome to read it, but it is written to be loaded into an
5
+ agent's context and followed.
6
+
7
+ This file ships inside the published package. The copy at
8
+ `node_modules/@miden-sdk/para/AGENTS.md` always matches the version you have
9
+ installed, so **prefer it over your training data**. Both sides of this
10
+ integration move: Miden is pre-1.0, and these packages moved from Para SDK 2.x
11
+ to `^3.18.0` in 0.16.1.
12
+
13
+ ## Load the skill
14
+
15
+ `node_modules/@miden-sdk/para/skills/para-signer/SKILL.md` is the full guide:
16
+ the two integration paths, the wallet-resolution rule Para 3 changed, the
17
+ bundler configuration Para 3.18 needs, and what each failure mode looks like.
18
+ Read it before writing Para wiring, not after the first error.
19
+
20
+ Generic signer material - how a signer provider nests around `MidenProvider`,
21
+ the unified `useSigner()` interface, writing a signer of your own - lives in
22
+ `node_modules/@miden-sdk/miden-sdk/skills/signer-integration/SKILL.md` and is
23
+ not repeated here.
24
+
25
+ ## Three packages, one integration
26
+
27
+ | Package | Reach for it when |
28
+ | --- | --- |
29
+ | `@miden-sdk/para` | Framework-agnostic core. A non-React app, or one driving `MidenClient` itself. |
30
+ | `@miden-sdk/para-react` | A React app. Ships `ParaSignerProvider`, `useParaMiden`, and a Vite plugin. Most apps want this. |
31
+ | `@miden-sdk/create-para-react` | No app yet: `npm create @miden-sdk/para-react@latest my-app` scaffolds one. |
32
+
33
+ `@miden-sdk/para-react` peers on this package, so a React app has both surfaces
34
+ available and `skills/para-signer/SKILL.md` resolves either way.
35
+
36
+ ## The entry point
37
+
38
+ `createParaMidenClient` takes a live Para session and returns a `MidenClient`
39
+ whose keystore signs through Para, plus the id of the Miden account derived from
40
+ the chosen wallet:
41
+
42
+ ```ts
43
+ import { createParaMidenClient } from "@miden-sdk/para";
44
+
45
+ const { client, accountId } = await createParaMidenClient(
46
+ para, // ParaWeb, from @getpara/web-sdk
47
+ wallets, // the session's wallets; EVM entries are selected from these
48
+ { endpoint: "https://rpc.testnet.miden.io", storageMode: "public" }
49
+ );
50
+ ```
51
+
52
+ It resolves the EVM wallets, asks the user to pick one when there is more than
53
+ one, builds the client with `MidenClient.create({ ..., keystore })`, and then
54
+ imports or creates the Miden account for that wallet's public key before
55
+ returning. No Miden private key exists anywhere: the account's auth component
56
+ commits to the Para-held EVM key.
57
+
58
+ The third argument is `Opts`: `endpoint` (the RPC URL, not `rpcUrl`),
59
+ `noteTransportUrl` (defaults to `https://transport.miden.io`), `seed` (client
60
+ store seed), `accountSeed`, and the required `storageMode`, which is `"public"`
61
+ or `"private"`. Two optional arguments follow it: `showSigningModal` (default
62
+ `true`) and `customSignConfirmStep`.
63
+
64
+ The rest of the public surface is the pieces that call is assembled from, for
65
+ when you are wiring a signer yourself rather than taking the whole client:
66
+
67
+ | Export | What it is |
68
+ | --- | --- |
69
+ | `signCb(para, wallet, showSigningModal, customSignConfirmStep?)` | Builds the `(publicKey, signingInputs) => Promise<Uint8Array>` callback a `MidenClient` keystore or a React `SignerContext` wants. |
70
+ | `resolveEvmWallets(para, wallets)` | Narrows a wallet list to full EVM `Wallet` records. Read the rule below before skipping it. |
71
+ | `getUncompressedPublicKeyFromWallet(para, wallet)` | The wallet's uncompressed key, falling back to `para.issueJwt()` when the record carries none. Throws rather than returning `undefined`. |
72
+ | `evmPkToCommitment(uncompressedPublicKey)` | The Miden public-key commitment for that key. |
73
+ | types | `Opts`, `MidenAccountOpts`, `MidenAccountStorageMode`, `TxSummaryJson`, `CustomSignConfirmStep` |
74
+
75
+ The confirmation modals are internal: they are not exported, and you replace
76
+ them with `showSigningModal: false` plus your own `customSignConfirmStep`, not
77
+ by importing them.
78
+
79
+ ## Rules that are easy to get wrong
80
+
81
+ **Resolve wallets through Para, not through `embedded.wallets`.** Para 3's
82
+ `useAccount().embedded.wallets` is `AvailableWallet[]` and omits `publicKey`.
83
+ Handing those records straight to the signing path costs an `issueJwt()` round
84
+ trip on every account bootstrap, and fails outright when the JWT has no entry
85
+ for the wallet. `resolveEvmWallets` prefers `para.getWalletsByType("EVM")`,
86
+ which returns full `Wallet` records, and falls back to filtering the list you
87
+ passed when the client does not expose it. `createParaMidenClient` already does
88
+ this for you.
89
+
90
+ **`storageMode: "private"` requires `accountSeed`.** Without one the call throws
91
+ before any client is built, because a private account that cannot be
92
+ regenerated from a seed is unrecoverable.
93
+
94
+ **A 0.15 account does not survive the upgrade.** `evmPkToCommitment` hashes the
95
+ affine point as Poseidon2 over 16 field elements - the x coordinate then the y
96
+ coordinate, each as eight 32-bit limbs, least significant limb first. 0.15
97
+ hashed a different preimage (nine felts packed from the 33-byte compressed SEC1
98
+ encoding), so the same EVM key yields a different account id and a different
99
+ commitment on 0.16. Treat it as a new account, not a migration.
100
+
101
+ **This path touches the DOM.** The account picker and the signing confirmation
102
+ are plain DOM overlays. They are guarded on `typeof document`, so on a server
103
+ the picker resolves to the first wallet and the signing prompt auto-approves.
104
+ Never run this flow server-side expecting a human in the loop. The picker is
105
+ also skipped when exactly one EVM wallet resolves.
106
+
107
+ **Para 3.18 needs bundler help.** `@getpara/react-core` lazily imports the
108
+ optional `@getpara/aa-*` account-abstraction connectors and the Solana and
109
+ Cosmos connectors. Vite's dependency pre-bundling resolves those specifiers
110
+ even though nothing calls them, so a build fails unless they are stubbed. The
111
+ `paraVitePlugin` exported from `@miden-sdk/para-react/vite` does exactly that;
112
+ the skill covers the non-Vite case.
113
+
114
+ ## Going deeper
115
+
116
+ - The React surface documents itself at
117
+ `node_modules/@miden-sdk/para-react/AGENTS.md`.
118
+ - The client this wraps documents itself at
119
+ `node_modules/@miden-sdk/miden-sdk/AGENTS.md`, with narrative docs at
120
+ <https://docs.miden.xyz/builder/tools/clients/web-client/>.
121
+ - Para's own SDK documentation: <https://docs.getpara.com>.
122
+ - Breaking changes and migration notes, worth reading at upgrade time: the
123
+ `CHANGELOG.md` in [`0xMiden/web-sdk`](https://github.com/0xMiden/web-sdk).
124
+ - The type declarations shipped in `dist/` are authoritative for signatures.
125
+ When this guide and the types disagree, the types are right and this file is a
126
+ bug - please report it.
package/README.md CHANGED
@@ -1,49 +1,52 @@
1
1
  # @miden-sdk/para
2
2
 
3
- [![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/0xMiden/miden-para/blob/main/LICENSE)
4
- [![test](https://github.com/0xMiden/miden-para/actions/workflows/test.yml/badge.svg)](https://github.com/0xMiden/miden-para/actions/workflows/test.yml)
5
- [![build](https://github.com/0xMiden/miden-para/actions/workflows/build.yml/badge.svg)](https://github.com/0xMiden/miden-para/actions/workflows/build.yml)
3
+ [![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/0xMiden/web-sdk/blob/main/LICENSE.md)
6
4
 
7
- This is the Miden x Para SDK integration. Below, you'll find instructions for local building and linking the library. If you're looking for React integration, see [Miden x Para x React](./packages/use-miden-para-react/README.md) (package `@miden-sdk/para-react`). If you want to scaffold a fresh Vite `react-ts` app with our Vite config baked in, check [create-miden-para-react](./packages/create-miden-para-react/README.md) (package `@miden-sdk/create-para-react`).
5
+ The Miden x Para integration: build a Miden account from a Para-managed EVM
6
+ wallet and sign Miden transactions through Para.
8
7
 
9
- ## Requirements
10
-
11
- - **Yarn 1.22.22** (enforced via `packageManager` field)
12
- - Node.js (compatible with your project)
13
- - A Para API key. **Production deployments require a Para production API key**; use a non-prod key for local/dev.
8
+ For the React bindings see [`@miden-sdk/para-react`](https://www.npmjs.com/package/@miden-sdk/para-react),
9
+ which is where `ParaSignerProvider` and the hooks live. To scaffold a fresh Vite
10
+ `react-ts` app with the Miden and Para config already wired, use
11
+ [`@miden-sdk/create-para-react`](https://www.npmjs.com/package/@miden-sdk/create-para-react).
14
12
 
15
- This project uses Yarn 1.22.22. The version is locked in `package.json` and will be automatically enforced by modern package managers that support the `packageManager` field.
13
+ ## Agent guidance
16
14
 
17
- ## Peer Dependencies
15
+ If you are an AI coding agent, read
16
+ `node_modules/@miden-sdk/para/AGENTS.md` and
17
+ `node_modules/@miden-sdk/para/skills/para-signer/SKILL.md` before writing code
18
+ against this package. They ship in this tarball, so they match the version you
19
+ have installed.
18
20
 
19
- `@miden-sdk/para` expects these packages to be provided by the consuming app. Install matching versions alongside this package to avoid duplicate copies:
21
+ ## Requirements
20
22
 
21
- - `@miden-sdk/miden-sdk@^0.13.0`
22
- - `@getpara/web-sdk@^3.18.0`
23
+ - Node.js >= 20.
24
+ - A Para API key. **Production deployments require a Para production API key**;
25
+ use a non-production key for local and development work.
23
26
 
24
- Example install:
27
+ ## Installation
25
28
 
26
29
  ```bash
27
- yarn add @miden-sdk/para @miden-sdk/miden-sdk@^0.16.1 @getpara/web-sdk@^3.18.0
30
+ pnpm add @miden-sdk/para @miden-sdk/miden-sdk @getpara/web-sdk
28
31
  ```
29
32
 
30
- When creating a client with `storageMode` set to `private`, supply an `accountSeed`; the initializer will throw if it is missing so that private accounts remain recoverable.
33
+ ## Peer dependencies
31
34
 
32
- ## Installation
35
+ `@miden-sdk/para` expects these to be provided by the consuming app. Install
36
+ matching versions alongside it so no duplicate copy of the SDK is resolved:
33
37
 
34
- ```bash
35
- yarn install
36
- ```
38
+ - `@miden-sdk/miden-sdk@^0.16.1`
39
+ - `@getpara/web-sdk@^3.18.0`
37
40
 
38
- ## Building
41
+ Para SDK 3.18 is required as of 0.16.1; the 2.x range no longer satisfies the
42
+ peer.
39
43
 
40
- ```bash
41
- yarn build
42
- ```
44
+ When creating a client with `storageMode` set to `private`, supply an
45
+ `accountSeed`. The initializer throws if it is missing, so that private accounts
46
+ stay recoverable.
43
47
 
44
- ## Publishing to npm
48
+ ## Contributing
45
49
 
46
- 1. Update the version in `package.json` (the published package is `@miden-sdk/para`).
47
- 2. Authenticate with npm if needed: `npm login`.
48
- 3. Publish: `npm run publish`. The `prepack` hook rebuilds `dist/` and the `postpack` hook moves the generated tarball into `build/`.
49
- 4. (Optional) Inspect the packed artifact without publishing via `npm pack` and check `build/` for the resulting `miden-sdk-miden-para-<version>.tgz`.
50
+ This package is developed in the [`0xMiden/web-sdk`](https://github.com/0xMiden/web-sdk)
51
+ monorepo under `packages/para/core`, and is released from it. See that repo's
52
+ `CONTRIBUTING.md` and `AGENTS.md` for the build, test and release flow.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miden-sdk/para",
3
- "version": "0.16.1",
3
+ "version": "0.16.2",
4
4
  "type": "commonjs",
5
5
  "description": "Miden x Para Integration",
6
6
  "license": "MIT",
@@ -29,11 +29,11 @@
29
29
  "react": "^19.2.0",
30
30
  "react-test-renderer": "^19.2.0",
31
31
  "typescript": "^5.8.3",
32
- "@miden-sdk/miden-sdk": "0.16.1"
32
+ "@miden-sdk/miden-sdk": "0.16.2"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@getpara/web-sdk": "^3.18.0",
36
- "@miden-sdk/miden-sdk": "^0.16.1"
36
+ "@miden-sdk/miden-sdk": "^0.16.2"
37
37
  },
38
38
  "exports": {
39
39
  ".": {
@@ -50,7 +50,9 @@
50
50
  "files": [
51
51
  "dist",
52
52
  "package.json",
53
- "docs/INTEGRATIONS.md"
53
+ "README.md",
54
+ "AGENTS.md",
55
+ "skills"
54
56
  ],
55
57
  "main": "dist/cjs/index.js",
56
58
  "module": "dist/esm/index.js",
@@ -0,0 +1,212 @@
1
+ ---
2
+ name: para-signer
3
+ description: Wiring Para (getpara.com) wallets into a Miden app with @miden-sdk/para and @miden-sdk/para-react. Covers the two integration paths (ParaSignerProvider vs createParaMidenClient/useParaMiden), Para 3 EVM wallet resolution, the signing and account-commitment model, the bundler stubs Para 3.18 needs, and the errors each mistake produces. Use when adding Para authentication, debugging a Para-backed signer, or upgrading a Para integration from Para SDK 2.x.
4
+ ---
5
+
6
+ # Para Signer Integration
7
+
8
+ Generic signer material - why a signer provider wraps `MidenProvider`, the
9
+ unified `useSigner()` interface, writing a signer of your own - is in
10
+ `node_modules/@miden-sdk/miden-sdk/skills/signer-integration/SKILL.md`. This
11
+ skill is only the Para-specific half.
12
+
13
+ ## The packages
14
+
15
+ | Package | Contains |
16
+ | --- | --- |
17
+ | `@miden-sdk/para` | Framework-agnostic core: `createParaMidenClient`, `signCb`, `resolveEvmWallets`, `getUncompressedPublicKeyFromWallet`, `evmPkToCommitment`. |
18
+ | `@miden-sdk/para-react` | React: `ParaSignerProvider`, `useParaSigner`, `useParaMiden`, and `paraVitePlugin` on the `./vite` entry. |
19
+ | `@miden-sdk/create-para-react` | `npm create @miden-sdk/para-react@latest my-app`. |
20
+
21
+ As of 0.16.1 all three peer on Para SDK 3.18 (`@getpara/web-sdk` and
22
+ `@getpara/react-sdk-lite` at `^3.18.0`). The 2.x range is dropped and will not
23
+ satisfy the peer.
24
+
25
+ ## Pick one path
26
+
27
+ **`ParaSignerProvider`** is the default for a React app. It publishes a
28
+ `SignerContext`, so every `@miden-sdk/react` hook signs through Para with no
29
+ further wiring, and `MidenProvider` manages the single client.
30
+
31
+ **`createParaMidenClient`** (or its hook wrapper `useParaMiden`) builds and
32
+ returns a `MidenClient` of its own. Use it in a non-React app, or when you are
33
+ driving the client directly and there is no `MidenProvider`.
34
+
35
+ Never both in one app: each owns a WASM-backed client, with its own store and
36
+ its own account bootstrap, and concurrent access to the WASM module crashes.
37
+
38
+ ### Path A: ParaSignerProvider
39
+
40
+ ```tsx
41
+ import { ParaSignerProvider, useParaSigner } from "@miden-sdk/para-react";
42
+ import { MidenProvider, useSigner, useMiden } from "@miden-sdk/react";
43
+
44
+ <ParaSignerProvider apiKey={apiKey} environment="BETA" appName="My App">
45
+ <MidenProvider config={{ rpcUrl: "testnet" }}>
46
+ <App />
47
+ </MidenProvider>
48
+ </ParaSignerProvider>;
49
+ ```
50
+
51
+ | Prop | Default | Notes |
52
+ | --- | --- | --- |
53
+ | `apiKey` | required | Para API key. Production deployments need a production key. |
54
+ | `environment` | required | `"BETA"`, `"PROD"`, `"SANDBOX"`, `"DEV"`, `"DEVELOPMENT"` or `"PRODUCTION"`. The last two are used directly when the Para build defines them, and fall back to `BETA` and `PROD` when it does not. |
55
+ | `appName` | `"Miden App"` | Shown in the Para modal. |
56
+ | `showSigningModal` | `true` | The built-in transaction confirmation overlay. |
57
+ | `customSignConfirmStep` | none | `(txSummaryJson) => Promise<unknown>`, run after the built-in modal and before Para signs. Throw to abort. |
58
+ | `queryClient` | internal | Pass yours to share one React Query client. |
59
+ | `paraProviderConfig` | none | Merged into `ParaProvider`: OAuth methods, external wallets, everything else Para exposes. |
60
+ | `customComponents` | none | Extra `AccountComponent`s, forwarded into `accountConfig`. |
61
+ | `importAccountId` | none | Import this account instead of building one. |
62
+
63
+ The provider renders `QueryClientProvider` and Para's `ParaProvider` itself and
64
+ imports `@getpara/react-sdk-lite/styles.css`. Do not wrap it with either again.
65
+
66
+ What it puts on the context: `name: "Para"`, `storeName: para_<walletId>` (so
67
+ two Para users on one browser do not share an IndexedDB store), a `signCb` bound
68
+ to the resolved wallet, and an `accountConfig` whose `publicKeyCommitment` is
69
+ the serialized commitment for that wallet's EVM key. **The storage mode is
70
+ always public.** There is no prop to make the signer's account private; use path
71
+ B with `storageMode: "private"` if you need that.
72
+
73
+ `connect()` opens the Para modal and `disconnect()` logs out of both the React
74
+ SDK and the Para client. `useParaSigner()` adds `{ para, wallet, isConnected }`
75
+ and throws outside the provider. `useModal` and `useLogout` are re-exported from
76
+ `@getpara/react-sdk-lite`.
77
+
78
+ Before the wallet connects, the provider publishes a deliberate
79
+ `isConnected: false` placeholder rather than `null`. That is what keeps
80
+ `MidenProvider` from building a local-keystore client - and touching WASM -
81
+ while the provider is still deriving the commitment. Do not "simplify" it to
82
+ `null`.
83
+
84
+ ### Path B: createParaMidenClient
85
+
86
+ ```ts
87
+ import { createParaMidenClient } from "@miden-sdk/para";
88
+
89
+ const { client, accountId } = await createParaMidenClient(
90
+ para, // ParaWeb
91
+ wallets, // session wallets; EVM entries are selected from these
92
+ { endpoint: "https://rpc.testnet.miden.io", storageMode: "public" },
93
+ true, // showSigningModal
94
+ confirmTx // optional customSignConfirmStep
95
+ );
96
+ ```
97
+
98
+ `Opts` fields: `endpoint` (the RPC URL - the field is not called `rpcUrl`),
99
+ `noteTransportUrl` (default `https://transport.miden.io`; `nodeTransportUrl` is
100
+ a deprecated alias), `seed` (client store seed), `accountSeed`, and the required
101
+ `storageMode` (`"public"` or `"private"`).
102
+
103
+ In React, `useParaMiden(nodeUrl, storageMode?, opts?, showSigningModal?, customSignConfirmStep?)`
104
+ wraps the same call under a Para `ParaProvider` ancestor and returns
105
+ `{ client, accountId, error, para, evmWallets, nodeUrl, opts }`. `client` is
106
+ `null` until the session resolves, it is held in a ref so re-renders do not
107
+ rebuild it, and setup failures land on `error` instead of throwing.
108
+
109
+ Both forms open DOM overlays: an account picker when more than one EVM wallet
110
+ resolves, and a confirmation per signature unless `showSigningModal` is `false`.
111
+ Both are guarded on `typeof document`, so server-side the picker silently
112
+ returns the first wallet and the signing prompt auto-approves. Do not run this
113
+ path on a server expecting a human in the loop.
114
+
115
+ ## Resolve EVM wallets through Para, always
116
+
117
+ This is the single most common Para 3 defect. `useAccount().embedded.wallets`
118
+ is `AvailableWallet[]`: it has `id` and `type`, and it does **not** have
119
+ `publicKey`. Everything downstream needs the uncompressed public key, so a
120
+ record without one sends `getUncompressedPublicKeyFromWallet` down its
121
+ `para.issueJwt()` fallback, and that fails outright when the JWT carries no
122
+ entry for the wallet.
123
+
124
+ `resolveEvmWallets(para, wallets)` prefers `para.getWalletsByType("EVM")`, which
125
+ returns full `Wallet` records, intersects it with the list you passed, and falls
126
+ back to filtering that list when the client does not expose the method.
127
+ `createParaMidenClient` and `ParaSignerProvider` both call it. Call it yourself
128
+ before handing wallets to `signCb`.
129
+
130
+ ## The signing and commitment model
131
+
132
+ `signCb(para, wallet, showSigningModal, customSignConfirmStep?)` returns the
133
+ callback a `MidenClient` keystore or a `SignerContext` wants. Per signature it:
134
+
135
+ 1. deserializes the `SigningInputs` and takes `inputs.toCommitment()`;
136
+ 2. keccak-256 hashes that commitment;
137
+ 3. renders the transaction summary for confirmation, then runs
138
+ `customSignConfirmStep`;
139
+ 4. calls `para.signMessage({ walletId, messageBase64 })`;
140
+ 5. prefixes the signature with the ECDSA auth-scheme byte and returns the bytes
141
+ Miden expects.
142
+
143
+ Use it as-is. Hand-rolling the hash or the serialization is how "invalid
144
+ signature" bugs start.
145
+
146
+ The account's auth component commits to the EVM key through
147
+ `evmPkToCommitment`, which hashes the affine point as Poseidon2 over 16 field
148
+ elements: the x coordinate then the y coordinate, each as eight 32-bit limbs,
149
+ least significant limb first.
150
+
151
+ > **Upgrade trap.** 0.15 hashed a different preimage - nine felts packed from
152
+ > the 33-byte compressed SEC1 encoding. The same Para wallet therefore derives a
153
+ > different commitment, and a different account id, on 0.16. There is no
154
+ > migration: it is a new account.
155
+
156
+ Account bootstrap, for a public account, tries `client.accounts.import(account)`
157
+ first and only inserts a fresh one when nothing was on chain. That is what makes
158
+ a second login on a new device pick the existing account up rather than
159
+ submitting a zero-nonce duplicate. A private account cannot be recovered that
160
+ way, which is why `storageMode: "private"` without `accountSeed` throws before
161
+ any client is built.
162
+
163
+ ## Bundler setup
164
+
165
+ `@getpara/react-core` lazily imports optional connectors that almost nobody
166
+ installs: the ten `@getpara/aa-*` account-abstraction packages, plus
167
+ `@getpara/solana-wallet-connectors` and `@getpara/cosmos-wallet-connectors`.
168
+ Lazy or not, a bundler still resolves the specifier, so the build fails on
169
+ packages your app never calls.
170
+
171
+ On Vite, use the plugin:
172
+
173
+ ```ts
174
+ // vite.config.ts
175
+ import { paraVitePlugin } from "@miden-sdk/para-react/vite";
176
+ import { midenVitePlugin } from "@miden-sdk/vite-plugin";
177
+
178
+ export default defineConfig({
179
+ plugins: [react(), midenVitePlugin(), paraVitePlugin()],
180
+ });
181
+ ```
182
+
183
+ `paraVitePlugin()` returns an array of plugins (Vite flattens it) that stubs
184
+ those twelve packages at both the esbuild pre-bundling layer and Vite's own
185
+ resolver, dedupes `@getpara/web-sdk` and `@getpara/react-sdk-lite`, and adds
186
+ Node polyfills for `buffer`, `crypto`, `stream` and `util`. Override that list
187
+ with `paraVitePlugin({ polyfills: [...] })`. The polyfills come from
188
+ `vite-plugin-node-polyfills`, an optional peer resolved from your project's
189
+ `node_modules`: without it the plugin warns and returns the stubs alone.
190
+
191
+ On another bundler, reproduce the three requirements by hand: resolve those
192
+ twelve specifiers to an empty module, provide the four Node polyfills, and force
193
+ a single copy of each `@getpara/*` package.
194
+
195
+ ## What each failure looks like
196
+
197
+ | Message | Cause |
198
+ | --- | --- |
199
+ | `No EVM wallets provided` | The session has no EVM wallet, or a non-EVM list was passed. Check `type === "EVM"` and that Para finished connecting. |
200
+ | `Got invalid jwt token`, `Wallet Not Found in jwt data`, `Wallet in jwt data has no public key` | The wallet record had no `publicKey` and the JWT fallback could not supply one. Resolve wallets through `getWalletsByType("EVM")`. |
201
+ | `accountSeed is required when using private storage mode` | `storageMode: "private"` with no `accountSeed`. |
202
+ | `User cancelled signing` | The confirmation modal was declined. Expected, not a bug. |
203
+ | `useParaSigner must be used within ParaSignerProvider` | The hook is mounted outside the provider. |
204
+ | A build error naming `@getpara/aa-<something>` | The connector stubs are missing. See "Bundler setup". |
205
+ | The app connects to Para but the signer stays disconnected | `ParaSignerProvider` logs `Failed to build Para signer context:` and falls back to the disconnected context. The console error is the real one; it is usually public-key resolution. |
206
+ | `Output note <id> carries no asset data` | The transaction summary could not be rendered. Deliberate: the modal would otherwise print "Assets: None" for assets that are merely unknown. |
207
+
208
+ ## Environment
209
+
210
+ `VITE_PARA_API_KEY` is the convention across the examples and the scaffolded
211
+ template, read through `import.meta.env`. Use a non-production Para key for
212
+ local and dev work; production deployments need a production key.