@miden-sdk/use-miden-para-react 0.13.2 → 0.13.4

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/dist/index.d.mts CHANGED
@@ -7,6 +7,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
7
7
  import { ReactNode } from 'react';
8
8
  import { ParaWeb, Wallet } from '@getpara/web-sdk';
9
9
  import { QueryClient } from '@tanstack/react-query';
10
+ import { SignerAccountConfig } from '@miden-sdk/react';
10
11
 
11
12
  /**
12
13
  * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.
@@ -55,6 +56,8 @@ interface ParaSignerProviderProps {
55
56
  * Use this for customizing OAuth methods, external wallets, etc.
56
57
  */
57
58
  paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;
59
+ /** Optional custom account components to include in the account (e.g. from a compiled .masp package) */
60
+ customComponents?: SignerAccountConfig['customComponents'];
58
61
  }
59
62
  /**
60
63
  * Para-specific extras exposed via useParaSigner hook.
@@ -78,7 +81,7 @@ interface ParaSignerExtras {
78
81
  * </ParaSignerProvider>
79
82
  * ```
80
83
  */
81
- declare function ParaSignerProvider({ children, apiKey, environment, appName, showSigningModal, customSignConfirmStep, queryClient, paraProviderConfig, }: ParaSignerProviderProps): react_jsx_runtime.JSX.Element;
84
+ declare function ParaSignerProvider({ children, apiKey, environment, appName, showSigningModal, customSignConfirmStep, queryClient, paraProviderConfig, customComponents, }: ParaSignerProviderProps): react_jsx_runtime.JSX.Element;
82
85
  /**
83
86
  * Hook for Para-specific extras beyond the unified useSigner interface.
84
87
  * Use this to access the Para client or wallet details directly.
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
7
7
  import { ReactNode } from 'react';
8
8
  import { ParaWeb, Wallet } from '@getpara/web-sdk';
9
9
  import { QueryClient } from '@tanstack/react-query';
10
+ import { SignerAccountConfig } from '@miden-sdk/react';
10
11
 
11
12
  /**
12
13
  * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.
@@ -55,6 +56,8 @@ interface ParaSignerProviderProps {
55
56
  * Use this for customizing OAuth methods, external wallets, etc.
56
57
  */
57
58
  paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;
59
+ /** Optional custom account components to include in the account (e.g. from a compiled .masp package) */
60
+ customComponents?: SignerAccountConfig['customComponents'];
58
61
  }
59
62
  /**
60
63
  * Para-specific extras exposed via useParaSigner hook.
@@ -78,7 +81,7 @@ interface ParaSignerExtras {
78
81
  * </ParaSignerProvider>
79
82
  * ```
80
83
  */
81
- declare function ParaSignerProvider({ children, apiKey, environment, appName, showSigningModal, customSignConfirmStep, queryClient, paraProviderConfig, }: ParaSignerProviderProps): react_jsx_runtime.JSX.Element;
84
+ declare function ParaSignerProvider({ children, apiKey, environment, appName, showSigningModal, customSignConfirmStep, queryClient, paraProviderConfig, customComponents, }: ParaSignerProviderProps): react_jsx_runtime.JSX.Element;
82
85
  /**
83
86
  * Hook for Para-specific extras beyond the unified useSigner interface.
84
87
  * Use this to access the Para client or wallet details directly.
package/dist/index.js CHANGED
@@ -105,6 +105,7 @@ function useParaMiden(nodeUrl, storageMode = "public", opts = {}, showSigningMod
105
105
  }
106
106
 
107
107
  // src/ParaSignerProvider.tsx
108
+ var import_styles = require("@getpara/react-sdk-lite/styles.css");
108
109
  var import_react2 = require("react");
109
110
  var import_web_sdk = require("@getpara/web-sdk");
110
111
  var import_react_sdk_lite2 = require("@getpara/react-sdk-lite");
@@ -132,7 +133,8 @@ function ParaSignerProvider({
132
133
  showSigningModal = true,
133
134
  customSignConfirmStep,
134
135
  queryClient,
135
- paraProviderConfig
136
+ paraProviderConfig,
137
+ customComponents
136
138
  }) {
137
139
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: queryClient != null ? queryClient : defaultQueryClient, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
138
140
  import_react_sdk_lite2.ParaProvider,
@@ -148,6 +150,7 @@ function ParaSignerProvider({
148
150
  {
149
151
  showSigningModal,
150
152
  customSignConfirmStep,
153
+ customComponents,
151
154
  children
152
155
  }
153
156
  )
@@ -157,15 +160,21 @@ function ParaSignerProvider({
157
160
  function ParaSignerProviderInner({
158
161
  children,
159
162
  showSigningModal = true,
160
- customSignConfirmStep
163
+ customSignConfirmStep,
164
+ customComponents
161
165
  }) {
162
- const { openModal } = (0, import_react_sdk_lite2.useModal)();
166
+ var _a, _b;
167
+ const { openModal, closeModal } = (0, import_react_sdk_lite2.useModal)();
163
168
  const { logoutAsync } = (0, import_react_sdk_lite2.useLogout)();
164
169
  const openModalRef = (0, import_react2.useRef)(openModal);
170
+ const closeModalRef = (0, import_react2.useRef)(closeModal);
165
171
  const logoutAsyncRef = (0, import_react2.useRef)(logoutAsync);
166
172
  (0, import_react2.useEffect)(() => {
167
173
  openModalRef.current = openModal;
168
174
  }, [openModal]);
175
+ (0, import_react2.useEffect)(() => {
176
+ closeModalRef.current = closeModal;
177
+ }, [closeModal]);
169
178
  (0, import_react2.useEffect)(() => {
170
179
  logoutAsyncRef.current = logoutAsync;
171
180
  }, [logoutAsync]);
@@ -182,49 +191,21 @@ function ParaSignerProviderInner({
182
191
  (0, import_react2.useEffect)(() => {
183
192
  customSignConfirmStepRef.current = customSignConfirmStep;
184
193
  }, [customSignConfirmStep]);
185
- const [wallet, setWallet] = (0, import_react2.useState)(null);
186
- const [isConnected, setIsConnected] = (0, import_react2.useState)(false);
194
+ const { isConnected: paraIsConnected, embedded } = (0, import_react_sdk_lite2.useAccount)();
195
+ const evmWallets = (_b = (_a = embedded == null ? void 0 : embedded.wallets) == null ? void 0 : _a.filter((w) => w.type === "EVM")) != null ? _b : [];
196
+ const wallet = evmWallets.length > 0 ? evmWallets[0] : null;
197
+ const isConnected = paraIsConnected && wallet !== null;
187
198
  (0, import_react2.useEffect)(() => {
188
- let cancelled = false;
189
- async function checkConnection() {
190
- try {
191
- const isLoggedIn = await paraRef.current.isFullyLoggedIn();
192
- if (!isLoggedIn || cancelled) {
193
- setIsConnected(false);
194
- setWallet(null);
195
- return;
196
- }
197
- const wallets = Object.values(await paraRef.current.getWallets());
198
- const evmWallets = wallets.filter((w) => w.type === "EVM");
199
- if (evmWallets.length > 0 && !cancelled) {
200
- setWallet((prev) => (prev == null ? void 0 : prev.id) === evmWallets[0].id ? prev : evmWallets[0]);
201
- setIsConnected(true);
202
- } else if (!cancelled) {
203
- setIsConnected(false);
204
- setWallet(null);
205
- }
206
- } catch {
207
- if (!cancelled) {
208
- setIsConnected(false);
209
- setWallet(null);
210
- }
211
- }
199
+ if (isConnected) {
200
+ closeModalRef.current();
212
201
  }
213
- checkConnection();
214
- const interval = setInterval(checkConnection, 2e3);
215
- return () => {
216
- cancelled = true;
217
- clearInterval(interval);
218
- };
219
- }, []);
202
+ }, [isConnected]);
220
203
  const connect = (0, import_react2.useCallback)(async () => {
221
204
  openModalRef.current();
222
205
  }, []);
223
206
  const disconnect = (0, import_react2.useCallback)(async () => {
224
207
  await logoutAsyncRef.current();
225
208
  await paraRef.current.logout();
226
- setIsConnected(false);
227
- setWallet(null);
228
209
  }, []);
229
210
  const disconnectedCtx = (0, import_react2.useRef)({
230
211
  signCb: async () => {
@@ -266,7 +247,8 @@ function ParaSignerProviderInner({
266
247
  accountConfig: {
267
248
  publicKeyCommitment: commitmentBytes,
268
249
  accountType: "RegularAccountImmutableCode",
269
- storageMode: AccountStorageMode.public()
250
+ storageMode: AccountStorageMode.public(),
251
+ ...(customComponents == null ? void 0 : customComponents.length) ? { customComponents } : {}
270
252
  },
271
253
  storeName: `para_${wallet.id}`,
272
254
  name: "Para",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/useParaMiden.ts","../src/ParaSignerProvider.tsx"],"sourcesContent":["export { useParaMiden } from './useParaMiden';\nexport {\n ParaSignerProvider,\n useParaSigner,\n useModal,\n useLogout,\n type ParaSignerProviderProps,\n type ParaSignerExtras,\n} from './ParaSignerProvider';\n","'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@miden-sdk/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@miden-sdk/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useRef,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\nimport { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';\nimport {\n ParaProvider,\n useClient,\n useModal,\n useLogout,\n type ParaProviderProps,\n} from '@getpara/react-sdk-lite';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { SignerContext, type SignerContextValue } from '@miden-sdk/react';\nimport { signCb as createSignCb, type CustomSignConfirmStep } from '@miden-sdk/miden-para';\nimport { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from '@miden-sdk/miden-para';\n\n// Re-export Para hooks for convenience\nexport { useModal, useLogout } from '@getpara/react-sdk-lite';\n\nconst defaultQueryClient = new QueryClient();\n\n// PARA SIGNER PROVIDER\n// ================================================================================================\n\n/** Environment string values accepted by ParaSignerProvider */\nexport type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';\n\n/**\n * Convert environment string to Environment enum value.\n * Handles the mapping safely for both ESM and CJS environments.\n */\nfunction getEnvironmentValue(env: ParaEnvironment): Environment {\n // Handle aliases\n const normalizedEnv = env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;\n\n // Try accessing the enum - Environment may be undefined in some test environments\n if (Environment && typeof Environment === 'object') {\n const value = Environment[normalizedEnv as keyof typeof Environment];\n if (value !== undefined) return value;\n }\n\n // Fallback: return the string directly (Para SDK may accept string values)\n return normalizedEnv as unknown as Environment;\n}\n\nexport interface ParaSignerProviderProps {\n children: ReactNode;\n /** Para API key */\n apiKey: string;\n /** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */\n environment: ParaEnvironment;\n /** App name displayed in Para modal */\n appName?: string;\n /** Whether to show the signing modal for transaction confirmation */\n showSigningModal?: boolean;\n /** Custom sign confirmation step callback */\n customSignConfirmStep?: CustomSignConfirmStep;\n /**\n * Optional custom QueryClient instance for React Query.\n * If not provided, a default instance is used internally.\n */\n queryClient?: QueryClient;\n /**\n * Advanced: Additional config to pass to ParaProvider.\n * Use this for customizing OAuth methods, external wallets, etc.\n */\n paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;\n}\n\n/**\n * Para-specific extras exposed via useParaSigner hook.\n */\nexport interface ParaSignerExtras {\n /** Para client instance */\n para: ParaWeb;\n /** Connected wallet (null if not connected) */\n wallet: Wallet | null;\n}\n\nconst ParaSignerExtrasContext = createContext<ParaSignerExtras | null>(null);\n\n/**\n * ParaSignerProvider wraps MidenProvider to enable Para wallet signing.\n * Includes ParaProvider internally, so you don't need to wrap with it separately.\n *\n * @example\n * ```tsx\n * <ParaSignerProvider apiKey=\"your-api-key\" environment=\"BETA\" appName=\"My App\">\n * <MidenProvider config={{ rpcUrl: \"testnet\" }}>\n * <App />\n * </MidenProvider>\n * </ParaSignerProvider>\n * ```\n */\nexport function ParaSignerProvider({\n children,\n apiKey,\n environment,\n appName = 'Miden App',\n showSigningModal = true,\n customSignConfirmStep,\n queryClient,\n paraProviderConfig,\n}: ParaSignerProviderProps) {\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <ParaProvider\n paraClientConfig={{\n env: getEnvironmentValue(environment),\n apiKey,\n }}\n config={{ appName }}\n {...paraProviderConfig}\n >\n <ParaSignerProviderInner\n showSigningModal={showSigningModal}\n customSignConfirmStep={customSignConfirmStep}\n >\n {children}\n </ParaSignerProviderInner>\n </ParaProvider>\n </QueryClientProvider>\n );\n}\n\n/**\n * Inner component that has access to ParaProvider context (useModal, etc.)\n */\nfunction ParaSignerProviderInner({\n children,\n showSigningModal = true,\n customSignConfirmStep,\n}: Pick<ParaSignerProviderProps, 'children' | 'showSigningModal' | 'customSignConfirmStep'>) {\n // Access Para modal from ParaProvider.\n // Store in refs to avoid re-render loops (these hooks return new objects each render).\n const { openModal } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => { openModalRef.current = openModal; }, [openModal]);\n useEffect(() => { logoutAsyncRef.current = logoutAsync; }, [logoutAsync]);\n\n // Get the Para client from ParaProvider context (avoids creating a duplicate instance).\n // Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.\n const para = useClient()!;\n const paraRef = useRef(para);\n useEffect(() => { paraRef.current = para; }, [para]);\n\n // Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.\n const showSigningModalRef = useRef(showSigningModal);\n const customSignConfirmStepRef = useRef(customSignConfirmStep);\n useEffect(() => { showSigningModalRef.current = showSigningModal; }, [showSigningModal]);\n useEffect(() => { customSignConfirmStepRef.current = customSignConfirmStep; }, [customSignConfirmStep]);\n\n const [wallet, setWallet] = useState<Wallet | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n\n // Check connection status on mount and periodically\n useEffect(() => {\n let cancelled = false;\n\n async function checkConnection() {\n try {\n const isLoggedIn = await paraRef.current.isFullyLoggedIn();\n if (!isLoggedIn || cancelled) {\n setIsConnected(false);\n setWallet(null);\n return;\n }\n\n const wallets = Object.values(await paraRef.current.getWallets());\n const evmWallets = wallets.filter((w) => w.type === 'EVM');\n\n if (evmWallets.length > 0 && !cancelled) {\n setWallet((prev) => prev?.id === evmWallets[0].id ? prev : evmWallets[0]);\n setIsConnected(true);\n } else if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n } catch {\n if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n }\n }\n\n checkConnection();\n const interval = setInterval(checkConnection, 2000);\n return () => {\n cancelled = true;\n clearInterval(interval);\n };\n }, []);\n\n // Connect opens the Para modal\n const connect = useCallback(async () => {\n openModalRef.current();\n }, []);\n\n // Disconnect logs out from Para\n const disconnect = useCallback(async () => {\n await logoutAsyncRef.current();\n await paraRef.current.logout();\n setIsConnected(false);\n setWallet(null);\n }, []);\n\n // Build signer context (includes connect/disconnect for unified useSigner hook).\n // Only depends on isConnected and wallet — everything else is accessed via refs\n // so that MidenProvider doesn't see a new context object on every poll cycle.\n //\n // IMPORTANT: initialise with a disconnected placeholder (isConnected:false) rather\n // than null. When signerContext is null MidenProvider creates a local-keystore\n // client whose auto-sync accesses the WASM module; our buildContext also touches\n // WASM (evmPkToCommitment / AccountStorageMode) → concurrent WASM access → crash.\n // A {isConnected:false} context makes MidenProvider's init effect return early\n // without creating any client, keeping the WASM module free for buildContext.\n const disconnectedCtx = useRef<SignerContextValue>({\n signCb: async () => { throw new Error('Para wallet not connected'); },\n accountConfig: null as any,\n storeName: '',\n name: 'Para',\n isConnected: false,\n connect,\n disconnect,\n });\n const [signerContext, setSignerContext] = useState<SignerContextValue>(\n disconnectedCtx.current\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function buildContext() {\n if (!isConnected || !wallet) {\n setSignerContext(disconnectedCtx.current);\n return;\n }\n\n try {\n // Connected - build full context with signing capability\n const p = paraRef.current;\n const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);\n if (!publicKey) throw new Error('Failed to get public key from wallet');\n const commitment = await evmPkToCommitment(publicKey);\n\n // Serialize the commitment Word to Uint8Array for SignerAccountConfig\n const commitmentBytes = commitment.serialize();\n\n const signCallback = createSignCb(\n p,\n wallet,\n showSigningModalRef.current,\n customSignConfirmStepRef.current\n );\n\n if (!cancelled) {\n const { AccountStorageMode } = await import(\n '@miden-sdk/miden-sdk'\n );\n\n setSignerContext({\n signCb: signCallback,\n accountConfig: {\n publicKeyCommitment: commitmentBytes,\n accountType: 'RegularAccountImmutableCode',\n storageMode: AccountStorageMode.public(),\n },\n storeName: `para_${wallet.id}`,\n name: 'Para',\n isConnected: true,\n connect,\n disconnect,\n });\n }\n } catch (error) {\n console.error('Failed to build Para signer context:', error);\n if (!cancelled) {\n setSignerContext(disconnectedCtx.current);\n }\n }\n }\n\n buildContext();\n return () => {\n cancelled = true;\n };\n }, [isConnected, wallet, connect, disconnect]);\n\n return (\n <ParaSignerExtrasContext.Provider value={{ para, wallet }}>\n <SignerContext.Provider value={signerContext}>\n {children}\n </SignerContext.Provider>\n </ParaSignerExtrasContext.Provider>\n );\n}\n\n/**\n * Hook for Para-specific extras beyond the unified useSigner interface.\n * Use this to access the Para client or wallet details directly.\n *\n * @example\n * ```tsx\n * const { para, wallet, isConnected } = useParaSigner();\n * ```\n */\nexport function useParaSigner(): ParaSignerExtras & { isConnected: boolean } {\n const extras = useContext(ParaSignerExtrasContext);\n const signer = useContext(SignerContext);\n if (!extras) {\n throw new Error('useParaSigner must be used within ParaSignerProvider');\n }\n return { ...extras, isConnected: signer?.isConnected ?? false };\n}\n"],"mappings":"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","names":["import_react","import_react_sdk_lite","import_miden_para","createSignCb"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/useParaMiden.ts","../src/ParaSignerProvider.tsx"],"sourcesContent":["export { useParaMiden } from './useParaMiden';\nexport {\n ParaSignerProvider,\n useParaSigner,\n useModal,\n useLogout,\n type ParaSignerProviderProps,\n type ParaSignerExtras,\n} from './ParaSignerProvider';\n","'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@miden-sdk/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@miden-sdk/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n","import '@getpara/react-sdk-lite/styles.css';\nimport {\n useState,\n useEffect,\n useCallback,\n useRef,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\nimport { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';\nimport {\n ParaProvider,\n useClient,\n useAccount as useParaAccount,\n useModal,\n useLogout,\n type ParaProviderProps,\n} from '@getpara/react-sdk-lite';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport {\n SignerContext,\n type SignerContextValue,\n type SignerAccountConfig,\n} from '@miden-sdk/react';\nimport {\n signCb as createSignCb,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\nimport {\n evmPkToCommitment,\n getUncompressedPublicKeyFromWallet,\n} from '@miden-sdk/miden-para';\n\n// Re-export Para hooks for convenience\nexport { useModal, useLogout } from '@getpara/react-sdk-lite';\n\nconst defaultQueryClient = new QueryClient();\n\n// PARA SIGNER PROVIDER\n// ================================================================================================\n\n/** Environment string values accepted by ParaSignerProvider */\nexport type ParaEnvironment =\n | 'BETA'\n | 'PROD'\n | 'SANDBOX'\n | 'DEV'\n | 'DEVELOPMENT'\n | 'PRODUCTION';\n\n/**\n * Convert environment string to Environment enum value.\n * Handles the mapping safely for both ESM and CJS environments.\n */\nfunction getEnvironmentValue(env: ParaEnvironment): Environment {\n // Handle aliases\n const normalizedEnv =\n env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;\n\n // Try accessing the enum - Environment may be undefined in some test environments\n if (Environment && typeof Environment === 'object') {\n const value = Environment[normalizedEnv as keyof typeof Environment];\n if (value !== undefined) return value;\n }\n\n // Fallback: return the string directly (Para SDK may accept string values)\n return normalizedEnv as unknown as Environment;\n}\n\nexport interface ParaSignerProviderProps {\n children: ReactNode;\n /** Para API key */\n apiKey: string;\n /** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */\n environment: ParaEnvironment;\n /** App name displayed in Para modal */\n appName?: string;\n /** Whether to show the signing modal for transaction confirmation */\n showSigningModal?: boolean;\n /** Custom sign confirmation step callback */\n customSignConfirmStep?: CustomSignConfirmStep;\n /**\n * Optional custom QueryClient instance for React Query.\n * If not provided, a default instance is used internally.\n */\n queryClient?: QueryClient;\n /**\n * Advanced: Additional config to pass to ParaProvider.\n * Use this for customizing OAuth methods, external wallets, etc.\n */\n paraProviderConfig?: Partial<\n Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>\n >;\n /** Optional custom account components to include in the account (e.g. from a compiled .masp package) */\n customComponents?: SignerAccountConfig['customComponents'];\n}\n\n/**\n * Para-specific extras exposed via useParaSigner hook.\n */\nexport interface ParaSignerExtras {\n /** Para client instance */\n para: ParaWeb;\n /** Connected wallet (null if not connected) */\n wallet: Wallet | null;\n}\n\nconst ParaSignerExtrasContext = createContext<ParaSignerExtras | null>(null);\n\n/**\n * ParaSignerProvider wraps MidenProvider to enable Para wallet signing.\n * Includes ParaProvider internally, so you don't need to wrap with it separately.\n *\n * @example\n * ```tsx\n * <ParaSignerProvider apiKey=\"your-api-key\" environment=\"BETA\" appName=\"My App\">\n * <MidenProvider config={{ rpcUrl: \"testnet\" }}>\n * <App />\n * </MidenProvider>\n * </ParaSignerProvider>\n * ```\n */\nexport function ParaSignerProvider({\n children,\n apiKey,\n environment,\n appName = 'Miden App',\n showSigningModal = true,\n customSignConfirmStep,\n queryClient,\n paraProviderConfig,\n customComponents,\n}: ParaSignerProviderProps) {\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <ParaProvider\n paraClientConfig={{\n env: getEnvironmentValue(environment),\n apiKey,\n }}\n config={{ appName }}\n {...paraProviderConfig}\n >\n <ParaSignerProviderInner\n showSigningModal={showSigningModal}\n customSignConfirmStep={customSignConfirmStep}\n customComponents={customComponents}\n >\n {children}\n </ParaSignerProviderInner>\n </ParaProvider>\n </QueryClientProvider>\n );\n}\n\n/**\n * Inner component that has access to ParaProvider context (useModal, etc.)\n */\nfunction ParaSignerProviderInner({\n children,\n showSigningModal = true,\n customSignConfirmStep,\n customComponents,\n}: Pick<\n ParaSignerProviderProps,\n 'children' | 'showSigningModal' | 'customSignConfirmStep' | 'customComponents'\n>) {\n // Access Para modal from ParaProvider.\n // Store in refs to avoid re-render loops (these hooks return new objects each render).\n const { openModal, closeModal } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const closeModalRef = useRef(closeModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => {\n openModalRef.current = openModal;\n }, [openModal]);\n useEffect(() => {\n closeModalRef.current = closeModal;\n }, [closeModal]);\n useEffect(() => {\n logoutAsyncRef.current = logoutAsync;\n }, [logoutAsync]);\n\n // Get the Para client from ParaProvider context (avoids creating a duplicate instance).\n // Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.\n const para = useClient()!;\n const paraRef = useRef(para);\n useEffect(() => {\n paraRef.current = para;\n }, [para]);\n\n // Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.\n const showSigningModalRef = useRef(showSigningModal);\n const customSignConfirmStepRef = useRef(customSignConfirmStep);\n useEffect(() => {\n showSigningModalRef.current = showSigningModal;\n }, [showSigningModal]);\n useEffect(() => {\n customSignConfirmStepRef.current = customSignConfirmStep;\n }, [customSignConfirmStep]);\n\n // Use Para SDK's reactive useAccount() hook to detect login state.\n // This subscribes to the internal state machine instead of polling isFullyLoggedIn().\n const { isConnected: paraIsConnected, embedded } = useParaAccount();\n const evmWallets = embedded?.wallets?.filter((w) => w.type === 'EVM') ?? [];\n const wallet = evmWallets.length > 0 ? (evmWallets[0] as unknown as Wallet) : null;\n const isConnected = paraIsConnected && wallet !== null;\n\n // Close the modal when login is detected\n useEffect(() => {\n if (isConnected) {\n closeModalRef.current();\n }\n }, [isConnected]);\n\n // Connect opens the Para modal\n const connect = useCallback(async () => {\n openModalRef.current();\n }, []);\n\n // Disconnect logs out from Para\n const disconnect = useCallback(async () => {\n await logoutAsyncRef.current();\n await paraRef.current.logout();\n }, []);\n\n // Build signer context (includes connect/disconnect for unified useSigner hook).\n // Only depends on isConnected and wallet — everything else is accessed via refs\n // so that MidenProvider doesn't see a new context object on every poll cycle.\n //\n // IMPORTANT: initialise with a disconnected placeholder (isConnected:false) rather\n // than null. When signerContext is null MidenProvider creates a local-keystore\n // client whose auto-sync accesses the WASM module; our buildContext also touches\n // WASM (evmPkToCommitment / AccountStorageMode) → concurrent WASM access → crash.\n // A {isConnected:false} context makes MidenProvider's init effect return early\n // without creating any client, keeping the WASM module free for buildContext.\n const disconnectedCtx = useRef<SignerContextValue>({\n signCb: async () => {\n throw new Error('Para wallet not connected');\n },\n accountConfig: null as any,\n storeName: '',\n name: 'Para',\n isConnected: false,\n connect,\n disconnect,\n });\n const [signerContext, setSignerContext] = useState<SignerContextValue>(\n disconnectedCtx.current\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function buildContext() {\n if (!isConnected || !wallet) {\n setSignerContext(disconnectedCtx.current);\n return;\n }\n\n try {\n // Connected - build full context with signing capability\n const p = paraRef.current;\n const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);\n if (!publicKey) throw new Error('Failed to get public key from wallet');\n const commitment = await evmPkToCommitment(publicKey);\n\n // Serialize the commitment Word to Uint8Array for SignerAccountConfig\n const commitmentBytes = commitment.serialize();\n\n const signCallback = createSignCb(\n p,\n wallet,\n showSigningModalRef.current,\n customSignConfirmStepRef.current\n );\n\n if (!cancelled) {\n const { AccountStorageMode } = await import('@miden-sdk/miden-sdk');\n\n setSignerContext({\n signCb: signCallback,\n accountConfig: {\n publicKeyCommitment: commitmentBytes,\n accountType: 'RegularAccountImmutableCode',\n storageMode: AccountStorageMode.public(),\n ...(customComponents?.length ? { customComponents } : {}),\n },\n storeName: `para_${wallet.id}`,\n name: 'Para',\n isConnected: true,\n connect,\n disconnect,\n });\n }\n } catch (error) {\n console.error('Failed to build Para signer context:', error);\n if (!cancelled) {\n setSignerContext(disconnectedCtx.current);\n }\n }\n }\n\n buildContext();\n return () => {\n cancelled = true;\n };\n }, [isConnected, wallet, connect, disconnect]);\n\n return (\n <ParaSignerExtrasContext.Provider value={{ para, wallet }}>\n <SignerContext.Provider value={signerContext}>\n {children}\n </SignerContext.Provider>\n </ParaSignerExtrasContext.Provider>\n );\n}\n\n/**\n * Hook for Para-specific extras beyond the unified useSigner interface.\n * Use this to access the Para client or wallet details directly.\n *\n * @example\n * ```tsx\n * const { para, wallet, isConnected } = useParaSigner();\n * ```\n */\nexport function useParaSigner(): ParaSignerExtras & { isConnected: boolean } {\n const extras = useContext(ParaSignerExtrasContext);\n const signer = useContext(SignerContext);\n if (!extras) {\n throw new Error('useParaSigner must be used within ParaSignerProvider');\n }\n return { ...extras, isConnected: signer?.isConnected ?? false };\n}\n"],"mappings":"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","names":["import_react","import_react_sdk_lite","import_miden_para","useParaAccount","createSignCb"]}
package/dist/index.mjs CHANGED
@@ -67,6 +67,7 @@ function useParaMiden(nodeUrl, storageMode = "public", opts = {}, showSigningMod
67
67
  }
68
68
 
69
69
  // src/ParaSignerProvider.tsx
70
+ import "@getpara/react-sdk-lite/styles.css";
70
71
  import {
71
72
  useState as useState2,
72
73
  useEffect as useEffect2,
@@ -79,13 +80,21 @@ import { Environment } from "@getpara/web-sdk";
79
80
  import {
80
81
  ParaProvider,
81
82
  useClient as useClient2,
83
+ useAccount as useParaAccount,
82
84
  useModal,
83
85
  useLogout
84
86
  } from "@getpara/react-sdk-lite";
85
87
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
86
- import { SignerContext } from "@miden-sdk/react";
87
- import { signCb as createSignCb } from "@miden-sdk/miden-para";
88
- import { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from "@miden-sdk/miden-para";
88
+ import {
89
+ SignerContext
90
+ } from "@miden-sdk/react";
91
+ import {
92
+ signCb as createSignCb
93
+ } from "@miden-sdk/miden-para";
94
+ import {
95
+ evmPkToCommitment,
96
+ getUncompressedPublicKeyFromWallet
97
+ } from "@miden-sdk/miden-para";
89
98
  import { useModal as useModal2, useLogout as useLogout2 } from "@getpara/react-sdk-lite";
90
99
  import { jsx } from "react/jsx-runtime";
91
100
  var defaultQueryClient = new QueryClient();
@@ -106,7 +115,8 @@ function ParaSignerProvider({
106
115
  showSigningModal = true,
107
116
  customSignConfirmStep,
108
117
  queryClient,
109
- paraProviderConfig
118
+ paraProviderConfig,
119
+ customComponents
110
120
  }) {
111
121
  return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient != null ? queryClient : defaultQueryClient, children: /* @__PURE__ */ jsx(
112
122
  ParaProvider,
@@ -122,6 +132,7 @@ function ParaSignerProvider({
122
132
  {
123
133
  showSigningModal,
124
134
  customSignConfirmStep,
135
+ customComponents,
125
136
  children
126
137
  }
127
138
  )
@@ -131,15 +142,21 @@ function ParaSignerProvider({
131
142
  function ParaSignerProviderInner({
132
143
  children,
133
144
  showSigningModal = true,
134
- customSignConfirmStep
145
+ customSignConfirmStep,
146
+ customComponents
135
147
  }) {
136
- const { openModal } = useModal();
148
+ var _a, _b;
149
+ const { openModal, closeModal } = useModal();
137
150
  const { logoutAsync } = useLogout();
138
151
  const openModalRef = useRef2(openModal);
152
+ const closeModalRef = useRef2(closeModal);
139
153
  const logoutAsyncRef = useRef2(logoutAsync);
140
154
  useEffect2(() => {
141
155
  openModalRef.current = openModal;
142
156
  }, [openModal]);
157
+ useEffect2(() => {
158
+ closeModalRef.current = closeModal;
159
+ }, [closeModal]);
143
160
  useEffect2(() => {
144
161
  logoutAsyncRef.current = logoutAsync;
145
162
  }, [logoutAsync]);
@@ -156,49 +173,21 @@ function ParaSignerProviderInner({
156
173
  useEffect2(() => {
157
174
  customSignConfirmStepRef.current = customSignConfirmStep;
158
175
  }, [customSignConfirmStep]);
159
- const [wallet, setWallet] = useState2(null);
160
- const [isConnected, setIsConnected] = useState2(false);
176
+ const { isConnected: paraIsConnected, embedded } = useParaAccount();
177
+ const evmWallets = (_b = (_a = embedded == null ? void 0 : embedded.wallets) == null ? void 0 : _a.filter((w) => w.type === "EVM")) != null ? _b : [];
178
+ const wallet = evmWallets.length > 0 ? evmWallets[0] : null;
179
+ const isConnected = paraIsConnected && wallet !== null;
161
180
  useEffect2(() => {
162
- let cancelled = false;
163
- async function checkConnection() {
164
- try {
165
- const isLoggedIn = await paraRef.current.isFullyLoggedIn();
166
- if (!isLoggedIn || cancelled) {
167
- setIsConnected(false);
168
- setWallet(null);
169
- return;
170
- }
171
- const wallets = Object.values(await paraRef.current.getWallets());
172
- const evmWallets = wallets.filter((w) => w.type === "EVM");
173
- if (evmWallets.length > 0 && !cancelled) {
174
- setWallet((prev) => (prev == null ? void 0 : prev.id) === evmWallets[0].id ? prev : evmWallets[0]);
175
- setIsConnected(true);
176
- } else if (!cancelled) {
177
- setIsConnected(false);
178
- setWallet(null);
179
- }
180
- } catch {
181
- if (!cancelled) {
182
- setIsConnected(false);
183
- setWallet(null);
184
- }
185
- }
181
+ if (isConnected) {
182
+ closeModalRef.current();
186
183
  }
187
- checkConnection();
188
- const interval = setInterval(checkConnection, 2e3);
189
- return () => {
190
- cancelled = true;
191
- clearInterval(interval);
192
- };
193
- }, []);
184
+ }, [isConnected]);
194
185
  const connect = useCallback(async () => {
195
186
  openModalRef.current();
196
187
  }, []);
197
188
  const disconnect = useCallback(async () => {
198
189
  await logoutAsyncRef.current();
199
190
  await paraRef.current.logout();
200
- setIsConnected(false);
201
- setWallet(null);
202
191
  }, []);
203
192
  const disconnectedCtx = useRef2({
204
193
  signCb: async () => {
@@ -240,7 +229,8 @@ function ParaSignerProviderInner({
240
229
  accountConfig: {
241
230
  publicKeyCommitment: commitmentBytes,
242
231
  accountType: "RegularAccountImmutableCode",
243
- storageMode: AccountStorageMode.public()
232
+ storageMode: AccountStorageMode.public(),
233
+ ...(customComponents == null ? void 0 : customComponents.length) ? { customComponents } : {}
244
234
  },
245
235
  storeName: `para_${wallet.id}`,
246
236
  name: "Para",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useParaMiden.ts","../src/ParaSignerProvider.tsx"],"sourcesContent":["'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@miden-sdk/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@miden-sdk/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useRef,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\nimport { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';\nimport {\n ParaProvider,\n useClient,\n useModal,\n useLogout,\n type ParaProviderProps,\n} from '@getpara/react-sdk-lite';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { SignerContext, type SignerContextValue } from '@miden-sdk/react';\nimport { signCb as createSignCb, type CustomSignConfirmStep } from '@miden-sdk/miden-para';\nimport { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from '@miden-sdk/miden-para';\n\n// Re-export Para hooks for convenience\nexport { useModal, useLogout } from '@getpara/react-sdk-lite';\n\nconst defaultQueryClient = new QueryClient();\n\n// PARA SIGNER PROVIDER\n// ================================================================================================\n\n/** Environment string values accepted by ParaSignerProvider */\nexport type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';\n\n/**\n * Convert environment string to Environment enum value.\n * Handles the mapping safely for both ESM and CJS environments.\n */\nfunction getEnvironmentValue(env: ParaEnvironment): Environment {\n // Handle aliases\n const normalizedEnv = env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;\n\n // Try accessing the enum - Environment may be undefined in some test environments\n if (Environment && typeof Environment === 'object') {\n const value = Environment[normalizedEnv as keyof typeof Environment];\n if (value !== undefined) return value;\n }\n\n // Fallback: return the string directly (Para SDK may accept string values)\n return normalizedEnv as unknown as Environment;\n}\n\nexport interface ParaSignerProviderProps {\n children: ReactNode;\n /** Para API key */\n apiKey: string;\n /** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */\n environment: ParaEnvironment;\n /** App name displayed in Para modal */\n appName?: string;\n /** Whether to show the signing modal for transaction confirmation */\n showSigningModal?: boolean;\n /** Custom sign confirmation step callback */\n customSignConfirmStep?: CustomSignConfirmStep;\n /**\n * Optional custom QueryClient instance for React Query.\n * If not provided, a default instance is used internally.\n */\n queryClient?: QueryClient;\n /**\n * Advanced: Additional config to pass to ParaProvider.\n * Use this for customizing OAuth methods, external wallets, etc.\n */\n paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;\n}\n\n/**\n * Para-specific extras exposed via useParaSigner hook.\n */\nexport interface ParaSignerExtras {\n /** Para client instance */\n para: ParaWeb;\n /** Connected wallet (null if not connected) */\n wallet: Wallet | null;\n}\n\nconst ParaSignerExtrasContext = createContext<ParaSignerExtras | null>(null);\n\n/**\n * ParaSignerProvider wraps MidenProvider to enable Para wallet signing.\n * Includes ParaProvider internally, so you don't need to wrap with it separately.\n *\n * @example\n * ```tsx\n * <ParaSignerProvider apiKey=\"your-api-key\" environment=\"BETA\" appName=\"My App\">\n * <MidenProvider config={{ rpcUrl: \"testnet\" }}>\n * <App />\n * </MidenProvider>\n * </ParaSignerProvider>\n * ```\n */\nexport function ParaSignerProvider({\n children,\n apiKey,\n environment,\n appName = 'Miden App',\n showSigningModal = true,\n customSignConfirmStep,\n queryClient,\n paraProviderConfig,\n}: ParaSignerProviderProps) {\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <ParaProvider\n paraClientConfig={{\n env: getEnvironmentValue(environment),\n apiKey,\n }}\n config={{ appName }}\n {...paraProviderConfig}\n >\n <ParaSignerProviderInner\n showSigningModal={showSigningModal}\n customSignConfirmStep={customSignConfirmStep}\n >\n {children}\n </ParaSignerProviderInner>\n </ParaProvider>\n </QueryClientProvider>\n );\n}\n\n/**\n * Inner component that has access to ParaProvider context (useModal, etc.)\n */\nfunction ParaSignerProviderInner({\n children,\n showSigningModal = true,\n customSignConfirmStep,\n}: Pick<ParaSignerProviderProps, 'children' | 'showSigningModal' | 'customSignConfirmStep'>) {\n // Access Para modal from ParaProvider.\n // Store in refs to avoid re-render loops (these hooks return new objects each render).\n const { openModal } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => { openModalRef.current = openModal; }, [openModal]);\n useEffect(() => { logoutAsyncRef.current = logoutAsync; }, [logoutAsync]);\n\n // Get the Para client from ParaProvider context (avoids creating a duplicate instance).\n // Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.\n const para = useClient()!;\n const paraRef = useRef(para);\n useEffect(() => { paraRef.current = para; }, [para]);\n\n // Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.\n const showSigningModalRef = useRef(showSigningModal);\n const customSignConfirmStepRef = useRef(customSignConfirmStep);\n useEffect(() => { showSigningModalRef.current = showSigningModal; }, [showSigningModal]);\n useEffect(() => { customSignConfirmStepRef.current = customSignConfirmStep; }, [customSignConfirmStep]);\n\n const [wallet, setWallet] = useState<Wallet | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n\n // Check connection status on mount and periodically\n useEffect(() => {\n let cancelled = false;\n\n async function checkConnection() {\n try {\n const isLoggedIn = await paraRef.current.isFullyLoggedIn();\n if (!isLoggedIn || cancelled) {\n setIsConnected(false);\n setWallet(null);\n return;\n }\n\n const wallets = Object.values(await paraRef.current.getWallets());\n const evmWallets = wallets.filter((w) => w.type === 'EVM');\n\n if (evmWallets.length > 0 && !cancelled) {\n setWallet((prev) => prev?.id === evmWallets[0].id ? prev : evmWallets[0]);\n setIsConnected(true);\n } else if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n } catch {\n if (!cancelled) {\n setIsConnected(false);\n setWallet(null);\n }\n }\n }\n\n checkConnection();\n const interval = setInterval(checkConnection, 2000);\n return () => {\n cancelled = true;\n clearInterval(interval);\n };\n }, []);\n\n // Connect opens the Para modal\n const connect = useCallback(async () => {\n openModalRef.current();\n }, []);\n\n // Disconnect logs out from Para\n const disconnect = useCallback(async () => {\n await logoutAsyncRef.current();\n await paraRef.current.logout();\n setIsConnected(false);\n setWallet(null);\n }, []);\n\n // Build signer context (includes connect/disconnect for unified useSigner hook).\n // Only depends on isConnected and wallet — everything else is accessed via refs\n // so that MidenProvider doesn't see a new context object on every poll cycle.\n //\n // IMPORTANT: initialise with a disconnected placeholder (isConnected:false) rather\n // than null. When signerContext is null MidenProvider creates a local-keystore\n // client whose auto-sync accesses the WASM module; our buildContext also touches\n // WASM (evmPkToCommitment / AccountStorageMode) → concurrent WASM access → crash.\n // A {isConnected:false} context makes MidenProvider's init effect return early\n // without creating any client, keeping the WASM module free for buildContext.\n const disconnectedCtx = useRef<SignerContextValue>({\n signCb: async () => { throw new Error('Para wallet not connected'); },\n accountConfig: null as any,\n storeName: '',\n name: 'Para',\n isConnected: false,\n connect,\n disconnect,\n });\n const [signerContext, setSignerContext] = useState<SignerContextValue>(\n disconnectedCtx.current\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function buildContext() {\n if (!isConnected || !wallet) {\n setSignerContext(disconnectedCtx.current);\n return;\n }\n\n try {\n // Connected - build full context with signing capability\n const p = paraRef.current;\n const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);\n if (!publicKey) throw new Error('Failed to get public key from wallet');\n const commitment = await evmPkToCommitment(publicKey);\n\n // Serialize the commitment Word to Uint8Array for SignerAccountConfig\n const commitmentBytes = commitment.serialize();\n\n const signCallback = createSignCb(\n p,\n wallet,\n showSigningModalRef.current,\n customSignConfirmStepRef.current\n );\n\n if (!cancelled) {\n const { AccountStorageMode } = await import(\n '@miden-sdk/miden-sdk'\n );\n\n setSignerContext({\n signCb: signCallback,\n accountConfig: {\n publicKeyCommitment: commitmentBytes,\n accountType: 'RegularAccountImmutableCode',\n storageMode: AccountStorageMode.public(),\n },\n storeName: `para_${wallet.id}`,\n name: 'Para',\n isConnected: true,\n connect,\n disconnect,\n });\n }\n } catch (error) {\n console.error('Failed to build Para signer context:', error);\n if (!cancelled) {\n setSignerContext(disconnectedCtx.current);\n }\n }\n }\n\n buildContext();\n return () => {\n cancelled = true;\n };\n }, [isConnected, wallet, connect, disconnect]);\n\n return (\n <ParaSignerExtrasContext.Provider value={{ para, wallet }}>\n <SignerContext.Provider value={signerContext}>\n {children}\n </SignerContext.Provider>\n </ParaSignerExtrasContext.Provider>\n );\n}\n\n/**\n * Hook for Para-specific extras beyond the unified useSigner interface.\n * Use this to access the Para client or wallet details directly.\n *\n * @example\n * ```tsx\n * const { para, wallet, isConnected } = useParaSigner();\n * ```\n */\nexport function useParaSigner(): ParaSignerExtras & { isConnected: boolean } {\n const extras = useContext(ParaSignerExtrasContext);\n const signer = useContext(SignerContext);\n if (!extras) {\n throw new Error('useParaSigner must be used within ParaSignerProvider');\n }\n return { ...extras, isConnected: signer?.isConnected ?? false };\n}\n"],"mappings":";AAEA,SAAS,WAAW,kBAA+B;AACnD,SAAS,WAAW,SAAS,QAAQ,gBAAgB;AACrD;AAAA,EACE;AAAA,OAIK;AAgBA,SAAS,aACd,SACA,cAAuC,UACvC,OAAwD,CAAC,GACzD,mBAA4B,MAC5B,uBACA;AACA,QAAM,OAAO,UAAU;AACvB,QAAM,EAAE,aAAa,SAAS,IAAI,WAAW;AAC7C,QAAM,YAAY;AAAA,IAChB;AAAA,EACF;AACA,QAAM,CAAC,WAAW,YAAY,IAAI,SAAiB,EAAE;AAErD,QAAM,aAAa;AAAA,IACjB,MAAG;AAxCP;AAwCU,4BAAS,YAAT,mBAAkB,OAAO,CAAC,WAAW,OAAO,SAAS;AAAA;AAAA,IAC3D,CAAC,SAAS,OAAO;AAAA,EACnB;AAEA,YAAU,MAAM;AACd,QAAI,YAAY;AAEhB,mBAAe,cAAc;AA/CjC;AAgDM,UACE,CAAC,eACD,CAAC,QACD,GAAC,cAAS,YAAT,mBAAkB,WACnB,UAAU,SACV;AACA;AAAA,MACF;AAEA,YAAM,EAAE,YAAY,IAAI,MAAM,OAAO,sBAAsB;AAE3D,YAAM,EAAE,QAAQ,iBAAiB,WAAW,IAAI,IAC9C,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,UACE,GAAG;AAAA,UACH,UAAU;AAAA,UACV,MAAM,YAAY;AAAA,UAClB;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEF,UAAI,WAAW;AACb;AAAA,MACF;AAEA,gBAAU,UAAU;AACpB,mBAAa,GAAG;AAAA,IAClB;AAEA,gBAAY;AAEZ,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,QAAQ,UAAU;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACvGA;AAAA,EACE,YAAAA;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAkB,mBAAgC;AAClD;AAAA,EACE;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,aAAa,2BAA2B;AACjD,SAAS,qBAA8C;AACvD,SAAS,UAAU,oBAAgD;AACnE,SAAS,mBAAmB,0CAA0C;AAGtE,SAAS,YAAAC,WAAU,aAAAC,kBAAiB;AAiG5B;AA/FR,IAAM,qBAAqB,IAAI,YAAY;AAY3C,SAAS,oBAAoB,KAAmC;AAE9D,QAAM,gBAAgB,QAAQ,gBAAgB,SAAS,QAAQ,eAAe,SAAS;AAGvF,MAAI,eAAe,OAAO,gBAAgB,UAAU;AAClD,UAAM,QAAQ,YAAY,aAAyC;AACnE,QAAI,UAAU,OAAW,QAAO;AAAA,EAClC;AAGA,SAAO;AACT;AAoCA,IAAM,0BAA0B,cAAuC,IAAI;AAepE,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,SACE,oBAAC,uBAAoB,QAAQ,oCAAe,oBAC1C;AAAA,IAAC;AAAA;AAAA,MACC,kBAAkB;AAAA,QAChB,KAAK,oBAAoB,WAAW;AAAA,QACpC;AAAA,MACF;AAAA,MACA,QAAQ,EAAE,QAAQ;AAAA,MACjB,GAAG;AAAA,MAEJ;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UAEC;AAAA;AAAA,MACH;AAAA;AAAA,EACF,GACF;AAEJ;AAKA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA,mBAAmB;AAAA,EACnB;AACF,GAA6F;AAG3F,QAAM,EAAE,UAAU,IAAI,SAAS;AAC/B,QAAM,EAAE,YAAY,IAAI,UAAU;AAClC,QAAM,eAAeH,QAAO,SAAS;AACrC,QAAM,iBAAiBA,QAAO,WAAW;AACzC,EAAAD,WAAU,MAAM;AAAE,iBAAa,UAAU;AAAA,EAAW,GAAG,CAAC,SAAS,CAAC;AAClE,EAAAA,WAAU,MAAM;AAAE,mBAAe,UAAU;AAAA,EAAa,GAAG,CAAC,WAAW,CAAC;AAIxE,QAAM,OAAOE,WAAU;AACvB,QAAM,UAAUD,QAAO,IAAI;AAC3B,EAAAD,WAAU,MAAM;AAAE,YAAQ,UAAU;AAAA,EAAM,GAAG,CAAC,IAAI,CAAC;AAGnD,QAAM,sBAAsBC,QAAO,gBAAgB;AACnD,QAAM,2BAA2BA,QAAO,qBAAqB;AAC7D,EAAAD,WAAU,MAAM;AAAE,wBAAoB,UAAU;AAAA,EAAkB,GAAG,CAAC,gBAAgB,CAAC;AACvF,EAAAA,WAAU,MAAM;AAAE,6BAAyB,UAAU;AAAA,EAAuB,GAAG,CAAC,qBAAqB,CAAC;AAEtG,QAAM,CAAC,QAAQ,SAAS,IAAID,UAAwB,IAAI;AACxD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AAGpD,EAAAC,WAAU,MAAM;AACd,QAAI,YAAY;AAEhB,mBAAe,kBAAkB;AAC/B,UAAI;AACF,cAAM,aAAa,MAAM,QAAQ,QAAQ,gBAAgB;AACzD,YAAI,CAAC,cAAc,WAAW;AAC5B,yBAAe,KAAK;AACpB,oBAAU,IAAI;AACd;AAAA,QACF;AAEA,cAAM,UAAU,OAAO,OAAO,MAAM,QAAQ,QAAQ,WAAW,CAAC;AAChE,cAAM,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK;AAEzD,YAAI,WAAW,SAAS,KAAK,CAAC,WAAW;AACvC,oBAAU,CAAC,UAAS,6BAAM,QAAO,WAAW,CAAC,EAAE,KAAK,OAAO,WAAW,CAAC,CAAC;AACxE,yBAAe,IAAI;AAAA,QACrB,WAAW,CAAC,WAAW;AACrB,yBAAe,KAAK;AACpB,oBAAU,IAAI;AAAA,QAChB;AAAA,MACF,QAAQ;AACN,YAAI,CAAC,WAAW;AACd,yBAAe,KAAK;AACpB,oBAAU,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAEA,oBAAgB;AAChB,UAAM,WAAW,YAAY,iBAAiB,GAAI;AAClD,WAAO,MAAM;AACX,kBAAY;AACZ,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,UAAU,YAAY,YAAY;AACtC,iBAAa,QAAQ;AAAA,EACvB,GAAG,CAAC,CAAC;AAGL,QAAM,aAAa,YAAY,YAAY;AACzC,UAAM,eAAe,QAAQ;AAC7B,UAAM,QAAQ,QAAQ,OAAO;AAC7B,mBAAe,KAAK;AACpB,cAAU,IAAI;AAAA,EAChB,GAAG,CAAC,CAAC;AAYL,QAAM,kBAAkBC,QAA2B;AAAA,IACjD,QAAQ,YAAY;AAAE,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAAG;AAAA,IACpE,eAAe;AAAA,IACf,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,CAAC,eAAe,gBAAgB,IAAIF;AAAA,IACxC,gBAAgB;AAAA,EAClB;AAEA,EAAAC,WAAU,MAAM;AACd,QAAI,YAAY;AAEhB,mBAAe,eAAe;AAC5B,UAAI,CAAC,eAAe,CAAC,QAAQ;AAC3B,yBAAiB,gBAAgB,OAAO;AACxC;AAAA,MACF;AAEA,UAAI;AAEF,cAAM,IAAI,QAAQ;AAClB,cAAM,YAAY,MAAM,mCAAmC,GAAG,MAAM;AACpE,YAAI,CAAC,UAAW,OAAM,IAAI,MAAM,sCAAsC;AACtE,cAAM,aAAa,MAAM,kBAAkB,SAAS;AAGpD,cAAM,kBAAkB,WAAW,UAAU;AAE7C,cAAM,eAAe;AAAA,UACnB;AAAA,UACA;AAAA,UACA,oBAAoB;AAAA,UACpB,yBAAyB;AAAA,QAC3B;AAEA,YAAI,CAAC,WAAW;AACd,gBAAM,EAAE,mBAAmB,IAAI,MAAM,OACnC,sBACF;AAEA,2BAAiB;AAAA,YACf,QAAQ;AAAA,YACR,eAAe;AAAA,cACb,qBAAqB;AAAA,cACrB,aAAa;AAAA,cACb,aAAa,mBAAmB,OAAO;AAAA,YACzC;AAAA,YACA,WAAW,QAAQ,OAAO,EAAE;AAAA,YAC5B,MAAM;AAAA,YACN,aAAa;AAAA,YACb;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,wCAAwC,KAAK;AAC3D,YAAI,CAAC,WAAW;AACd,2BAAiB,gBAAgB,OAAO;AAAA,QAC1C;AAAA,MACF;AAAA,IACF;AAEA,iBAAa;AACb,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,aAAa,QAAQ,SAAS,UAAU,CAAC;AAE7C,SACE,oBAAC,wBAAwB,UAAxB,EAAiC,OAAO,EAAE,MAAM,OAAO,GACtD,8BAAC,cAAc,UAAd,EAAuB,OAAO,eAC5B,UACH,GACF;AAEJ;AAWO,SAAS,gBAA6D;AA3T7E;AA4TE,QAAM,SAAS,WAAW,uBAAuB;AACjD,QAAM,SAAS,WAAW,aAAa;AACvC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AACA,SAAO,EAAE,GAAG,QAAQ,cAAa,sCAAQ,gBAAR,YAAuB,MAAM;AAChE;","names":["useState","useEffect","useRef","useClient","useModal","useLogout"]}
1
+ {"version":3,"sources":["../src/useParaMiden.ts","../src/ParaSignerProvider.tsx"],"sourcesContent":["'use client';\n\nimport { useClient, useAccount, type Wallet } from '@getpara/react-sdk-lite';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createParaMidenClient,\n type Opts,\n type MidenAccountStorageMode,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\n\n/**\n * React hook that converts Para React SDK context into a ready-to-use Miden WebClient.\n * Spawns the client once a Para session with at least one EVM wallet is active.\n *\n * Returns:\n * - client: WebClient instance backed by the active Para session (or null while loading)\n * - accountId: Miden account id derived for the selected EVM wallet\n * - para: Para client instance from context\n * - evmWallets: filtered list of Para wallets with type === 'EVM'\n * - nodeUrl: Miden node endpoint used for the client\n * - opts: forwarded options used when creating the client\n * - showSigningModal: toggles the built-in signing modal\n * - customSignConfirmStep: optional callback for custom transaction confirmation flows\n */\nexport function useParaMiden(\n nodeUrl: string,\n storageMode: MidenAccountStorageMode = 'public',\n opts: Omit<Opts, 'endpoint' | 'type' | 'storageMode'> = {},\n showSigningModal: boolean = true,\n customSignConfirmStep?: CustomSignConfirmStep\n) {\n const para = useClient();\n const { isConnected, embedded } = useAccount();\n const clientRef = useRef<import('@miden-sdk/miden-sdk').WebClient | null>(\n null\n );\n const [accountId, setAccountId] = useState<string>('');\n\n const evmWallets = useMemo(\n () => embedded.wallets?.filter((wallet) => wallet.type === 'EVM'),\n [embedded.wallets]\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function setupClient() {\n if (\n !isConnected ||\n !para ||\n !embedded.wallets?.length ||\n clientRef.current\n ) {\n return;\n }\n\n const { AccountType } = await import('@miden-sdk/miden-sdk');\n\n const { client: midenParaClient, accountId: aId } =\n await createParaMidenClient(\n para,\n evmWallets as Wallet[],\n {\n ...opts,\n endpoint: nodeUrl,\n type: AccountType.RegularAccountImmutableCode,\n storageMode,\n },\n showSigningModal,\n customSignConfirmStep\n );\n\n if (cancelled) {\n return;\n }\n\n clientRef.current = midenParaClient;\n setAccountId(aId);\n }\n\n setupClient();\n\n return () => {\n cancelled = true;\n };\n }, [\n isConnected,\n evmWallets,\n para,\n nodeUrl,\n showSigningModal,\n customSignConfirmStep,\n ]);\n\n return {\n client: clientRef.current,\n accountId,\n para,\n evmWallets,\n nodeUrl,\n opts,\n };\n}\n","import '@getpara/react-sdk-lite/styles.css';\nimport {\n useState,\n useEffect,\n useCallback,\n useRef,\n createContext,\n useContext,\n type ReactNode,\n} from 'react';\nimport { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';\nimport {\n ParaProvider,\n useClient,\n useAccount as useParaAccount,\n useModal,\n useLogout,\n type ParaProviderProps,\n} from '@getpara/react-sdk-lite';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport {\n SignerContext,\n type SignerContextValue,\n type SignerAccountConfig,\n} from '@miden-sdk/react';\nimport {\n signCb as createSignCb,\n type CustomSignConfirmStep,\n} from '@miden-sdk/miden-para';\nimport {\n evmPkToCommitment,\n getUncompressedPublicKeyFromWallet,\n} from '@miden-sdk/miden-para';\n\n// Re-export Para hooks for convenience\nexport { useModal, useLogout } from '@getpara/react-sdk-lite';\n\nconst defaultQueryClient = new QueryClient();\n\n// PARA SIGNER PROVIDER\n// ================================================================================================\n\n/** Environment string values accepted by ParaSignerProvider */\nexport type ParaEnvironment =\n | 'BETA'\n | 'PROD'\n | 'SANDBOX'\n | 'DEV'\n | 'DEVELOPMENT'\n | 'PRODUCTION';\n\n/**\n * Convert environment string to Environment enum value.\n * Handles the mapping safely for both ESM and CJS environments.\n */\nfunction getEnvironmentValue(env: ParaEnvironment): Environment {\n // Handle aliases\n const normalizedEnv =\n env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;\n\n // Try accessing the enum - Environment may be undefined in some test environments\n if (Environment && typeof Environment === 'object') {\n const value = Environment[normalizedEnv as keyof typeof Environment];\n if (value !== undefined) return value;\n }\n\n // Fallback: return the string directly (Para SDK may accept string values)\n return normalizedEnv as unknown as Environment;\n}\n\nexport interface ParaSignerProviderProps {\n children: ReactNode;\n /** Para API key */\n apiKey: string;\n /** Para environment (BETA, PROD, SANDBOX, DEV, DEVELOPMENT, PRODUCTION) */\n environment: ParaEnvironment;\n /** App name displayed in Para modal */\n appName?: string;\n /** Whether to show the signing modal for transaction confirmation */\n showSigningModal?: boolean;\n /** Custom sign confirmation step callback */\n customSignConfirmStep?: CustomSignConfirmStep;\n /**\n * Optional custom QueryClient instance for React Query.\n * If not provided, a default instance is used internally.\n */\n queryClient?: QueryClient;\n /**\n * Advanced: Additional config to pass to ParaProvider.\n * Use this for customizing OAuth methods, external wallets, etc.\n */\n paraProviderConfig?: Partial<\n Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>\n >;\n /** Optional custom account components to include in the account (e.g. from a compiled .masp package) */\n customComponents?: SignerAccountConfig['customComponents'];\n}\n\n/**\n * Para-specific extras exposed via useParaSigner hook.\n */\nexport interface ParaSignerExtras {\n /** Para client instance */\n para: ParaWeb;\n /** Connected wallet (null if not connected) */\n wallet: Wallet | null;\n}\n\nconst ParaSignerExtrasContext = createContext<ParaSignerExtras | null>(null);\n\n/**\n * ParaSignerProvider wraps MidenProvider to enable Para wallet signing.\n * Includes ParaProvider internally, so you don't need to wrap with it separately.\n *\n * @example\n * ```tsx\n * <ParaSignerProvider apiKey=\"your-api-key\" environment=\"BETA\" appName=\"My App\">\n * <MidenProvider config={{ rpcUrl: \"testnet\" }}>\n * <App />\n * </MidenProvider>\n * </ParaSignerProvider>\n * ```\n */\nexport function ParaSignerProvider({\n children,\n apiKey,\n environment,\n appName = 'Miden App',\n showSigningModal = true,\n customSignConfirmStep,\n queryClient,\n paraProviderConfig,\n customComponents,\n}: ParaSignerProviderProps) {\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <ParaProvider\n paraClientConfig={{\n env: getEnvironmentValue(environment),\n apiKey,\n }}\n config={{ appName }}\n {...paraProviderConfig}\n >\n <ParaSignerProviderInner\n showSigningModal={showSigningModal}\n customSignConfirmStep={customSignConfirmStep}\n customComponents={customComponents}\n >\n {children}\n </ParaSignerProviderInner>\n </ParaProvider>\n </QueryClientProvider>\n );\n}\n\n/**\n * Inner component that has access to ParaProvider context (useModal, etc.)\n */\nfunction ParaSignerProviderInner({\n children,\n showSigningModal = true,\n customSignConfirmStep,\n customComponents,\n}: Pick<\n ParaSignerProviderProps,\n 'children' | 'showSigningModal' | 'customSignConfirmStep' | 'customComponents'\n>) {\n // Access Para modal from ParaProvider.\n // Store in refs to avoid re-render loops (these hooks return new objects each render).\n const { openModal, closeModal } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const closeModalRef = useRef(closeModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => {\n openModalRef.current = openModal;\n }, [openModal]);\n useEffect(() => {\n closeModalRef.current = closeModal;\n }, [closeModal]);\n useEffect(() => {\n logoutAsyncRef.current = logoutAsync;\n }, [logoutAsync]);\n\n // Get the Para client from ParaProvider context (avoids creating a duplicate instance).\n // Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.\n const para = useClient()!;\n const paraRef = useRef(para);\n useEffect(() => {\n paraRef.current = para;\n }, [para]);\n\n // Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.\n const showSigningModalRef = useRef(showSigningModal);\n const customSignConfirmStepRef = useRef(customSignConfirmStep);\n useEffect(() => {\n showSigningModalRef.current = showSigningModal;\n }, [showSigningModal]);\n useEffect(() => {\n customSignConfirmStepRef.current = customSignConfirmStep;\n }, [customSignConfirmStep]);\n\n // Use Para SDK's reactive useAccount() hook to detect login state.\n // This subscribes to the internal state machine instead of polling isFullyLoggedIn().\n const { isConnected: paraIsConnected, embedded } = useParaAccount();\n const evmWallets = embedded?.wallets?.filter((w) => w.type === 'EVM') ?? [];\n const wallet = evmWallets.length > 0 ? (evmWallets[0] as unknown as Wallet) : null;\n const isConnected = paraIsConnected && wallet !== null;\n\n // Close the modal when login is detected\n useEffect(() => {\n if (isConnected) {\n closeModalRef.current();\n }\n }, [isConnected]);\n\n // Connect opens the Para modal\n const connect = useCallback(async () => {\n openModalRef.current();\n }, []);\n\n // Disconnect logs out from Para\n const disconnect = useCallback(async () => {\n await logoutAsyncRef.current();\n await paraRef.current.logout();\n }, []);\n\n // Build signer context (includes connect/disconnect for unified useSigner hook).\n // Only depends on isConnected and wallet — everything else is accessed via refs\n // so that MidenProvider doesn't see a new context object on every poll cycle.\n //\n // IMPORTANT: initialise with a disconnected placeholder (isConnected:false) rather\n // than null. When signerContext is null MidenProvider creates a local-keystore\n // client whose auto-sync accesses the WASM module; our buildContext also touches\n // WASM (evmPkToCommitment / AccountStorageMode) → concurrent WASM access → crash.\n // A {isConnected:false} context makes MidenProvider's init effect return early\n // without creating any client, keeping the WASM module free for buildContext.\n const disconnectedCtx = useRef<SignerContextValue>({\n signCb: async () => {\n throw new Error('Para wallet not connected');\n },\n accountConfig: null as any,\n storeName: '',\n name: 'Para',\n isConnected: false,\n connect,\n disconnect,\n });\n const [signerContext, setSignerContext] = useState<SignerContextValue>(\n disconnectedCtx.current\n );\n\n useEffect(() => {\n let cancelled = false;\n\n async function buildContext() {\n if (!isConnected || !wallet) {\n setSignerContext(disconnectedCtx.current);\n return;\n }\n\n try {\n // Connected - build full context with signing capability\n const p = paraRef.current;\n const publicKey = await getUncompressedPublicKeyFromWallet(p, wallet);\n if (!publicKey) throw new Error('Failed to get public key from wallet');\n const commitment = await evmPkToCommitment(publicKey);\n\n // Serialize the commitment Word to Uint8Array for SignerAccountConfig\n const commitmentBytes = commitment.serialize();\n\n const signCallback = createSignCb(\n p,\n wallet,\n showSigningModalRef.current,\n customSignConfirmStepRef.current\n );\n\n if (!cancelled) {\n const { AccountStorageMode } = await import('@miden-sdk/miden-sdk');\n\n setSignerContext({\n signCb: signCallback,\n accountConfig: {\n publicKeyCommitment: commitmentBytes,\n accountType: 'RegularAccountImmutableCode',\n storageMode: AccountStorageMode.public(),\n ...(customComponents?.length ? { customComponents } : {}),\n },\n storeName: `para_${wallet.id}`,\n name: 'Para',\n isConnected: true,\n connect,\n disconnect,\n });\n }\n } catch (error) {\n console.error('Failed to build Para signer context:', error);\n if (!cancelled) {\n setSignerContext(disconnectedCtx.current);\n }\n }\n }\n\n buildContext();\n return () => {\n cancelled = true;\n };\n }, [isConnected, wallet, connect, disconnect]);\n\n return (\n <ParaSignerExtrasContext.Provider value={{ para, wallet }}>\n <SignerContext.Provider value={signerContext}>\n {children}\n </SignerContext.Provider>\n </ParaSignerExtrasContext.Provider>\n );\n}\n\n/**\n * Hook for Para-specific extras beyond the unified useSigner interface.\n * Use this to access the Para client or wallet details directly.\n *\n * @example\n * ```tsx\n * const { para, wallet, isConnected } = useParaSigner();\n * ```\n */\nexport function useParaSigner(): ParaSignerExtras & { isConnected: boolean } {\n const extras = useContext(ParaSignerExtrasContext);\n const signer = useContext(SignerContext);\n if (!extras) {\n throw new Error('useParaSigner must be used within ParaSignerProvider');\n }\n return { ...extras, isConnected: signer?.isConnected ?? false };\n}\n"],"mappings":"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","names":["useState","useEffect","useRef","useClient","useModal","useLogout"]}
@@ -0,0 +1,30 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface ParaVitePluginOptions {
4
+ /**
5
+ * Node.js polyfills to include. Para SDK requires these for crypto operations.
6
+ * Default: ["buffer", "crypto", "stream", "util"]
7
+ */
8
+ polyfills?: string[];
9
+ }
10
+ /**
11
+ * Vite plugin that configures Para SDK requirements:
12
+ * - Node.js polyfills (buffer, crypto, stream, util) via vite-plugin-node-polyfills
13
+ * - Stubs for unused Para wallet connectors (Solana, Cosmos)
14
+ *
15
+ * Returns an array of plugins (Vite flattens nested arrays in the plugins config).
16
+ *
17
+ * Requires `vite-plugin-node-polyfills` as a dev dependency.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { paraVitePlugin } from "@miden-sdk/use-miden-para-react/vite";
22
+ *
23
+ * export default defineConfig({
24
+ * plugins: [react(), midenVitePlugin(), paraVitePlugin()],
25
+ * });
26
+ * ```
27
+ */
28
+ declare function paraVitePlugin(options?: ParaVitePluginOptions): Plugin[];
29
+
30
+ export { type ParaVitePluginOptions, paraVitePlugin };
@@ -0,0 +1,30 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface ParaVitePluginOptions {
4
+ /**
5
+ * Node.js polyfills to include. Para SDK requires these for crypto operations.
6
+ * Default: ["buffer", "crypto", "stream", "util"]
7
+ */
8
+ polyfills?: string[];
9
+ }
10
+ /**
11
+ * Vite plugin that configures Para SDK requirements:
12
+ * - Node.js polyfills (buffer, crypto, stream, util) via vite-plugin-node-polyfills
13
+ * - Stubs for unused Para wallet connectors (Solana, Cosmos)
14
+ *
15
+ * Returns an array of plugins (Vite flattens nested arrays in the plugins config).
16
+ *
17
+ * Requires `vite-plugin-node-polyfills` as a dev dependency.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { paraVitePlugin } from "@miden-sdk/use-miden-para-react/vite";
22
+ *
23
+ * export default defineConfig({
24
+ * plugins: [react(), midenVitePlugin(), paraVitePlugin()],
25
+ * });
26
+ * ```
27
+ */
28
+ declare function paraVitePlugin(options?: ParaVitePluginOptions): Plugin[];
29
+
30
+ export { type ParaVitePluginOptions, paraVitePlugin };
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/paraVitePlugin.ts
21
+ var paraVitePlugin_exports = {};
22
+ __export(paraVitePlugin_exports, {
23
+ paraVitePlugin: () => paraVitePlugin
24
+ });
25
+ module.exports = __toCommonJS(paraVitePlugin_exports);
26
+ var import_node_module = require("module");
27
+ var STUB_PACKAGES = [
28
+ "@getpara/solana-wallet-connectors",
29
+ "@getpara/cosmos-wallet-connectors"
30
+ ];
31
+ var STUB_PREFIX = "\0para-stub:";
32
+ function paraVitePlugin(options) {
33
+ var _a;
34
+ const polyfills = (_a = options == null ? void 0 : options.polyfills) != null ? _a : ["buffer", "crypto", "stream", "util"];
35
+ let nodePolyfillsPlugins = [];
36
+ try {
37
+ const projectRequire = (0, import_node_module.createRequire)(`file://${process.cwd()}/`);
38
+ const { nodePolyfills } = projectRequire("vite-plugin-node-polyfills");
39
+ const result = nodePolyfills({ include: polyfills });
40
+ nodePolyfillsPlugins = Array.isArray(result) ? result : [result];
41
+ } catch {
42
+ console.warn(
43
+ "[@miden-sdk/para-vite-plugin] vite-plugin-node-polyfills not found. Install it: npm install -D vite-plugin-node-polyfills"
44
+ );
45
+ }
46
+ const stubConnectorsEsbuild = {
47
+ name: "stub-para-connectors",
48
+ setup(build) {
49
+ const filter = new RegExp(
50
+ `^(${STUB_PACKAGES.map((p) => p.replace(/[\\^$.*+?()[\]{}|/]/g, "\\$&")).join("|")})$`
51
+ );
52
+ build.onResolve({ filter }, (args) => ({
53
+ path: args.path,
54
+ namespace: "para-stub"
55
+ }));
56
+ build.onLoad(
57
+ { filter: /.*/, namespace: "para-stub" },
58
+ () => ({ contents: "export default {};", loader: "js" })
59
+ );
60
+ }
61
+ };
62
+ const paraPlugin = {
63
+ name: "@miden-sdk/para-vite-plugin",
64
+ enforce: "pre",
65
+ config() {
66
+ return {
67
+ resolve: {
68
+ dedupe: ["@getpara/web-sdk", "@getpara/react-sdk-lite"]
69
+ }
70
+ };
71
+ },
72
+ // Inject esbuild stub plugin after all config() hooks have run,
73
+ // so other plugins (e.g. vite-plugin-node-polyfills) can't overwrite it.
74
+ configResolved(config) {
75
+ if (!config.optimizeDeps.esbuildOptions) {
76
+ config.optimizeDeps.esbuildOptions = {};
77
+ }
78
+ if (!config.optimizeDeps.esbuildOptions.plugins) {
79
+ config.optimizeDeps.esbuildOptions.plugins = [];
80
+ }
81
+ const hasPlugin = config.optimizeDeps.esbuildOptions.plugins.some(
82
+ (p) => p.name === "stub-para-connectors"
83
+ );
84
+ if (!hasPlugin) {
85
+ config.optimizeDeps.esbuildOptions.plugins.push(stubConnectorsEsbuild);
86
+ }
87
+ },
88
+ // Stub the connector packages at Vite's module resolution level
89
+ // (handles imports that bypass pre-bundling, e.g. in SSR or dev).
90
+ resolveId(source) {
91
+ if (STUB_PACKAGES.includes(source)) {
92
+ return STUB_PREFIX + source;
93
+ }
94
+ },
95
+ load(id) {
96
+ if (id.startsWith(STUB_PREFIX)) {
97
+ return "export default {};";
98
+ }
99
+ }
100
+ };
101
+ return [paraPlugin, ...nodePolyfillsPlugins];
102
+ }
103
+ // Annotate the CommonJS export names for ESM import in node:
104
+ 0 && (module.exports = {
105
+ paraVitePlugin
106
+ });
107
+ //# sourceMappingURL=paraVitePlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/paraVitePlugin.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\nimport { createRequire } from \"node:module\";\n\nexport interface ParaVitePluginOptions {\n /**\n * Node.js polyfills to include. Para SDK requires these for crypto operations.\n * Default: [\"buffer\", \"crypto\", \"stream\", \"util\"]\n */\n polyfills?: string[];\n}\n\nconst STUB_PACKAGES = [\n \"@getpara/solana-wallet-connectors\",\n \"@getpara/cosmos-wallet-connectors\",\n];\n\nconst STUB_PREFIX = \"\\0para-stub:\";\n\n/**\n * Vite plugin that configures Para SDK requirements:\n * - Node.js polyfills (buffer, crypto, stream, util) via vite-plugin-node-polyfills\n * - Stubs for unused Para wallet connectors (Solana, Cosmos)\n *\n * Returns an array of plugins (Vite flattens nested arrays in the plugins config).\n *\n * Requires `vite-plugin-node-polyfills` as a dev dependency.\n *\n * @example\n * ```ts\n * import { paraVitePlugin } from \"@miden-sdk/use-miden-para-react/vite\";\n *\n * export default defineConfig({\n * plugins: [react(), midenVitePlugin(), paraVitePlugin()],\n * });\n * ```\n */\nexport function paraVitePlugin(options?: ParaVitePluginOptions): Plugin[] {\n const polyfills = options?.polyfills ?? [\"buffer\", \"crypto\", \"stream\", \"util\"];\n\n // Resolve nodePolyfills from the consuming project's node_modules (not\n // from this package's location) using createRequire with process.cwd().\n let nodePolyfillsPlugins: Plugin[] = [];\n try {\n const projectRequire = createRequire(`file://${process.cwd()}/`);\n const { nodePolyfills } = projectRequire(\"vite-plugin-node-polyfills\");\n const result = nodePolyfills({ include: polyfills });\n // nodePolyfills can return a single Plugin or Plugin[]\n nodePolyfillsPlugins = Array.isArray(result) ? result : [result];\n } catch {\n console.warn(\n \"[@miden-sdk/para-vite-plugin] vite-plugin-node-polyfills not found. \" +\n \"Install it: npm install -D vite-plugin-node-polyfills\"\n );\n }\n\n /**\n * Esbuild plugin that stubs the connector packages during Vite's dep\n * pre-bundling so esbuild doesn't leave unresolvable bare imports in\n * the pre-bundled output.\n */\n const stubConnectorsEsbuild = {\n name: \"stub-para-connectors\",\n setup(build: any) {\n const filter = new RegExp(\n `^(${STUB_PACKAGES.map((p) => p.replace(/[\\\\^$.*+?()[\\]{}|/]/g, \"\\\\$&\")).join(\"|\")})$`\n );\n build.onResolve({ filter }, (args: any) => ({\n path: args.path,\n namespace: \"para-stub\",\n }));\n build.onLoad(\n { filter: /.*/, namespace: \"para-stub\" },\n () => ({ contents: \"export default {};\", loader: \"js\" as const })\n );\n },\n };\n\n const paraPlugin: Plugin = {\n name: \"@miden-sdk/para-vite-plugin\",\n enforce: \"pre\",\n\n config() {\n return {\n resolve: {\n dedupe: [\"@getpara/web-sdk\", \"@getpara/react-sdk-lite\"],\n },\n };\n },\n\n // Inject esbuild stub plugin after all config() hooks have run,\n // so other plugins (e.g. vite-plugin-node-polyfills) can't overwrite it.\n configResolved(config) {\n if (!config.optimizeDeps.esbuildOptions) {\n config.optimizeDeps.esbuildOptions = {};\n }\n if (!config.optimizeDeps.esbuildOptions.plugins) {\n config.optimizeDeps.esbuildOptions.plugins = [];\n }\n const hasPlugin = config.optimizeDeps.esbuildOptions.plugins.some(\n (p: any) => p.name === \"stub-para-connectors\"\n );\n if (!hasPlugin) {\n config.optimizeDeps.esbuildOptions.plugins.push(stubConnectorsEsbuild);\n }\n },\n\n // Stub the connector packages at Vite's module resolution level\n // (handles imports that bypass pre-bundling, e.g. in SSR or dev).\n resolveId(source) {\n if (STUB_PACKAGES.includes(source)) {\n return STUB_PREFIX + source;\n }\n },\n\n load(id) {\n if (id.startsWith(STUB_PREFIX)) {\n return \"export default {};\";\n }\n },\n };\n\n return [paraPlugin, ...nodePolyfillsPlugins];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,yBAA8B;AAU9B,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AACF;AAEA,IAAM,cAAc;AAoBb,SAAS,eAAe,SAA2C;AApC1E;AAqCE,QAAM,aAAY,wCAAS,cAAT,YAAsB,CAAC,UAAU,UAAU,UAAU,MAAM;AAI7E,MAAI,uBAAiC,CAAC;AACtC,MAAI;AACF,UAAM,qBAAiB,kCAAc,UAAU,QAAQ,IAAI,CAAC,GAAG;AAC/D,UAAM,EAAE,cAAc,IAAI,eAAe,4BAA4B;AACrE,UAAM,SAAS,cAAc,EAAE,SAAS,UAAU,CAAC;AAEnD,2BAAuB,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AAAA,EACjE,QAAQ;AACN,YAAQ;AAAA,MACN;AAAA,IAEF;AAAA,EACF;AAOA,QAAM,wBAAwB;AAAA,IAC5B,MAAM;AAAA,IACN,MAAM,OAAY;AAChB,YAAM,SAAS,IAAI;AAAA,QACjB,KAAK,cAAc,IAAI,CAAC,MAAM,EAAE,QAAQ,wBAAwB,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC;AAAA,MACpF;AACA,YAAM,UAAU,EAAE,OAAO,GAAG,CAAC,UAAe;AAAA,QAC1C,MAAM,KAAK;AAAA,QACX,WAAW;AAAA,MACb,EAAE;AACF,YAAM;AAAA,QACJ,EAAE,QAAQ,MAAM,WAAW,YAAY;AAAA,QACvC,OAAO,EAAE,UAAU,sBAAsB,QAAQ,KAAc;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAqB;AAAA,IACzB,MAAM;AAAA,IACN,SAAS;AAAA,IAET,SAAS;AACP,aAAO;AAAA,QACL,SAAS;AAAA,UACP,QAAQ,CAAC,oBAAoB,yBAAyB;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA,IAIA,eAAe,QAAQ;AACrB,UAAI,CAAC,OAAO,aAAa,gBAAgB;AACvC,eAAO,aAAa,iBAAiB,CAAC;AAAA,MACxC;AACA,UAAI,CAAC,OAAO,aAAa,eAAe,SAAS;AAC/C,eAAO,aAAa,eAAe,UAAU,CAAC;AAAA,MAChD;AACA,YAAM,YAAY,OAAO,aAAa,eAAe,QAAQ;AAAA,QAC3D,CAAC,MAAW,EAAE,SAAS;AAAA,MACzB;AACA,UAAI,CAAC,WAAW;AACd,eAAO,aAAa,eAAe,QAAQ,KAAK,qBAAqB;AAAA,MACvE;AAAA,IACF;AAAA;AAAA;AAAA,IAIA,UAAU,QAAQ;AAChB,UAAI,cAAc,SAAS,MAAM,GAAG;AAClC,eAAO,cAAc;AAAA,MACvB;AAAA,IACF;AAAA,IAEA,KAAK,IAAI;AACP,UAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC,YAAY,GAAG,oBAAoB;AAC7C;","names":[]}
@@ -0,0 +1,82 @@
1
+ // src/paraVitePlugin.ts
2
+ import { createRequire } from "module";
3
+ var STUB_PACKAGES = [
4
+ "@getpara/solana-wallet-connectors",
5
+ "@getpara/cosmos-wallet-connectors"
6
+ ];
7
+ var STUB_PREFIX = "\0para-stub:";
8
+ function paraVitePlugin(options) {
9
+ var _a;
10
+ const polyfills = (_a = options == null ? void 0 : options.polyfills) != null ? _a : ["buffer", "crypto", "stream", "util"];
11
+ let nodePolyfillsPlugins = [];
12
+ try {
13
+ const projectRequire = createRequire(`file://${process.cwd()}/`);
14
+ const { nodePolyfills } = projectRequire("vite-plugin-node-polyfills");
15
+ const result = nodePolyfills({ include: polyfills });
16
+ nodePolyfillsPlugins = Array.isArray(result) ? result : [result];
17
+ } catch {
18
+ console.warn(
19
+ "[@miden-sdk/para-vite-plugin] vite-plugin-node-polyfills not found. Install it: npm install -D vite-plugin-node-polyfills"
20
+ );
21
+ }
22
+ const stubConnectorsEsbuild = {
23
+ name: "stub-para-connectors",
24
+ setup(build) {
25
+ const filter = new RegExp(
26
+ `^(${STUB_PACKAGES.map((p) => p.replace(/[\\^$.*+?()[\]{}|/]/g, "\\$&")).join("|")})$`
27
+ );
28
+ build.onResolve({ filter }, (args) => ({
29
+ path: args.path,
30
+ namespace: "para-stub"
31
+ }));
32
+ build.onLoad(
33
+ { filter: /.*/, namespace: "para-stub" },
34
+ () => ({ contents: "export default {};", loader: "js" })
35
+ );
36
+ }
37
+ };
38
+ const paraPlugin = {
39
+ name: "@miden-sdk/para-vite-plugin",
40
+ enforce: "pre",
41
+ config() {
42
+ return {
43
+ resolve: {
44
+ dedupe: ["@getpara/web-sdk", "@getpara/react-sdk-lite"]
45
+ }
46
+ };
47
+ },
48
+ // Inject esbuild stub plugin after all config() hooks have run,
49
+ // so other plugins (e.g. vite-plugin-node-polyfills) can't overwrite it.
50
+ configResolved(config) {
51
+ if (!config.optimizeDeps.esbuildOptions) {
52
+ config.optimizeDeps.esbuildOptions = {};
53
+ }
54
+ if (!config.optimizeDeps.esbuildOptions.plugins) {
55
+ config.optimizeDeps.esbuildOptions.plugins = [];
56
+ }
57
+ const hasPlugin = config.optimizeDeps.esbuildOptions.plugins.some(
58
+ (p) => p.name === "stub-para-connectors"
59
+ );
60
+ if (!hasPlugin) {
61
+ config.optimizeDeps.esbuildOptions.plugins.push(stubConnectorsEsbuild);
62
+ }
63
+ },
64
+ // Stub the connector packages at Vite's module resolution level
65
+ // (handles imports that bypass pre-bundling, e.g. in SSR or dev).
66
+ resolveId(source) {
67
+ if (STUB_PACKAGES.includes(source)) {
68
+ return STUB_PREFIX + source;
69
+ }
70
+ },
71
+ load(id) {
72
+ if (id.startsWith(STUB_PREFIX)) {
73
+ return "export default {};";
74
+ }
75
+ }
76
+ };
77
+ return [paraPlugin, ...nodePolyfillsPlugins];
78
+ }
79
+ export {
80
+ paraVitePlugin
81
+ };
82
+ //# sourceMappingURL=paraVitePlugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/paraVitePlugin.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\nimport { createRequire } from \"node:module\";\n\nexport interface ParaVitePluginOptions {\n /**\n * Node.js polyfills to include. Para SDK requires these for crypto operations.\n * Default: [\"buffer\", \"crypto\", \"stream\", \"util\"]\n */\n polyfills?: string[];\n}\n\nconst STUB_PACKAGES = [\n \"@getpara/solana-wallet-connectors\",\n \"@getpara/cosmos-wallet-connectors\",\n];\n\nconst STUB_PREFIX = \"\\0para-stub:\";\n\n/**\n * Vite plugin that configures Para SDK requirements:\n * - Node.js polyfills (buffer, crypto, stream, util) via vite-plugin-node-polyfills\n * - Stubs for unused Para wallet connectors (Solana, Cosmos)\n *\n * Returns an array of plugins (Vite flattens nested arrays in the plugins config).\n *\n * Requires `vite-plugin-node-polyfills` as a dev dependency.\n *\n * @example\n * ```ts\n * import { paraVitePlugin } from \"@miden-sdk/use-miden-para-react/vite\";\n *\n * export default defineConfig({\n * plugins: [react(), midenVitePlugin(), paraVitePlugin()],\n * });\n * ```\n */\nexport function paraVitePlugin(options?: ParaVitePluginOptions): Plugin[] {\n const polyfills = options?.polyfills ?? [\"buffer\", \"crypto\", \"stream\", \"util\"];\n\n // Resolve nodePolyfills from the consuming project's node_modules (not\n // from this package's location) using createRequire with process.cwd().\n let nodePolyfillsPlugins: Plugin[] = [];\n try {\n const projectRequire = createRequire(`file://${process.cwd()}/`);\n const { nodePolyfills } = projectRequire(\"vite-plugin-node-polyfills\");\n const result = nodePolyfills({ include: polyfills });\n // nodePolyfills can return a single Plugin or Plugin[]\n nodePolyfillsPlugins = Array.isArray(result) ? result : [result];\n } catch {\n console.warn(\n \"[@miden-sdk/para-vite-plugin] vite-plugin-node-polyfills not found. \" +\n \"Install it: npm install -D vite-plugin-node-polyfills\"\n );\n }\n\n /**\n * Esbuild plugin that stubs the connector packages during Vite's dep\n * pre-bundling so esbuild doesn't leave unresolvable bare imports in\n * the pre-bundled output.\n */\n const stubConnectorsEsbuild = {\n name: \"stub-para-connectors\",\n setup(build: any) {\n const filter = new RegExp(\n `^(${STUB_PACKAGES.map((p) => p.replace(/[\\\\^$.*+?()[\\]{}|/]/g, \"\\\\$&\")).join(\"|\")})$`\n );\n build.onResolve({ filter }, (args: any) => ({\n path: args.path,\n namespace: \"para-stub\",\n }));\n build.onLoad(\n { filter: /.*/, namespace: \"para-stub\" },\n () => ({ contents: \"export default {};\", loader: \"js\" as const })\n );\n },\n };\n\n const paraPlugin: Plugin = {\n name: \"@miden-sdk/para-vite-plugin\",\n enforce: \"pre\",\n\n config() {\n return {\n resolve: {\n dedupe: [\"@getpara/web-sdk\", \"@getpara/react-sdk-lite\"],\n },\n };\n },\n\n // Inject esbuild stub plugin after all config() hooks have run,\n // so other plugins (e.g. vite-plugin-node-polyfills) can't overwrite it.\n configResolved(config) {\n if (!config.optimizeDeps.esbuildOptions) {\n config.optimizeDeps.esbuildOptions = {};\n }\n if (!config.optimizeDeps.esbuildOptions.plugins) {\n config.optimizeDeps.esbuildOptions.plugins = [];\n }\n const hasPlugin = config.optimizeDeps.esbuildOptions.plugins.some(\n (p: any) => p.name === \"stub-para-connectors\"\n );\n if (!hasPlugin) {\n config.optimizeDeps.esbuildOptions.plugins.push(stubConnectorsEsbuild);\n }\n },\n\n // Stub the connector packages at Vite's module resolution level\n // (handles imports that bypass pre-bundling, e.g. in SSR or dev).\n resolveId(source) {\n if (STUB_PACKAGES.includes(source)) {\n return STUB_PREFIX + source;\n }\n },\n\n load(id) {\n if (id.startsWith(STUB_PREFIX)) {\n return \"export default {};\";\n }\n },\n };\n\n return [paraPlugin, ...nodePolyfillsPlugins];\n}\n"],"mappings":";AACA,SAAS,qBAAqB;AAU9B,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AACF;AAEA,IAAM,cAAc;AAoBb,SAAS,eAAe,SAA2C;AApC1E;AAqCE,QAAM,aAAY,wCAAS,cAAT,YAAsB,CAAC,UAAU,UAAU,UAAU,MAAM;AAI7E,MAAI,uBAAiC,CAAC;AACtC,MAAI;AACF,UAAM,iBAAiB,cAAc,UAAU,QAAQ,IAAI,CAAC,GAAG;AAC/D,UAAM,EAAE,cAAc,IAAI,eAAe,4BAA4B;AACrE,UAAM,SAAS,cAAc,EAAE,SAAS,UAAU,CAAC;AAEnD,2BAAuB,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AAAA,EACjE,QAAQ;AACN,YAAQ;AAAA,MACN;AAAA,IAEF;AAAA,EACF;AAOA,QAAM,wBAAwB;AAAA,IAC5B,MAAM;AAAA,IACN,MAAM,OAAY;AAChB,YAAM,SAAS,IAAI;AAAA,QACjB,KAAK,cAAc,IAAI,CAAC,MAAM,EAAE,QAAQ,wBAAwB,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC;AAAA,MACpF;AACA,YAAM,UAAU,EAAE,OAAO,GAAG,CAAC,UAAe;AAAA,QAC1C,MAAM,KAAK;AAAA,QACX,WAAW;AAAA,MACb,EAAE;AACF,YAAM;AAAA,QACJ,EAAE,QAAQ,MAAM,WAAW,YAAY;AAAA,QACvC,OAAO,EAAE,UAAU,sBAAsB,QAAQ,KAAc;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAqB;AAAA,IACzB,MAAM;AAAA,IACN,SAAS;AAAA,IAET,SAAS;AACP,aAAO;AAAA,QACL,SAAS;AAAA,UACP,QAAQ,CAAC,oBAAoB,yBAAyB;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA,IAIA,eAAe,QAAQ;AACrB,UAAI,CAAC,OAAO,aAAa,gBAAgB;AACvC,eAAO,aAAa,iBAAiB,CAAC;AAAA,MACxC;AACA,UAAI,CAAC,OAAO,aAAa,eAAe,SAAS;AAC/C,eAAO,aAAa,eAAe,UAAU,CAAC;AAAA,MAChD;AACA,YAAM,YAAY,OAAO,aAAa,eAAe,QAAQ;AAAA,QAC3D,CAAC,MAAW,EAAE,SAAS;AAAA,MACzB;AACA,UAAI,CAAC,WAAW;AACd,eAAO,aAAa,eAAe,QAAQ,KAAK,qBAAqB;AAAA,MACvE;AAAA,IACF;AAAA;AAAA;AAAA,IAIA,UAAU,QAAQ;AAChB,UAAI,cAAc,SAAS,MAAM,GAAG;AAClC,eAAO,cAAc;AAAA,MACvB;AAAA,IACF;AAAA,IAEA,KAAK,IAAI;AACP,UAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC,YAAY,GAAG,oBAAoB;AAC7C;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miden-sdk/use-miden-para-react",
3
- "version": "0.13.2",
3
+ "version": "0.13.4",
4
4
  "description": "React hook that wires Para accounts into a Miden client",
5
5
  "license": "MIT",
6
6
  "author": "Miden Labs",
@@ -21,6 +21,11 @@
21
21
  "types": "./dist/index.d.ts",
22
22
  "import": "./dist/index.mjs",
23
23
  "require": "./dist/index.cjs"
24
+ },
25
+ "./vite": {
26
+ "types": "./dist/paraVitePlugin.d.ts",
27
+ "import": "./dist/paraVitePlugin.mjs",
28
+ "require": "./dist/paraVitePlugin.cjs"
24
29
  }
25
30
  },
26
31
  "files": [
@@ -29,30 +34,40 @@
29
34
  "README.md",
30
35
  "package.json"
31
36
  ],
32
- "sideEffects": false,
37
+ "sideEffects": [
38
+ "*.css"
39
+ ],
33
40
  "scripts": {
34
41
  "build": "tsup",
35
42
  "prepack": "npm run build",
36
43
  "publish": "npm run build && npm publish --access public"
37
44
  },
38
45
  "peerDependencies": {
39
- "@miden-sdk/miden-sdk": "^0.13.1",
40
46
  "@getpara/react-sdk-lite": "^2.11.0",
41
47
  "@getpara/web-sdk": "^2.11.0",
42
48
  "@miden-sdk/miden-para": "^0.13.2",
43
- "@miden-sdk/react": "^0.13.1",
49
+ "@miden-sdk/miden-sdk": "^0.13.1",
50
+ "@miden-sdk/react": "^0.13.3",
44
51
  "@tanstack/react-query": "^5.0.0",
45
- "react": "^18.0.0 || ^19.0.0"
52
+ "react": "^18.0.0 || ^19.0.0",
53
+ "vite-plugin-node-polyfills": "^0.22.0"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "vite-plugin-node-polyfills": {
57
+ "optional": true
58
+ }
46
59
  },
47
60
  "devDependencies": {
48
- "@miden-sdk/miden-sdk": "^0.13.1",
49
61
  "@getpara/react-sdk-lite": "^2.11.0",
50
62
  "@getpara/web-sdk": "^2.11.0",
51
- "@miden-sdk/react": "^0.13.1",
63
+ "@miden-sdk/miden-sdk": "^0.13.1",
64
+ "@miden-sdk/react": "^0.13.3",
52
65
  "@tanstack/react-query": "^5.90.12",
66
+ "@types/node": "^25.3.5",
53
67
  "@types/react": "^19.2.5",
54
68
  "tsup": "^8.3.0",
55
- "typescript": "^5.9.3"
69
+ "typescript": "^5.9.3",
70
+ "vite": "^7.3.1"
56
71
  },
57
72
  "engines": {
58
73
  "node": ">=18"
@@ -1,3 +1,4 @@
1
+ import '@getpara/react-sdk-lite/styles.css';
1
2
  import {
2
3
  useState,
3
4
  useEffect,
@@ -11,14 +12,25 @@ import { ParaWeb, Environment, type Wallet } from '@getpara/web-sdk';
11
12
  import {
12
13
  ParaProvider,
13
14
  useClient,
15
+ useAccount as useParaAccount,
14
16
  useModal,
15
17
  useLogout,
16
18
  type ParaProviderProps,
17
19
  } from '@getpara/react-sdk-lite';
18
20
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
19
- import { SignerContext, type SignerContextValue } from '@miden-sdk/react';
20
- import { signCb as createSignCb, type CustomSignConfirmStep } from '@miden-sdk/miden-para';
21
- import { evmPkToCommitment, getUncompressedPublicKeyFromWallet } from '@miden-sdk/miden-para';
21
+ import {
22
+ SignerContext,
23
+ type SignerContextValue,
24
+ type SignerAccountConfig,
25
+ } from '@miden-sdk/react';
26
+ import {
27
+ signCb as createSignCb,
28
+ type CustomSignConfirmStep,
29
+ } from '@miden-sdk/miden-para';
30
+ import {
31
+ evmPkToCommitment,
32
+ getUncompressedPublicKeyFromWallet,
33
+ } from '@miden-sdk/miden-para';
22
34
 
23
35
  // Re-export Para hooks for convenience
24
36
  export { useModal, useLogout } from '@getpara/react-sdk-lite';
@@ -29,7 +41,13 @@ const defaultQueryClient = new QueryClient();
29
41
  // ================================================================================================
30
42
 
31
43
  /** Environment string values accepted by ParaSignerProvider */
32
- export type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT' | 'PRODUCTION';
44
+ export type ParaEnvironment =
45
+ | 'BETA'
46
+ | 'PROD'
47
+ | 'SANDBOX'
48
+ | 'DEV'
49
+ | 'DEVELOPMENT'
50
+ | 'PRODUCTION';
33
51
 
34
52
  /**
35
53
  * Convert environment string to Environment enum value.
@@ -37,7 +55,8 @@ export type ParaEnvironment = 'BETA' | 'PROD' | 'SANDBOX' | 'DEV' | 'DEVELOPMENT
37
55
  */
38
56
  function getEnvironmentValue(env: ParaEnvironment): Environment {
39
57
  // Handle aliases
40
- const normalizedEnv = env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;
58
+ const normalizedEnv =
59
+ env === 'DEVELOPMENT' ? 'BETA' : env === 'PRODUCTION' ? 'PROD' : env;
41
60
 
42
61
  // Try accessing the enum - Environment may be undefined in some test environments
43
62
  if (Environment && typeof Environment === 'object') {
@@ -70,7 +89,11 @@ export interface ParaSignerProviderProps {
70
89
  * Advanced: Additional config to pass to ParaProvider.
71
90
  * Use this for customizing OAuth methods, external wallets, etc.
72
91
  */
73
- paraProviderConfig?: Partial<Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>>;
92
+ paraProviderConfig?: Partial<
93
+ Omit<ParaProviderProps<any, any>, 'children' | 'paraClientConfig'>
94
+ >;
95
+ /** Optional custom account components to include in the account (e.g. from a compiled .masp package) */
96
+ customComponents?: SignerAccountConfig['customComponents'];
74
97
  }
75
98
 
76
99
  /**
@@ -107,6 +130,7 @@ export function ParaSignerProvider({
107
130
  customSignConfirmStep,
108
131
  queryClient,
109
132
  paraProviderConfig,
133
+ customComponents,
110
134
  }: ParaSignerProviderProps) {
111
135
  return (
112
136
  <QueryClientProvider client={queryClient ?? defaultQueryClient}>
@@ -121,6 +145,7 @@ export function ParaSignerProvider({
121
145
  <ParaSignerProviderInner
122
146
  showSigningModal={showSigningModal}
123
147
  customSignConfirmStep={customSignConfirmStep}
148
+ customComponents={customComponents}
124
149
  >
125
150
  {children}
126
151
  </ParaSignerProviderInner>
@@ -136,69 +161,59 @@ function ParaSignerProviderInner({
136
161
  children,
137
162
  showSigningModal = true,
138
163
  customSignConfirmStep,
139
- }: Pick<ParaSignerProviderProps, 'children' | 'showSigningModal' | 'customSignConfirmStep'>) {
164
+ customComponents,
165
+ }: Pick<
166
+ ParaSignerProviderProps,
167
+ 'children' | 'showSigningModal' | 'customSignConfirmStep' | 'customComponents'
168
+ >) {
140
169
  // Access Para modal from ParaProvider.
141
170
  // Store in refs to avoid re-render loops (these hooks return new objects each render).
142
- const { openModal } = useModal();
171
+ const { openModal, closeModal } = useModal();
143
172
  const { logoutAsync } = useLogout();
144
173
  const openModalRef = useRef(openModal);
174
+ const closeModalRef = useRef(closeModal);
145
175
  const logoutAsyncRef = useRef(logoutAsync);
146
- useEffect(() => { openModalRef.current = openModal; }, [openModal]);
147
- useEffect(() => { logoutAsyncRef.current = logoutAsync; }, [logoutAsync]);
176
+ useEffect(() => {
177
+ openModalRef.current = openModal;
178
+ }, [openModal]);
179
+ useEffect(() => {
180
+ closeModalRef.current = closeModal;
181
+ }, [closeModal]);
182
+ useEffect(() => {
183
+ logoutAsyncRef.current = logoutAsync;
184
+ }, [logoutAsync]);
148
185
 
149
186
  // Get the Para client from ParaProvider context (avoids creating a duplicate instance).
150
187
  // Store in a ref so downstream effects don't re-fire when the hook returns a new wrapper.
151
188
  const para = useClient()!;
152
189
  const paraRef = useRef(para);
153
- useEffect(() => { paraRef.current = para; }, [para]);
190
+ useEffect(() => {
191
+ paraRef.current = para;
192
+ }, [para]);
154
193
 
155
194
  // Keep props in refs so buildContext doesn't re-run when parent re-renders with new closures.
156
195
  const showSigningModalRef = useRef(showSigningModal);
157
196
  const customSignConfirmStepRef = useRef(customSignConfirmStep);
158
- useEffect(() => { showSigningModalRef.current = showSigningModal; }, [showSigningModal]);
159
- useEffect(() => { customSignConfirmStepRef.current = customSignConfirmStep; }, [customSignConfirmStep]);
160
-
161
- const [wallet, setWallet] = useState<Wallet | null>(null);
162
- const [isConnected, setIsConnected] = useState(false);
163
-
164
- // Check connection status on mount and periodically
165
197
  useEffect(() => {
166
- let cancelled = false;
167
-
168
- async function checkConnection() {
169
- try {
170
- const isLoggedIn = await paraRef.current.isFullyLoggedIn();
171
- if (!isLoggedIn || cancelled) {
172
- setIsConnected(false);
173
- setWallet(null);
174
- return;
175
- }
198
+ showSigningModalRef.current = showSigningModal;
199
+ }, [showSigningModal]);
200
+ useEffect(() => {
201
+ customSignConfirmStepRef.current = customSignConfirmStep;
202
+ }, [customSignConfirmStep]);
176
203
 
177
- const wallets = Object.values(await paraRef.current.getWallets());
178
- const evmWallets = wallets.filter((w) => w.type === 'EVM');
204
+ // Use Para SDK's reactive useAccount() hook to detect login state.
205
+ // This subscribes to the internal state machine instead of polling isFullyLoggedIn().
206
+ const { isConnected: paraIsConnected, embedded } = useParaAccount();
207
+ const evmWallets = embedded?.wallets?.filter((w) => w.type === 'EVM') ?? [];
208
+ const wallet = evmWallets.length > 0 ? (evmWallets[0] as unknown as Wallet) : null;
209
+ const isConnected = paraIsConnected && wallet !== null;
179
210
 
180
- if (evmWallets.length > 0 && !cancelled) {
181
- setWallet((prev) => prev?.id === evmWallets[0].id ? prev : evmWallets[0]);
182
- setIsConnected(true);
183
- } else if (!cancelled) {
184
- setIsConnected(false);
185
- setWallet(null);
186
- }
187
- } catch {
188
- if (!cancelled) {
189
- setIsConnected(false);
190
- setWallet(null);
191
- }
192
- }
211
+ // Close the modal when login is detected
212
+ useEffect(() => {
213
+ if (isConnected) {
214
+ closeModalRef.current();
193
215
  }
194
-
195
- checkConnection();
196
- const interval = setInterval(checkConnection, 2000);
197
- return () => {
198
- cancelled = true;
199
- clearInterval(interval);
200
- };
201
- }, []);
216
+ }, [isConnected]);
202
217
 
203
218
  // Connect opens the Para modal
204
219
  const connect = useCallback(async () => {
@@ -209,8 +224,6 @@ function ParaSignerProviderInner({
209
224
  const disconnect = useCallback(async () => {
210
225
  await logoutAsyncRef.current();
211
226
  await paraRef.current.logout();
212
- setIsConnected(false);
213
- setWallet(null);
214
227
  }, []);
215
228
 
216
229
  // Build signer context (includes connect/disconnect for unified useSigner hook).
@@ -224,7 +237,9 @@ function ParaSignerProviderInner({
224
237
  // A {isConnected:false} context makes MidenProvider's init effect return early
225
238
  // without creating any client, keeping the WASM module free for buildContext.
226
239
  const disconnectedCtx = useRef<SignerContextValue>({
227
- signCb: async () => { throw new Error('Para wallet not connected'); },
240
+ signCb: async () => {
241
+ throw new Error('Para wallet not connected');
242
+ },
228
243
  accountConfig: null as any,
229
244
  storeName: '',
230
245
  name: 'Para',
@@ -263,9 +278,7 @@ function ParaSignerProviderInner({
263
278
  );
264
279
 
265
280
  if (!cancelled) {
266
- const { AccountStorageMode } = await import(
267
- '@miden-sdk/miden-sdk'
268
- );
281
+ const { AccountStorageMode } = await import('@miden-sdk/miden-sdk');
269
282
 
270
283
  setSignerContext({
271
284
  signCb: signCallback,
@@ -273,6 +286,7 @@ function ParaSignerProviderInner({
273
286
  publicKeyCommitment: commitmentBytes,
274
287
  accountType: 'RegularAccountImmutableCode',
275
288
  storageMode: AccountStorageMode.public(),
289
+ ...(customComponents?.length ? { customComponents } : {}),
276
290
  },
277
291
  storeName: `para_${wallet.id}`,
278
292
  name: 'Para',
@@ -0,0 +1,123 @@
1
+ import type { Plugin } from "vite";
2
+ import { createRequire } from "node:module";
3
+
4
+ export interface ParaVitePluginOptions {
5
+ /**
6
+ * Node.js polyfills to include. Para SDK requires these for crypto operations.
7
+ * Default: ["buffer", "crypto", "stream", "util"]
8
+ */
9
+ polyfills?: string[];
10
+ }
11
+
12
+ const STUB_PACKAGES = [
13
+ "@getpara/solana-wallet-connectors",
14
+ "@getpara/cosmos-wallet-connectors",
15
+ ];
16
+
17
+ const STUB_PREFIX = "\0para-stub:";
18
+
19
+ /**
20
+ * Vite plugin that configures Para SDK requirements:
21
+ * - Node.js polyfills (buffer, crypto, stream, util) via vite-plugin-node-polyfills
22
+ * - Stubs for unused Para wallet connectors (Solana, Cosmos)
23
+ *
24
+ * Returns an array of plugins (Vite flattens nested arrays in the plugins config).
25
+ *
26
+ * Requires `vite-plugin-node-polyfills` as a dev dependency.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { paraVitePlugin } from "@miden-sdk/use-miden-para-react/vite";
31
+ *
32
+ * export default defineConfig({
33
+ * plugins: [react(), midenVitePlugin(), paraVitePlugin()],
34
+ * });
35
+ * ```
36
+ */
37
+ export function paraVitePlugin(options?: ParaVitePluginOptions): Plugin[] {
38
+ const polyfills = options?.polyfills ?? ["buffer", "crypto", "stream", "util"];
39
+
40
+ // Resolve nodePolyfills from the consuming project's node_modules (not
41
+ // from this package's location) using createRequire with process.cwd().
42
+ let nodePolyfillsPlugins: Plugin[] = [];
43
+ try {
44
+ const projectRequire = createRequire(`file://${process.cwd()}/`);
45
+ const { nodePolyfills } = projectRequire("vite-plugin-node-polyfills");
46
+ const result = nodePolyfills({ include: polyfills });
47
+ // nodePolyfills can return a single Plugin or Plugin[]
48
+ nodePolyfillsPlugins = Array.isArray(result) ? result : [result];
49
+ } catch {
50
+ console.warn(
51
+ "[@miden-sdk/para-vite-plugin] vite-plugin-node-polyfills not found. " +
52
+ "Install it: npm install -D vite-plugin-node-polyfills"
53
+ );
54
+ }
55
+
56
+ /**
57
+ * Esbuild plugin that stubs the connector packages during Vite's dep
58
+ * pre-bundling so esbuild doesn't leave unresolvable bare imports in
59
+ * the pre-bundled output.
60
+ */
61
+ const stubConnectorsEsbuild = {
62
+ name: "stub-para-connectors",
63
+ setup(build: any) {
64
+ const filter = new RegExp(
65
+ `^(${STUB_PACKAGES.map((p) => p.replace(/[\\^$.*+?()[\]{}|/]/g, "\\$&")).join("|")})$`
66
+ );
67
+ build.onResolve({ filter }, (args: any) => ({
68
+ path: args.path,
69
+ namespace: "para-stub",
70
+ }));
71
+ build.onLoad(
72
+ { filter: /.*/, namespace: "para-stub" },
73
+ () => ({ contents: "export default {};", loader: "js" as const })
74
+ );
75
+ },
76
+ };
77
+
78
+ const paraPlugin: Plugin = {
79
+ name: "@miden-sdk/para-vite-plugin",
80
+ enforce: "pre",
81
+
82
+ config() {
83
+ return {
84
+ resolve: {
85
+ dedupe: ["@getpara/web-sdk", "@getpara/react-sdk-lite"],
86
+ },
87
+ };
88
+ },
89
+
90
+ // Inject esbuild stub plugin after all config() hooks have run,
91
+ // so other plugins (e.g. vite-plugin-node-polyfills) can't overwrite it.
92
+ configResolved(config) {
93
+ if (!config.optimizeDeps.esbuildOptions) {
94
+ config.optimizeDeps.esbuildOptions = {};
95
+ }
96
+ if (!config.optimizeDeps.esbuildOptions.plugins) {
97
+ config.optimizeDeps.esbuildOptions.plugins = [];
98
+ }
99
+ const hasPlugin = config.optimizeDeps.esbuildOptions.plugins.some(
100
+ (p: any) => p.name === "stub-para-connectors"
101
+ );
102
+ if (!hasPlugin) {
103
+ config.optimizeDeps.esbuildOptions.plugins.push(stubConnectorsEsbuild);
104
+ }
105
+ },
106
+
107
+ // Stub the connector packages at Vite's module resolution level
108
+ // (handles imports that bypass pre-bundling, e.g. in SSR or dev).
109
+ resolveId(source) {
110
+ if (STUB_PACKAGES.includes(source)) {
111
+ return STUB_PREFIX + source;
112
+ }
113
+ },
114
+
115
+ load(id) {
116
+ if (id.startsWith(STUB_PREFIX)) {
117
+ return "export default {};";
118
+ }
119
+ },
120
+ };
121
+
122
+ return [paraPlugin, ...nodePolyfillsPlugins];
123
+ }