@miden-sdk/use-miden-para-react 0.13.3 → 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.js +14 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -38
- package/dist/index.mjs.map +1 -1
- package/dist/paraVitePlugin.d.mts +30 -0
- package/dist/paraVitePlugin.d.ts +30 -0
- package/dist/paraVitePlugin.js +107 -0
- package/dist/paraVitePlugin.js.map +1 -0
- package/dist/paraVitePlugin.mjs +82 -0
- package/dist/paraVitePlugin.mjs.map +1 -0
- package/package.json +19 -4
- package/src/ParaSignerProvider.tsx +17 -43
- package/src/paraVitePlugin.ts +123 -0
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");
|
|
@@ -162,13 +163,18 @@ function ParaSignerProviderInner({
|
|
|
162
163
|
customSignConfirmStep,
|
|
163
164
|
customComponents
|
|
164
165
|
}) {
|
|
165
|
-
|
|
166
|
+
var _a, _b;
|
|
167
|
+
const { openModal, closeModal } = (0, import_react_sdk_lite2.useModal)();
|
|
166
168
|
const { logoutAsync } = (0, import_react_sdk_lite2.useLogout)();
|
|
167
169
|
const openModalRef = (0, import_react2.useRef)(openModal);
|
|
170
|
+
const closeModalRef = (0, import_react2.useRef)(closeModal);
|
|
168
171
|
const logoutAsyncRef = (0, import_react2.useRef)(logoutAsync);
|
|
169
172
|
(0, import_react2.useEffect)(() => {
|
|
170
173
|
openModalRef.current = openModal;
|
|
171
174
|
}, [openModal]);
|
|
175
|
+
(0, import_react2.useEffect)(() => {
|
|
176
|
+
closeModalRef.current = closeModal;
|
|
177
|
+
}, [closeModal]);
|
|
172
178
|
(0, import_react2.useEffect)(() => {
|
|
173
179
|
logoutAsyncRef.current = logoutAsync;
|
|
174
180
|
}, [logoutAsync]);
|
|
@@ -185,51 +191,21 @@ function ParaSignerProviderInner({
|
|
|
185
191
|
(0, import_react2.useEffect)(() => {
|
|
186
192
|
customSignConfirmStepRef.current = customSignConfirmStep;
|
|
187
193
|
}, [customSignConfirmStep]);
|
|
188
|
-
const
|
|
189
|
-
const
|
|
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;
|
|
190
198
|
(0, import_react2.useEffect)(() => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
try {
|
|
194
|
-
const isLoggedIn = await paraRef.current.isFullyLoggedIn();
|
|
195
|
-
if (!isLoggedIn || cancelled) {
|
|
196
|
-
setIsConnected(false);
|
|
197
|
-
setWallet(null);
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
const wallets = Object.values(await paraRef.current.getWallets());
|
|
201
|
-
const evmWallets = wallets.filter((w) => w.type === "EVM");
|
|
202
|
-
if (evmWallets.length > 0 && !cancelled) {
|
|
203
|
-
setWallet(
|
|
204
|
-
(prev) => (prev == null ? void 0 : prev.id) === evmWallets[0].id ? prev : evmWallets[0]
|
|
205
|
-
);
|
|
206
|
-
setIsConnected(true);
|
|
207
|
-
} else if (!cancelled) {
|
|
208
|
-
setIsConnected(false);
|
|
209
|
-
setWallet(null);
|
|
210
|
-
}
|
|
211
|
-
} catch {
|
|
212
|
-
if (!cancelled) {
|
|
213
|
-
setIsConnected(false);
|
|
214
|
-
setWallet(null);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
199
|
+
if (isConnected) {
|
|
200
|
+
closeModalRef.current();
|
|
217
201
|
}
|
|
218
|
-
|
|
219
|
-
const interval = setInterval(checkConnection, 2e3);
|
|
220
|
-
return () => {
|
|
221
|
-
cancelled = true;
|
|
222
|
-
clearInterval(interval);
|
|
223
|
-
};
|
|
224
|
-
}, []);
|
|
202
|
+
}, [isConnected]);
|
|
225
203
|
const connect = (0, import_react2.useCallback)(async () => {
|
|
226
204
|
openModalRef.current();
|
|
227
205
|
}, []);
|
|
228
206
|
const disconnect = (0, import_react2.useCallback)(async () => {
|
|
229
207
|
await logoutAsyncRef.current();
|
|
230
208
|
await paraRef.current.logout();
|
|
231
|
-
setIsConnected(false);
|
|
232
|
-
setWallet(null);
|
|
233
209
|
}, []);
|
|
234
210
|
const disconnectedCtx = (0, import_react2.useRef)({
|
|
235
211
|
signCb: async () => {
|
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 {\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 } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => {\n openModalRef.current = openModal;\n }, [openModal]);\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 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) =>\n prev?.id === evmWallets[0].id ? prev : evmWallets[0]\n );\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 () => {\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","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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,4BAAmD;AACnD,mBAAqD;AACrD,wBAKO;AAgBA,SAAS,aACd,SACA,cAAuC,UACvC,OAAwD,CAAC,GACzD,mBAA4B,MAC5B,uBACA;AACA,QAAM,WAAO,iCAAU;AACvB,QAAM,EAAE,aAAa,SAAS,QAAI,kCAAW;AAC7C,QAAM,gBAAY;AAAA,IAChB;AAAA,EACF;AACA,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAiB,EAAE;AAErD,QAAM,iBAAa;AAAA,IACjB,MAAG;AAxCP;AAwCU,4BAAS,YAAT,mBAAkB,OAAO,CAAC,WAAW,OAAO,SAAS;AAAA;AAAA,IAC3D,CAAC,SAAS,OAAO;AAAA,EACnB;AAEA,8BAAU,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,UAAM;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,oBAAO;AACP,IAAAA,gBAQO;AACP,qBAAkD;AAClD,IAAAC,yBAOO;AACP,yBAAiD;AACjD,IAAAD,gBAIO;AACP,IAAAE,qBAGO;AACP,IAAAA,qBAGO;AAGP,IAAAD,yBAAoC;AA6G5B;AA3GR,IAAM,qBAAqB,IAAI,+BAAY;AAkB3C,SAAS,oBAAoB,KAAmC;AAE9D,QAAM,gBACJ,QAAQ,gBAAgB,SAAS,QAAQ,eAAe,SAAS;AAGnE,MAAI,8BAAe,OAAO,+BAAgB,UAAU;AAClD,UAAM,QAAQ,2BAAY,aAAyC;AACnE,QAAI,UAAU,OAAW,QAAO;AAAA,EAClC;AAGA,SAAO;AACT;AAwCA,IAAM,8BAA0B,6BAAuC,IAAI;AAepE,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,SACE,4CAAC,0CAAoB,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,UACA;AAAA,UAEC;AAAA;AAAA,MACH;AAAA;AAAA,EACF,GACF;AAEJ;AAKA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA,mBAAmB;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AAvKH;AA0KE,QAAM,EAAE,WAAW,WAAW,QAAI,iCAAS;AAC3C,QAAM,EAAE,YAAY,QAAI,kCAAU;AAClC,QAAM,mBAAe,sBAAO,SAAS;AACrC,QAAM,oBAAgB,sBAAO,UAAU;AACvC,QAAM,qBAAiB,sBAAO,WAAW;AACzC,+BAAU,MAAM;AACd,iBAAa,UAAU;AAAA,EACzB,GAAG,CAAC,SAAS,CAAC;AACd,+BAAU,MAAM;AACd,kBAAc,UAAU;AAAA,EAC1B,GAAG,CAAC,UAAU,CAAC;AACf,+BAAU,MAAM;AACd,mBAAe,UAAU;AAAA,EAC3B,GAAG,CAAC,WAAW,CAAC;AAIhB,QAAM,WAAO,kCAAU;AACvB,QAAM,cAAU,sBAAO,IAAI;AAC3B,+BAAU,MAAM;AACd,YAAQ,UAAU;AAAA,EACpB,GAAG,CAAC,IAAI,CAAC;AAGT,QAAM,0BAAsB,sBAAO,gBAAgB;AACnD,QAAM,+BAA2B,sBAAO,qBAAqB;AAC7D,+BAAU,MAAM;AACd,wBAAoB,UAAU;AAAA,EAChC,GAAG,CAAC,gBAAgB,CAAC;AACrB,+BAAU,MAAM;AACd,6BAAyB,UAAU;AAAA,EACrC,GAAG,CAAC,qBAAqB,CAAC;AAI1B,QAAM,EAAE,aAAa,iBAAiB,SAAS,QAAI,uBAAAE,YAAe;AAClE,QAAM,cAAa,gDAAU,YAAV,mBAAmB,OAAO,CAAC,MAAM,EAAE,SAAS,WAA5C,YAAsD,CAAC;AAC1E,QAAM,SAAS,WAAW,SAAS,IAAK,WAAW,CAAC,IAA0B;AAC9E,QAAM,cAAc,mBAAmB,WAAW;AAGlD,+BAAU,MAAM;AACd,QAAI,aAAa;AACf,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAGhB,QAAM,cAAU,2BAAY,YAAY;AACtC,iBAAa,QAAQ;AAAA,EACvB,GAAG,CAAC,CAAC;AAGL,QAAM,iBAAa,2BAAY,YAAY;AACzC,UAAM,eAAe,QAAQ;AAC7B,UAAM,QAAQ,QAAQ,OAAO;AAAA,EAC/B,GAAG,CAAC,CAAC;AAYL,QAAM,sBAAkB,sBAA2B;AAAA,IACjD,QAAQ,YAAY;AAClB,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAAA,IACA,eAAe;AAAA,IACf,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,CAAC,eAAe,gBAAgB,QAAI;AAAA,IACxC,gBAAgB;AAAA,EAClB;AAEA,+BAAU,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,UAAM,uDAAmC,GAAG,MAAM;AACpE,YAAI,CAAC,UAAW,OAAM,IAAI,MAAM,sCAAsC;AACtE,cAAM,aAAa,UAAM,sCAAkB,SAAS;AAGpD,cAAM,kBAAkB,WAAW,UAAU;AAE7C,cAAM,mBAAe,mBAAAC;AAAA,UACnB;AAAA,UACA;AAAA,UACA,oBAAoB;AAAA,UACpB,yBAAyB;AAAA,QAC3B;AAEA,YAAI,CAAC,WAAW;AACd,gBAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,sBAAsB;AAElE,2BAAiB;AAAA,YACf,QAAQ;AAAA,YACR,eAAe;AAAA,cACb,qBAAqB;AAAA,cACrB,aAAa;AAAA,cACb,aAAa,mBAAmB,OAAO;AAAA,cACvC,IAAI,qDAAkB,UAAS,EAAE,iBAAiB,IAAI,CAAC;AAAA,YACzD;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,4CAAC,wBAAwB,UAAxB,EAAiC,OAAO,EAAE,MAAM,OAAO,GACtD,sDAAC,4BAAc,UAAd,EAAuB,OAAO,eAC5B,UACH,GACF;AAEJ;AAWO,SAAS,gBAA6D;AAzU7E;AA0UE,QAAM,aAAS,0BAAW,uBAAuB;AACjD,QAAM,aAAS,0BAAW,2BAAa;AACvC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AACA,SAAO,EAAE,GAAG,QAAQ,cAAa,sCAAQ,gBAAR,YAAuB,MAAM;AAChE;","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,6 +80,7 @@ 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";
|
|
@@ -143,13 +145,18 @@ function ParaSignerProviderInner({
|
|
|
143
145
|
customSignConfirmStep,
|
|
144
146
|
customComponents
|
|
145
147
|
}) {
|
|
146
|
-
|
|
148
|
+
var _a, _b;
|
|
149
|
+
const { openModal, closeModal } = useModal();
|
|
147
150
|
const { logoutAsync } = useLogout();
|
|
148
151
|
const openModalRef = useRef2(openModal);
|
|
152
|
+
const closeModalRef = useRef2(closeModal);
|
|
149
153
|
const logoutAsyncRef = useRef2(logoutAsync);
|
|
150
154
|
useEffect2(() => {
|
|
151
155
|
openModalRef.current = openModal;
|
|
152
156
|
}, [openModal]);
|
|
157
|
+
useEffect2(() => {
|
|
158
|
+
closeModalRef.current = closeModal;
|
|
159
|
+
}, [closeModal]);
|
|
153
160
|
useEffect2(() => {
|
|
154
161
|
logoutAsyncRef.current = logoutAsync;
|
|
155
162
|
}, [logoutAsync]);
|
|
@@ -166,51 +173,21 @@ function ParaSignerProviderInner({
|
|
|
166
173
|
useEffect2(() => {
|
|
167
174
|
customSignConfirmStepRef.current = customSignConfirmStep;
|
|
168
175
|
}, [customSignConfirmStep]);
|
|
169
|
-
const
|
|
170
|
-
const
|
|
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;
|
|
171
180
|
useEffect2(() => {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
const isLoggedIn = await paraRef.current.isFullyLoggedIn();
|
|
176
|
-
if (!isLoggedIn || cancelled) {
|
|
177
|
-
setIsConnected(false);
|
|
178
|
-
setWallet(null);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const wallets = Object.values(await paraRef.current.getWallets());
|
|
182
|
-
const evmWallets = wallets.filter((w) => w.type === "EVM");
|
|
183
|
-
if (evmWallets.length > 0 && !cancelled) {
|
|
184
|
-
setWallet(
|
|
185
|
-
(prev) => (prev == null ? void 0 : prev.id) === evmWallets[0].id ? prev : evmWallets[0]
|
|
186
|
-
);
|
|
187
|
-
setIsConnected(true);
|
|
188
|
-
} else if (!cancelled) {
|
|
189
|
-
setIsConnected(false);
|
|
190
|
-
setWallet(null);
|
|
191
|
-
}
|
|
192
|
-
} catch {
|
|
193
|
-
if (!cancelled) {
|
|
194
|
-
setIsConnected(false);
|
|
195
|
-
setWallet(null);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
181
|
+
if (isConnected) {
|
|
182
|
+
closeModalRef.current();
|
|
198
183
|
}
|
|
199
|
-
|
|
200
|
-
const interval = setInterval(checkConnection, 2e3);
|
|
201
|
-
return () => {
|
|
202
|
-
cancelled = true;
|
|
203
|
-
clearInterval(interval);
|
|
204
|
-
};
|
|
205
|
-
}, []);
|
|
184
|
+
}, [isConnected]);
|
|
206
185
|
const connect = useCallback(async () => {
|
|
207
186
|
openModalRef.current();
|
|
208
187
|
}, []);
|
|
209
188
|
const disconnect = useCallback(async () => {
|
|
210
189
|
await logoutAsyncRef.current();
|
|
211
190
|
await paraRef.current.logout();
|
|
212
|
-
setIsConnected(false);
|
|
213
|
-
setWallet(null);
|
|
214
191
|
}, []);
|
|
215
192
|
const disconnectedCtx = useRef2({
|
|
216
193
|
signCb: async () => {
|
package/dist/index.mjs.map
CHANGED
|
@@ -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 {\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 } = useModal();\n const { logoutAsync } = useLogout();\n const openModalRef = useRef(openModal);\n const logoutAsyncRef = useRef(logoutAsync);\n useEffect(() => {\n openModalRef.current = openModal;\n }, [openModal]);\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 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) =>\n prev?.id === evmWallets[0].id ? prev : evmWallets[0]\n );\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 () => {\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"]}
|
|
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.
|
|
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,7 +34,9 @@
|
|
|
29
34
|
"README.md",
|
|
30
35
|
"package.json"
|
|
31
36
|
],
|
|
32
|
-
"sideEffects":
|
|
37
|
+
"sideEffects": [
|
|
38
|
+
"*.css"
|
|
39
|
+
],
|
|
33
40
|
"scripts": {
|
|
34
41
|
"build": "tsup",
|
|
35
42
|
"prepack": "npm run build",
|
|
@@ -42,7 +49,13 @@
|
|
|
42
49
|
"@miden-sdk/miden-sdk": "^0.13.1",
|
|
43
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
61
|
"@getpara/react-sdk-lite": "^2.11.0",
|
|
@@ -50,9 +63,11 @@
|
|
|
50
63
|
"@miden-sdk/miden-sdk": "^0.13.1",
|
|
51
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,6 +12,7 @@ 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,
|
|
@@ -166,13 +168,17 @@ function ParaSignerProviderInner({
|
|
|
166
168
|
>) {
|
|
167
169
|
// Access Para modal from ParaProvider.
|
|
168
170
|
// Store in refs to avoid re-render loops (these hooks return new objects each render).
|
|
169
|
-
const { openModal } = useModal();
|
|
171
|
+
const { openModal, closeModal } = useModal();
|
|
170
172
|
const { logoutAsync } = useLogout();
|
|
171
173
|
const openModalRef = useRef(openModal);
|
|
174
|
+
const closeModalRef = useRef(closeModal);
|
|
172
175
|
const logoutAsyncRef = useRef(logoutAsync);
|
|
173
176
|
useEffect(() => {
|
|
174
177
|
openModalRef.current = openModal;
|
|
175
178
|
}, [openModal]);
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
closeModalRef.current = closeModal;
|
|
181
|
+
}, [closeModal]);
|
|
176
182
|
useEffect(() => {
|
|
177
183
|
logoutAsyncRef.current = logoutAsync;
|
|
178
184
|
}, [logoutAsync]);
|
|
@@ -195,49 +201,19 @@ function ParaSignerProviderInner({
|
|
|
195
201
|
customSignConfirmStepRef.current = customSignConfirmStep;
|
|
196
202
|
}, [customSignConfirmStep]);
|
|
197
203
|
|
|
198
|
-
|
|
199
|
-
|
|
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;
|
|
200
210
|
|
|
201
|
-
//
|
|
211
|
+
// Close the modal when login is detected
|
|
202
212
|
useEffect(() => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
async function checkConnection() {
|
|
206
|
-
try {
|
|
207
|
-
const isLoggedIn = await paraRef.current.isFullyLoggedIn();
|
|
208
|
-
if (!isLoggedIn || cancelled) {
|
|
209
|
-
setIsConnected(false);
|
|
210
|
-
setWallet(null);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const wallets = Object.values(await paraRef.current.getWallets());
|
|
215
|
-
const evmWallets = wallets.filter((w) => w.type === 'EVM');
|
|
216
|
-
|
|
217
|
-
if (evmWallets.length > 0 && !cancelled) {
|
|
218
|
-
setWallet((prev) =>
|
|
219
|
-
prev?.id === evmWallets[0].id ? prev : evmWallets[0]
|
|
220
|
-
);
|
|
221
|
-
setIsConnected(true);
|
|
222
|
-
} else if (!cancelled) {
|
|
223
|
-
setIsConnected(false);
|
|
224
|
-
setWallet(null);
|
|
225
|
-
}
|
|
226
|
-
} catch {
|
|
227
|
-
if (!cancelled) {
|
|
228
|
-
setIsConnected(false);
|
|
229
|
-
setWallet(null);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
213
|
+
if (isConnected) {
|
|
214
|
+
closeModalRef.current();
|
|
232
215
|
}
|
|
233
|
-
|
|
234
|
-
checkConnection();
|
|
235
|
-
const interval = setInterval(checkConnection, 2000);
|
|
236
|
-
return () => {
|
|
237
|
-
cancelled = true;
|
|
238
|
-
clearInterval(interval);
|
|
239
|
-
};
|
|
240
|
-
}, []);
|
|
216
|
+
}, [isConnected]);
|
|
241
217
|
|
|
242
218
|
// Connect opens the Para modal
|
|
243
219
|
const connect = useCallback(async () => {
|
|
@@ -248,8 +224,6 @@ function ParaSignerProviderInner({
|
|
|
248
224
|
const disconnect = useCallback(async () => {
|
|
249
225
|
await logoutAsyncRef.current();
|
|
250
226
|
await paraRef.current.logout();
|
|
251
|
-
setIsConnected(false);
|
|
252
|
-
setWallet(null);
|
|
253
227
|
}, []);
|
|
254
228
|
|
|
255
229
|
// Build signer context (includes connect/disconnect for unified useSigner hook).
|
|
@@ -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
|
+
}
|