@parity/product-sdk 0.0.0-dev.312.0 → 0.0.0-dev.329.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/address/index.d.ts +3 -1
  2. package/dist/{chunk-BRZNHTLQ.js → chunk-7GM3HUZF.js} +2 -2
  3. package/dist/chunk-7GM3HUZF.js.map +1 -0
  4. package/dist/chunk-TUXU2VPS.js +14 -0
  5. package/dist/chunk-TUXU2VPS.js.map +1 -0
  6. package/dist/{chunk-DHRCWMY5.js → chunk-VWD6HK2C.js} +29 -20
  7. package/dist/chunk-VWD6HK2C.js.map +1 -0
  8. package/dist/core/index.d.ts +50 -3
  9. package/dist/core/index.js +3 -2
  10. package/dist/{dotns-bswWAmR2.d.ts → dotns-CtmOwVQW.d.ts} +2 -2
  11. package/dist/identity/index.d.ts +118 -89
  12. package/dist/identity/index.js +200 -78
  13. package/dist/identity/index.js.map +1 -1
  14. package/dist/index.d.ts +3 -53
  15. package/dist/index.js +3 -2
  16. package/dist/nfts/index.d.ts +1 -0
  17. package/dist/nfts/index.js +3 -0
  18. package/dist/nfts/index.js.map +1 -0
  19. package/dist/react/index.d.ts +5 -5
  20. package/dist/react/index.js +4 -3
  21. package/dist/react/index.js.map +1 -1
  22. package/dist/renderer/index.d.ts +1 -0
  23. package/dist/renderer/index.js +3 -0
  24. package/dist/renderer/index.js.map +1 -0
  25. package/dist/testing/index.d.ts +2 -2
  26. package/dist/testing/index.js +3 -5
  27. package/dist/testing/index.js.map +1 -1
  28. package/dist/{types-B5Zx4RNq.d.ts → types-BpWw-OJl.d.ts} +19 -9
  29. package/package.json +22 -11
  30. package/src/core/createApp.test.ts +194 -0
  31. package/src/core/createApp.ts +35 -22
  32. package/src/core/local-storage-api.ts +74 -0
  33. package/src/core/types.ts +18 -7
  34. package/src/identity/dotns-abis.ts +44 -9
  35. package/src/identity/dotns-addresses.test.ts +536 -0
  36. package/src/identity/dotns-addresses.ts +320 -0
  37. package/src/identity/dotns-errors.ts +2 -0
  38. package/src/identity/dotns-namehash.ts +2 -2
  39. package/src/identity/dotns-registry.test.ts +158 -3
  40. package/src/identity/dotns-registry.ts +71 -73
  41. package/src/identity/dotns.ts +2 -2
  42. package/src/identity/index.test.ts +43 -0
  43. package/src/identity/index.ts +10 -6
  44. package/src/identity/types.ts +0 -19
  45. package/src/index.ts +3 -2
  46. package/src/individuality/contract.test.ts +426 -2
  47. package/src/nfts/contract.test.ts +58 -0
  48. package/src/nfts/index.ts +8 -0
  49. package/src/react/context.ts +1 -1
  50. package/src/react/index.ts +1 -1
  51. package/src/react/provider.tsx +3 -3
  52. package/src/renderer/index.ts +10 -0
  53. package/src/testing.ts +14 -11
  54. package/dist/chunk-BRZNHTLQ.js.map +0 -1
  55. package/dist/chunk-DHRCWMY5.js.map +0 -1
  56. package/src/identity/product-account.test.ts +0 -130
  57. package/src/identity/product-account.ts +0 -115
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/context.ts","../../src/react/provider.tsx","../../src/react/useWallet.ts","../../src/react/useLocalStorage.ts","../../src/react/useChain.ts"],"names":["useState","useEffect","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * React context for Product SDK\n */\n\nimport { createContext, useContext } from \"react\";\nimport type { App } from \"../core/types.js\";\n\n/** Context for the Product SDK app instance */\nexport const ProductSDKContext = createContext<App | null>(null);\n\n/**\n * Hook to access the Product SDK app instance\n *\n * @throws If used outside of ProductSDKProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const app = useProductSDK();\n * // Use app.wallet, app.localStorage, etc.\n * }\n * ```\n */\nexport function useProductSDK(): App {\n const app = useContext(ProductSDKContext);\n if (!app) {\n throw new Error(\n \"useProductSDK must be used within a ProductSDKProvider. \" +\n 'Wrap your app with <ProductSDKProvider name=\"your-app\">.',\n );\n }\n return app;\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * ProductSDKProvider component\n */\n\nimport React, { useEffect, useState, type ReactNode } from \"react\";\nimport { ProductSDKContext } from \"./context.js\";\nimport { createApp } from \"../core/createApp.js\";\nimport type { App, LogLevel } from \"../core/types.js\";\n\n/** Props for ProductSDKProvider */\nexport interface ProductSDKProviderProps {\n /** Application name - used for storage namespacing and product account derivation */\n name: string;\n /** Log level (default: 'info') */\n logLevel?: LogLevel;\n /** Child components */\n children: ReactNode;\n /** Fallback to show while loading */\n fallback?: ReactNode;\n}\n\n/**\n * Provider component that initializes the Product SDK\n *\n * @example\n * ```tsx\n * import { ProductSDKProvider } from '@parity/product-sdk/react';\n *\n * function App() {\n * return (\n * <ProductSDKProvider name=\"my-app\" fallback={<Loading />}>\n * <MyApp />\n * </ProductSDKProvider>\n * );\n * }\n * ```\n */\nexport function ProductSDKProvider({\n name,\n logLevel = \"info\",\n children,\n fallback = null,\n}: ProductSDKProviderProps) {\n const [app, setApp] = useState<App | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n\n createApp({ name, logLevel })\n .then((createdApp) => {\n if (mounted) {\n setApp(createdApp);\n }\n })\n .catch((e) => {\n if (mounted) {\n setError(e instanceof Error ? e : new Error(String(e)));\n }\n });\n\n return () => {\n mounted = false;\n };\n }, [name, logLevel]);\n\n if (error) {\n throw error;\n }\n\n if (!app) {\n return <>{fallback}</>;\n }\n\n return <ProductSDKContext.Provider value={app}>{children}</ProductSDKContext.Provider>;\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * useWallet hook\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { useProductSDK } from \"./context.js\";\nimport type {\n Account,\n DotNsIdentitySignature,\n SignMessageWithDotNsIdentityArgs,\n} from \"../core/types.js\";\n\n/** Wallet hook state */\nexport interface UseWalletState {\n /** Whether wallet is connected */\n isConnected: boolean;\n /** Whether connection is in progress */\n isConnecting: boolean;\n /** Available accounts */\n accounts: Account[];\n /** Currently selected account */\n selectedAccount: Account | null;\n /** Last error */\n error: Error | null;\n}\n\n/** Wallet hook actions */\nexport interface UseWalletActions {\n /** Connect to wallet */\n connect: () => Promise<void>;\n /** Disconnect from wallet */\n disconnect: () => Promise<void>;\n /** Select an account */\n selectAccount: (address: string) => void;\n /** Sign a message */\n signMessage: (message: string | Uint8Array) => Promise<Uint8Array>;\n /** Sign a message with the account that owns a DotNS / People username identity. */\n signMessageWithDotNsIdentity: (\n args: SignMessageWithDotNsIdentityArgs,\n ) => Promise<DotNsIdentitySignature>;\n}\n\n/** Return type of useWallet */\nexport type UseWalletReturn = UseWalletState & UseWalletActions;\n\n/**\n * Hook for wallet connection and signing\n *\n * @example\n * ```tsx\n * function WalletButton() {\n * const { isConnected, accounts, connect, disconnect, selectAccount } = useWallet();\n *\n * if (!isConnected) {\n * return <button onClick={connect}>Connect Wallet</button>;\n * }\n *\n * return (\n * <div>\n * <select onChange={(e) => selectAccount(e.target.value)}>\n * {accounts.map((a) => (\n * <option key={a.address} value={a.address}>\n * {a.name || a.address}\n * </option>\n * ))}\n * </select>\n * <button onClick={disconnect}>Disconnect</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useWallet(): UseWalletReturn {\n const app = useProductSDK();\n\n const [state, setState] = useState<UseWalletState>({\n isConnected: false,\n isConnecting: false,\n accounts: [],\n selectedAccount: null,\n error: null,\n });\n\n const connect = useCallback(async () => {\n setState((s) => ({ ...s, isConnecting: true, error: null }));\n try {\n const result = await app.wallet.connect();\n setState((s) => ({\n ...s,\n isConnected: true,\n isConnecting: false,\n accounts: result.accounts,\n selectedAccount: result.accounts[0] || null,\n }));\n } catch (e) {\n setState((s) => ({\n ...s,\n isConnecting: false,\n error: e instanceof Error ? e : new Error(String(e)),\n }));\n }\n }, [app]);\n\n const disconnect = useCallback(async () => {\n await app.wallet.disconnect();\n setState({\n isConnected: false,\n isConnecting: false,\n accounts: [],\n selectedAccount: null,\n error: null,\n });\n }, [app]);\n\n const selectAccount = useCallback(\n (address: string) => {\n app.wallet.selectAccount(address);\n const account = state.accounts.find((a) => a.address === address) || null;\n setState((s) => ({ ...s, selectedAccount: account }));\n },\n [app, state.accounts],\n );\n\n const signMessage = useCallback(\n async (message: string | Uint8Array) => {\n return app.wallet.signMessage(message);\n },\n [app],\n );\n\n const signMessageWithDotNsIdentity = useCallback(\n async (args: SignMessageWithDotNsIdentityArgs) => {\n return app.wallet.signMessageWithDotNsIdentity(args);\n },\n [app],\n );\n\n // Subscribe to account changes\n useEffect(() => {\n const unsubscribe = app.wallet.onAccountChange((account) => {\n setState((s) => ({ ...s, selectedAccount: account }));\n });\n return unsubscribe;\n }, [app]);\n\n return {\n ...state,\n connect,\n disconnect,\n selectAccount,\n signMessage,\n signMessageWithDotNsIdentity,\n };\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * useLocalStorage hook\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { useProductSDK } from \"./context.js\";\n\n/**\n * Hook for key-value storage operations\n *\n * @param key - Storage key\n * @param defaultValue - Default value if key doesn't exist\n *\n * @example\n * ```tsx\n * function ThemeToggle() {\n * const [theme, setTheme, { loading }] = useLocalStorage('theme', 'light');\n *\n * if (loading) return <div>Loading...</div>;\n *\n * return (\n * <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>\n * Current: {theme}\n * </button>\n * );\n * }\n * ```\n */\nexport function useLocalStorage<T = string>(\n key: string,\n defaultValue?: T,\n): [T | null, (value: T) => Promise<void>, { loading: boolean; error: Error | null }] {\n const app = useProductSDK();\n\n const [value, setValue] = useState<T | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Load initial value\n useEffect(() => {\n let mounted = true;\n\n const loadValue = async () => {\n try {\n setLoading(true);\n const stored = await app.localStorage.getJSON<T>(key);\n if (mounted) {\n setValue(stored ?? defaultValue ?? null);\n setLoading(false);\n }\n } catch (e) {\n if (mounted) {\n setError(e instanceof Error ? e : new Error(String(e)));\n setLoading(false);\n }\n }\n };\n\n loadValue();\n\n return () => {\n mounted = false;\n };\n }, [app, key, defaultValue]);\n\n const setStoredValue = useCallback(\n async (newValue: T) => {\n try {\n setError(null);\n await app.localStorage.setJSON(key, newValue);\n setValue(newValue);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n throw e;\n }\n },\n [app, key],\n );\n\n return [value, setStoredValue, { loading, error }];\n}\n\n/**\n * Hook for string storage (simpler API)\n *\n * @param key - Storage key\n * @param defaultValue - Default value\n */\nexport function useLocalStorageString(\n key: string,\n defaultValue?: string,\n): [string | null, (value: string) => Promise<void>, { loading: boolean }] {\n const app = useProductSDK();\n\n const [value, setValue] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let mounted = true;\n\n const loadValue = async () => {\n const stored = await app.localStorage.get(key);\n if (mounted) {\n setValue(stored ?? defaultValue ?? null);\n setLoading(false);\n }\n };\n\n loadValue();\n\n return () => {\n mounted = false;\n };\n }, [app, key, defaultValue]);\n\n const setStoredValue = useCallback(\n async (newValue: string) => {\n await app.localStorage.set(key, newValue);\n setValue(newValue);\n },\n [app, key],\n );\n\n return [value, setStoredValue, { loading }];\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * useChain hook\n */\n\nimport { useMemo } from \"react\";\nimport { useProductSDK } from \"./context.js\";\nimport type { ChainDefinition, TypedApi } from \"../core/types.js\";\n\n/**\n * Hook to get a typed chain client\n *\n * @param chain - Chain descriptor (PAPI ChainDefinition)\n *\n * @example\n * ```tsx\n * import { paseo_asset_hub } from '@parity/product-sdk-descriptors/paseo-asset-hub';\n * import { useChain } from '@parity/product-sdk/react';\n *\n * function AssetHubBalance() {\n * const assetHub = useChain(paseo_asset_hub);\n *\n * // assetHub is typed for Asset Hub queries\n * const balance = await assetHub.query.System.Account.getValue(address);\n * }\n * ```\n */\nexport function useChain<T extends ChainDefinition>(chain: T): TypedApi<T> {\n const app = useProductSDK();\n\n return useMemo(() => {\n return app.chain.getClient(chain);\n }, [app, chain]);\n}\n"]}
1
+ {"version":3,"sources":["../../src/react/context.ts","../../src/react/provider.tsx","../../src/react/useWallet.ts","../../src/react/useLocalStorage.ts","../../src/react/useChain.ts"],"names":["useState","useEffect","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * React context for Product SDK\n */\n\nimport { createContext, useContext } from \"react\";\nimport type { App } from \"../core/types.js\";\n\n/** Context for the Product SDK app instance */\nexport const ProductSDKContext = createContext<App | null>(null);\n\n/**\n * Hook to access the Product SDK app instance\n *\n * @throws If used outside of ProductSDKProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const app = useProductSDK();\n * // Use app.wallet, app.localStorage, etc.\n * }\n * ```\n */\nexport function useProductSDK(): App {\n const app = useContext(ProductSDKContext);\n if (!app) {\n throw new Error(\n \"useProductSDK must be used within a ProductSDKProvider. \" +\n \"Wrap your app with <ProductSDKProvider>.\",\n );\n }\n return app;\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * ProductSDKProvider component\n */\n\nimport React, { useEffect, useState, type ReactNode } from \"react\";\nimport { ProductSDKContext } from \"./context.js\";\nimport { createApp } from \"../core/createApp.js\";\nimport type { App, LogLevel } from \"../core/types.js\";\n\n/** Props for ProductSDKProvider */\nexport interface ProductSDKProviderProps {\n /** @deprecated Ignored with a warning. The host product ID supplies the app name. */\n name?: string;\n /** Log level (default: 'info') */\n logLevel?: LogLevel;\n /** Child components */\n children: ReactNode;\n /** Fallback to show while loading */\n fallback?: ReactNode;\n}\n\n/**\n * Provider component that initializes the Product SDK\n *\n * @example\n * ```tsx\n * import { ProductSDKProvider } from '@parity/product-sdk/react';\n *\n * function App() {\n * return (\n * <ProductSDKProvider fallback={<Loading />}>\n * <MyApp />\n * </ProductSDKProvider>\n * );\n * }\n * ```\n */\nexport function ProductSDKProvider({\n name,\n logLevel = \"info\",\n children,\n fallback = null,\n}: ProductSDKProviderProps) {\n const [app, setApp] = useState<App | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n\n createApp({ name, logLevel })\n .then((createdApp) => {\n if (mounted) {\n setApp(createdApp);\n }\n })\n .catch((e) => {\n if (mounted) {\n setError(e instanceof Error ? e : new Error(String(e)));\n }\n });\n\n return () => {\n mounted = false;\n };\n }, [name, logLevel]);\n\n if (error) {\n throw error;\n }\n\n if (!app) {\n return <>{fallback}</>;\n }\n\n return <ProductSDKContext.Provider value={app}>{children}</ProductSDKContext.Provider>;\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * useWallet hook\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { useProductSDK } from \"./context.js\";\nimport type {\n Account,\n DotNsIdentitySignature,\n SignMessageWithDotNsIdentityArgs,\n} from \"../core/types.js\";\n\n/** Wallet hook state */\nexport interface UseWalletState {\n /** Whether wallet is connected */\n isConnected: boolean;\n /** Whether connection is in progress */\n isConnecting: boolean;\n /** Available accounts */\n accounts: Account[];\n /** Currently selected account */\n selectedAccount: Account | null;\n /** Last error */\n error: Error | null;\n}\n\n/** Wallet hook actions */\nexport interface UseWalletActions {\n /** Connect to wallet */\n connect: () => Promise<void>;\n /** Disconnect from wallet */\n disconnect: () => Promise<void>;\n /** Select an account */\n selectAccount: (address: string) => void;\n /** Sign a message */\n signMessage: (message: string | Uint8Array) => Promise<Uint8Array>;\n /** Sign a message with the account that owns a DotNS / People username identity. */\n signMessageWithDotNsIdentity: (\n args: SignMessageWithDotNsIdentityArgs,\n ) => Promise<DotNsIdentitySignature>;\n}\n\n/** Return type of useWallet */\nexport type UseWalletReturn = UseWalletState & UseWalletActions;\n\n/**\n * Hook for wallet connection and signing\n *\n * @example\n * ```tsx\n * function WalletButton() {\n * const { isConnected, accounts, connect, disconnect, selectAccount } = useWallet();\n *\n * if (!isConnected) {\n * return <button onClick={connect}>Connect Wallet</button>;\n * }\n *\n * return (\n * <div>\n * <select onChange={(e) => selectAccount(e.target.value)}>\n * {accounts.map((a) => (\n * <option key={a.address} value={a.address}>\n * {a.name || a.address}\n * </option>\n * ))}\n * </select>\n * <button onClick={disconnect}>Disconnect</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useWallet(): UseWalletReturn {\n const app = useProductSDK();\n\n const [state, setState] = useState<UseWalletState>({\n isConnected: false,\n isConnecting: false,\n accounts: [],\n selectedAccount: null,\n error: null,\n });\n\n const connect = useCallback(async () => {\n setState((s) => ({ ...s, isConnecting: true, error: null }));\n try {\n const result = await app.wallet.connect();\n setState((s) => ({\n ...s,\n isConnected: true,\n isConnecting: false,\n accounts: result.accounts,\n selectedAccount: result.accounts[0] || null,\n }));\n } catch (e) {\n setState((s) => ({\n ...s,\n isConnecting: false,\n error: e instanceof Error ? e : new Error(String(e)),\n }));\n }\n }, [app]);\n\n const disconnect = useCallback(async () => {\n await app.wallet.disconnect();\n setState({\n isConnected: false,\n isConnecting: false,\n accounts: [],\n selectedAccount: null,\n error: null,\n });\n }, [app]);\n\n const selectAccount = useCallback(\n (address: string) => {\n app.wallet.selectAccount(address);\n const account = state.accounts.find((a) => a.address === address) || null;\n setState((s) => ({ ...s, selectedAccount: account }));\n },\n [app, state.accounts],\n );\n\n const signMessage = useCallback(\n async (message: string | Uint8Array) => {\n return app.wallet.signMessage(message);\n },\n [app],\n );\n\n const signMessageWithDotNsIdentity = useCallback(\n async (args: SignMessageWithDotNsIdentityArgs) => {\n return app.wallet.signMessageWithDotNsIdentity(args);\n },\n [app],\n );\n\n // Subscribe to account changes\n useEffect(() => {\n const unsubscribe = app.wallet.onAccountChange((account) => {\n setState((s) => ({ ...s, selectedAccount: account }));\n });\n return unsubscribe;\n }, [app]);\n\n return {\n ...state,\n connect,\n disconnect,\n selectAccount,\n signMessage,\n signMessageWithDotNsIdentity,\n };\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * useLocalStorage hook\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { useProductSDK } from \"./context.js\";\n\n/**\n * Hook for key-value storage operations\n *\n * @param key - Storage key\n * @param defaultValue - Default value if key doesn't exist\n *\n * @example\n * ```tsx\n * function ThemeToggle() {\n * const [theme, setTheme, { loading }] = useLocalStorage('theme', 'light');\n *\n * if (loading) return <div>Loading...</div>;\n *\n * return (\n * <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>\n * Current: {theme}\n * </button>\n * );\n * }\n * ```\n */\nexport function useLocalStorage<T = string>(\n key: string,\n defaultValue?: T,\n): [T | null, (value: T) => Promise<void>, { loading: boolean; error: Error | null }] {\n const app = useProductSDK();\n\n const [value, setValue] = useState<T | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Load initial value\n useEffect(() => {\n let mounted = true;\n\n const loadValue = async () => {\n try {\n setLoading(true);\n const stored = await app.localStorage.getJSON<T>(key);\n if (mounted) {\n setValue(stored ?? defaultValue ?? null);\n setLoading(false);\n }\n } catch (e) {\n if (mounted) {\n setError(e instanceof Error ? e : new Error(String(e)));\n setLoading(false);\n }\n }\n };\n\n loadValue();\n\n return () => {\n mounted = false;\n };\n }, [app, key, defaultValue]);\n\n const setStoredValue = useCallback(\n async (newValue: T) => {\n try {\n setError(null);\n await app.localStorage.setJSON(key, newValue);\n setValue(newValue);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n throw e;\n }\n },\n [app, key],\n );\n\n return [value, setStoredValue, { loading, error }];\n}\n\n/**\n * Hook for string storage (simpler API)\n *\n * @param key - Storage key\n * @param defaultValue - Default value\n */\nexport function useLocalStorageString(\n key: string,\n defaultValue?: string,\n): [string | null, (value: string) => Promise<void>, { loading: boolean }] {\n const app = useProductSDK();\n\n const [value, setValue] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let mounted = true;\n\n const loadValue = async () => {\n const stored = await app.localStorage.get(key);\n if (mounted) {\n setValue(stored ?? defaultValue ?? null);\n setLoading(false);\n }\n };\n\n loadValue();\n\n return () => {\n mounted = false;\n };\n }, [app, key, defaultValue]);\n\n const setStoredValue = useCallback(\n async (newValue: string) => {\n await app.localStorage.set(key, newValue);\n setValue(newValue);\n },\n [app, key],\n );\n\n return [value, setStoredValue, { loading }];\n}\n","// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * useChain hook\n */\n\nimport { useMemo } from \"react\";\nimport { useProductSDK } from \"./context.js\";\nimport type { ChainDefinition, TypedApi } from \"../core/types.js\";\n\n/**\n * Hook to get a typed chain client\n *\n * @param chain - Chain descriptor (PAPI ChainDefinition)\n *\n * @example\n * ```tsx\n * import { paseo_asset_hub } from '@parity/product-sdk-descriptors/paseo-asset-hub';\n * import { useChain } from '@parity/product-sdk/react';\n *\n * function AssetHubBalance() {\n * const assetHub = useChain(paseo_asset_hub);\n *\n * // assetHub is typed for Asset Hub queries\n * const balance = await assetHub.query.System.Account.getValue(address);\n * }\n * ```\n */\nexport function useChain<T extends ChainDefinition>(chain: T): TypedApi<T> {\n const app = useProductSDK();\n\n return useMemo(() => {\n return app.chain.getClient(chain);\n }, [app, chain]);\n}\n"]}
@@ -0,0 +1 @@
1
+ export * from '@parity/product-sdk-renderer';
@@ -0,0 +1,3 @@
1
+ export * from '@parity/product-sdk-renderer';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}
@@ -1,4 +1,4 @@
1
- import { A as Account, L as LocalStorageApi, C as ChainApi, a as CloudStorageApi, b as App } from '../types-B5Zx4RNq.js';
1
+ import { A as Account, L as LocalStorageApi, C as ChainApi, a as CloudStorageApi, b as App } from '../types-BpWw-OJl.js';
2
2
  export * from '@parity/product-sdk-local-storage/testing';
3
3
  export * from '@parity/product-sdk-signer/testing';
4
4
  export * from '@parity/product-sdk-contracts/testing';
@@ -7,7 +7,7 @@ import '@parity/product-sdk-logger';
7
7
  import '@parity/product-sdk-cloud-storage';
8
8
  import '@parity/result';
9
9
  import '@parity/product-sdk-chain-client';
10
- import '../dotns-bswWAmR2.js';
10
+ import '../dotns-CtmOwVQW.js';
11
11
  import 'polkadot-api';
12
12
 
13
13
  /** Configurable behavior for the fake {@link WalletApi}. */
@@ -1,3 +1,4 @@
1
+ import { createLocalStorageApi } from '../chunk-TUXU2VPS.js';
1
2
  import { ProductCloudStorageError } from '@parity/product-sdk-cloud-storage';
2
3
  import { createFakeHostLocalStorage } from '@parity/product-sdk-local-storage/testing';
3
4
  export * from '@parity/product-sdk-local-storage/testing';
@@ -6,7 +7,6 @@ export * from '@parity/product-sdk-signer/testing';
6
7
  export * from '@parity/product-sdk-contracts/testing';
7
8
  export * from '@parity/product-sdk-host/testing';
8
9
 
9
- // src/testing.ts
10
10
  var textEncoder = new TextEncoder();
11
11
  function makeFakeWallet(options) {
12
12
  const accounts = options?.accounts ?? [];
@@ -63,7 +63,7 @@ function makeFakeWallet(options) {
63
63
  }
64
64
  function makeFakeLocalStorage() {
65
65
  const host = createFakeHostLocalStorage();
66
- return {
66
+ const kv = {
67
67
  async get(key) {
68
68
  return await host.readString(key) || null;
69
69
  },
@@ -78,11 +78,9 @@ function makeFakeLocalStorage() {
78
78
  },
79
79
  async remove(key) {
80
80
  await host.clear(key);
81
- },
82
- async clear() {
83
- host.reset();
84
81
  }
85
82
  };
83
+ return createLocalStorageApi(kv);
86
84
  }
87
85
  function makeFakeCloudStorage() {
88
86
  const store = /* @__PURE__ */ new Map();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * Test fakes for `@parity/product-sdk` (umbrella).\n *\n * `createFakeApp` returns a fake {@link App} — use it directly in logic tests or\n * hand it to `ProductSDKContext.Provider` for React component tests, so code that\n * calls `useProductSDK()` / `useWallet()` runs with no host. This entry also\n * re-exports every package's fakes, for a single meta-package import.\n *\n * @packageDocumentation\n */\nimport { ProductCloudStorageError } from \"@parity/product-sdk-cloud-storage\";\nimport { createFakeHostLocalStorage } from \"@parity/product-sdk-local-storage/testing\";\nimport { err, ok, unwrapErr, unwrapOk } from \"@parity/result\";\n\nimport type {\n Account,\n App,\n ChainApi,\n CloudStorageApi,\n LocalStorageApi,\n WalletApi,\n} from \"./core/types.js\";\n\nconst textEncoder = new TextEncoder();\n\n// Re-export the per-package fakes so `@parity/product-sdk/testing` is a one-stop import.\n// statement-store is deliberately absent: the umbrella doesn't wrap that package, so apps\n// using it depend on it directly — import `@parity/product-sdk-statement-store/testing`\n// there instead. Re-exporting its fake here would add a dependency the umbrella otherwise\n// doesn't have and could skew against the version the app actually installs.\nexport * from \"@parity/product-sdk-local-storage/testing\";\nexport * from \"@parity/product-sdk-signer/testing\";\nexport * from \"@parity/product-sdk-contracts/testing\";\nexport * from \"@parity/product-sdk-host/testing\";\n\n/** Configurable behavior for the fake {@link WalletApi}. */\nexport interface FakeWalletOptions {\n /** Accounts `connect()` / `getAccounts()` expose. Default: none. */\n accounts?: Account[];\n /** Initially selected account. Default: the first account, or `null`. */\n selected?: Account | null;\n /** Bytes returned by `signMessage` / `createProof`. Default: 64 zero bytes. */\n signature?: Uint8Array;\n /** Value returned by `getProductAccount()`. Default: the selected account. */\n productAccount?: Account | null;\n /** Value returned by `getAnonymousAlias()`. Default: `null`. */\n anonymousAlias?: string | null;\n}\n\n/** Options for {@link createFakeApp}. */\nexport interface CreateFakeAppOptions {\n /** App name reported by `getAppInfo()`. Default: `\"fake-app\"`. */\n name?: string;\n /** Configure the fake wallet. */\n wallet?: FakeWalletOptions;\n /** Override the local-storage API. Default: in-memory (backed by `createFakeHostLocalStorage`). */\n localStorage?: LocalStorageApi;\n /** Override the chain API. Default: unconfigured (throws until you provide one). */\n chain?: ChainApi;\n /** Override cloud storage, or pass `null` to disable it. Default: an in-memory fake. */\n cloudStorage?: CloudStorageApi | null;\n}\n\nfunction makeFakeWallet(options?: FakeWalletOptions): WalletApi {\n const accounts = options?.accounts ?? [];\n let selected = options?.selected !== undefined ? options.selected : (accounts[0] ?? null);\n const signature = options?.signature ?? new Uint8Array(64);\n const listeners = new Set<(account: Account | null) => void>();\n const notify = () => {\n for (const l of listeners) l(selected);\n };\n\n return {\n async connect() {\n return { accounts };\n },\n async disconnect() {\n selected = null;\n notify();\n },\n getAccounts() {\n return accounts;\n },\n getSelectedAccount() {\n return selected;\n },\n selectAccount(address) {\n selected = accounts.find((a) => a.address === address) ?? null;\n notify();\n },\n async signMessage() {\n return signature;\n },\n async signMessageWithDotNsIdentity(args) {\n return {\n username: args.username ?? \"alice\",\n accountId: `0x${\"00\".repeat(32)}`,\n signature,\n };\n },\n onAccountChange(callback) {\n listeners.add(callback);\n return () => {\n listeners.delete(callback);\n };\n },\n getProductAccount() {\n return options?.productAccount !== undefined ? options.productAccount : selected;\n },\n getAnonymousAlias() {\n return options?.anonymousAlias ?? null;\n },\n async createProof() {\n return signature;\n },\n };\n}\n\nfunction makeFakeLocalStorage(): LocalStorageApi {\n // Compose the local-storage fake; mirror createApp's adapter semantics\n // (get normalizes \"\" -> null, getJSON normalizes undefined -> null).\n const host = createFakeHostLocalStorage();\n return {\n async get(key) {\n return (await host.readString(key)) || null;\n },\n async set(key, value) {\n await host.writeString(key, value);\n },\n async getJSON<T>(key: string) {\n return ((await host.readJSON(key)) ?? null) as T | null;\n },\n async setJSON<T>(key: string, value: T) {\n await host.writeJSON(key, value);\n },\n async remove(key) {\n await host.clear(key);\n },\n async clear() {\n // Unlike the production adapter (a no-op in container mode), the fake\n // actually empties, so tests get real isolation.\n host.reset();\n },\n };\n}\n\nfunction makeFakeCloudStorage(): CloudStorageApi {\n const store = new Map<string, Uint8Array>();\n const toBytes = (data: string | Uint8Array) =>\n typeof data === \"string\" ? textEncoder.encode(data) : data;\n // Deterministic content-addressed id so upload / computeCid / fetch line up.\n const cidOf = (bytes: Uint8Array) => {\n let h = 0x811c9dc5;\n for (const b of bytes) {\n h ^= b;\n h = Math.imul(h, 0x01000193);\n }\n return `bafyfake${(h >>> 0).toString(16).padStart(8, \"0\")}`;\n };\n return {\n async upload(data) {\n const bytes = toBytes(data);\n const cid = cidOf(bytes);\n store.set(cid, bytes);\n return ok(cid);\n },\n async fetch(cid) {\n const bytes = store.get(cid);\n if (!bytes) {\n return err(\n new ProductCloudStorageError(\n `fake cloud storage: no object stored for CID ${cid}`,\n ),\n );\n }\n return ok(bytes);\n },\n async computeCid(data) {\n return cidOf(toBytes(data));\n },\n };\n}\n\nfunction makeUnconfiguredChain(): ChainApi {\n const fail = (): never => {\n throw new Error(\n \"createFakeApp: `chain` is not configured. Pass a `chain` override in options. \" +\n \"There is no chain-read fake — the host owns RPC selection; test chain-reading \" +\n \"logic behind your own interface and cover the real wiring in e2e.\",\n );\n };\n // Reads throw (fail fast, no silent undefined); state queries stay quiet.\n return {\n getClient: fail,\n getRawClient: fail,\n connect: fail,\n isConnected: () => false,\n destroyAll: () => {},\n };\n}\n\n/**\n * Create a fake {@link App}. Wallet, local-storage, and cloud-storage are working\n * in-memory fakes; `chain` is unconfigured until you override it. Every sub-API\n * is overridable.\n *\n * @example\n * ```ts\n * import { createFakeApp } from \"@parity/product-sdk/testing\";\n *\n * const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n * await app.wallet.connect();\n * expect(app.wallet.getAccounts()).toHaveLength(2);\n * ```\n *\n * For React, feed the fake to the exported context:\n * ```tsx\n * import { ProductSDKContext } from \"@parity/product-sdk/react\";\n * render(<ProductSDKContext.Provider value={app}><AccountPicker /></ProductSDKContext.Provider>);\n * ```\n */\nexport function createFakeApp(options?: CreateFakeAppOptions): App {\n const name = options?.name ?? \"fake-app\";\n return {\n wallet: makeFakeWallet(options?.wallet),\n localStorage: options?.localStorage ?? makeFakeLocalStorage(),\n chain: options?.chain ?? makeUnconfiguredChain(),\n cloudStorage:\n options?.cloudStorage !== undefined ? options.cloudStorage : makeFakeCloudStorage(),\n getAppInfo: () => ({ name }),\n };\n}\n\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n const alice: Account = { address: \"5Alice\", name: \"Alice\", source: \"dev\" };\n const bob: Account = { address: \"5Bob\", name: \"Bob\", source: \"dev\" };\n\n describe(\"createFakeApp\", () => {\n test(\"wallet lists, selects, and notifies on account change\", async () => {\n const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n expect(app.wallet.getAccounts()).toHaveLength(2);\n expect(app.wallet.getSelectedAccount()).toEqual(alice);\n\n let changed: Account | null = null;\n app.wallet.onAccountChange((a) => {\n changed = a;\n });\n app.wallet.selectAccount(\"5Bob\");\n expect(app.wallet.getSelectedAccount()).toEqual(bob);\n expect(changed).toEqual(bob);\n\n const { accounts } = await app.wallet.connect();\n expect(accounts).toHaveLength(2);\n });\n\n test(\"localStorage round-trips and clear empties it\", async () => {\n const app = createFakeApp();\n await app.localStorage.set(\"k\", \"v\");\n await app.localStorage.setJSON(\"o\", { n: 1 });\n expect(await app.localStorage.get(\"k\")).toBe(\"v\");\n expect(await app.localStorage.getJSON(\"o\")).toEqual({ n: 1 });\n expect(await app.localStorage.get(\"missing\")).toBeNull();\n\n await app.localStorage.clear();\n expect(await app.localStorage.get(\"k\")).toBeNull();\n });\n\n test(\"cloudStorage round-trips upload -> fetch; computeCid matches upload\", async () => {\n const cs = createFakeApp().cloudStorage;\n if (!cs) throw new Error(\"expected default cloud storage\");\n const cid = unwrapOk(await cs.upload(\"hello\"));\n expect(await cs.computeCid(\"hello\")).toBe(cid);\n expect(new TextDecoder().decode(unwrapOk(await cs.fetch(cid)))).toBe(\"hello\");\n expect(unwrapErr(await cs.fetch(\"bafyfakemissing\"))).toBeInstanceOf(\n ProductCloudStorageError,\n );\n });\n\n test(\"cloudStorage can be disabled with null\", () => {\n expect(createFakeApp({ cloudStorage: null }).cloudStorage).toBeNull();\n });\n\n test(\"chain is unconfigured by default\", () => {\n const app = createFakeApp();\n expect(app.chain.isConnected({} as never)).toBe(false);\n expect(() => app.chain.getClient({} as never)).toThrow(/not configured/);\n });\n\n test(\"getAppInfo reports the name\", () => {\n expect(createFakeApp({ name: \"my-app\" }).getAppInfo().name).toBe(\"my-app\");\n });\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/testing.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * Test fakes for `@parity/product-sdk` (umbrella).\n *\n * `createFakeApp` returns a fake {@link App} — use it directly in logic tests or\n * hand it to `ProductSDKContext.Provider` for React component tests, so code that\n * calls `useProductSDK()` / `useWallet()` runs with no host. This entry also\n * re-exports every package's fakes, for a single meta-package import.\n *\n * @packageDocumentation\n */\nimport { ProductCloudStorageError } from \"@parity/product-sdk-cloud-storage\";\nimport type { LocalKvStore } from \"@parity/product-sdk-local-storage\";\nimport { createFakeHostLocalStorage } from \"@parity/product-sdk-local-storage/testing\";\nimport { createLocalStorageApi } from \"./core/local-storage-api.js\";\nimport { err, ok, unwrapErr, unwrapOk } from \"@parity/result\";\n\nimport type {\n Account,\n App,\n ChainApi,\n CloudStorageApi,\n LocalStorageApi,\n WalletApi,\n} from \"./core/types.js\";\n\nconst textEncoder = new TextEncoder();\n\n// Re-export the per-package fakes so `@parity/product-sdk/testing` is a one-stop import.\n// statement-store is deliberately absent: the umbrella doesn't wrap that package, so apps\n// using it depend on it directly — import `@parity/product-sdk-statement-store/testing`\n// there instead. Re-exporting its fake here would add a dependency the umbrella otherwise\n// doesn't have and could skew against the version the app actually installs.\nexport * from \"@parity/product-sdk-local-storage/testing\";\nexport * from \"@parity/product-sdk-signer/testing\";\nexport * from \"@parity/product-sdk-contracts/testing\";\nexport * from \"@parity/product-sdk-host/testing\";\n\n/** Configurable behavior for the fake {@link WalletApi}. */\nexport interface FakeWalletOptions {\n /** Accounts `connect()` / `getAccounts()` expose. Default: none. */\n accounts?: Account[];\n /** Initially selected account. Default: the first account, or `null`. */\n selected?: Account | null;\n /** Bytes returned by `signMessage` / `createProof`. Default: 64 zero bytes. */\n signature?: Uint8Array;\n /** Value returned by `getProductAccount()`. Default: the selected account. */\n productAccount?: Account | null;\n /** Value returned by `getAnonymousAlias()`. Default: `null`. */\n anonymousAlias?: string | null;\n}\n\n/** Options for {@link createFakeApp}. */\nexport interface CreateFakeAppOptions {\n /** App name reported by `getAppInfo()`. Default: `\"fake-app\"`. */\n name?: string;\n /** Configure the fake wallet. */\n wallet?: FakeWalletOptions;\n /** Override the local-storage API. Default: in-memory (backed by `createFakeHostLocalStorage`). */\n localStorage?: LocalStorageApi;\n /** Override the chain API. Default: unconfigured (throws until you provide one). */\n chain?: ChainApi;\n /** Override cloud storage, or pass `null` to disable it. Default: an in-memory fake. */\n cloudStorage?: CloudStorageApi | null;\n}\n\nfunction makeFakeWallet(options?: FakeWalletOptions): WalletApi {\n const accounts = options?.accounts ?? [];\n let selected = options?.selected !== undefined ? options.selected : (accounts[0] ?? null);\n const signature = options?.signature ?? new Uint8Array(64);\n const listeners = new Set<(account: Account | null) => void>();\n const notify = () => {\n for (const l of listeners) l(selected);\n };\n\n return {\n async connect() {\n return { accounts };\n },\n async disconnect() {\n selected = null;\n notify();\n },\n getAccounts() {\n return accounts;\n },\n getSelectedAccount() {\n return selected;\n },\n selectAccount(address) {\n selected = accounts.find((a) => a.address === address) ?? null;\n notify();\n },\n async signMessage() {\n return signature;\n },\n async signMessageWithDotNsIdentity(args) {\n return {\n username: args.username ?? \"alice\",\n accountId: `0x${\"00\".repeat(32)}`,\n signature,\n };\n },\n onAccountChange(callback) {\n listeners.add(callback);\n return () => {\n listeners.delete(callback);\n };\n },\n getProductAccount() {\n return options?.productAccount !== undefined ? options.productAccount : selected;\n },\n getAnonymousAlias() {\n return options?.anonymousAlias ?? null;\n },\n async createProof() {\n return signature;\n },\n };\n}\n\nfunction makeFakeLocalStorage(): LocalStorageApi {\n // Route through the *same* `createLocalStorageApi` factory `createApp` uses,\n // so the fake and the shipped adapter cannot drift (#344). The fake's host\n // is adapted to a `LocalKvStore` here rather than via the async\n // `createLocalKvStore`, so `createFakeApp` stays synchronous; the semantics\n // (get \"\" -> null, getJSON undefined -> null) match `createHostBackend`.\n const host = createFakeHostLocalStorage();\n const kv: LocalKvStore = {\n async get(key) {\n return (await host.readString(key)) || null;\n },\n async set(key, value) {\n await host.writeString(key, value);\n },\n async getJSON<T>(key: string) {\n return ((await host.readJSON(key)) ?? null) as T | null;\n },\n async setJSON(key, value) {\n await host.writeJSON(key, value);\n },\n async remove(key) {\n await host.clear(key);\n },\n };\n return createLocalStorageApi(kv);\n}\n\nfunction makeFakeCloudStorage(): CloudStorageApi {\n const store = new Map<string, Uint8Array>();\n const toBytes = (data: string | Uint8Array) =>\n typeof data === \"string\" ? textEncoder.encode(data) : data;\n // Deterministic content-addressed id so upload / computeCid / fetch line up.\n const cidOf = (bytes: Uint8Array) => {\n let h = 0x811c9dc5;\n for (const b of bytes) {\n h ^= b;\n h = Math.imul(h, 0x01000193);\n }\n return `bafyfake${(h >>> 0).toString(16).padStart(8, \"0\")}`;\n };\n return {\n async upload(data) {\n const bytes = toBytes(data);\n const cid = cidOf(bytes);\n store.set(cid, bytes);\n return ok(cid);\n },\n async fetch(cid) {\n const bytes = store.get(cid);\n if (!bytes) {\n return err(\n new ProductCloudStorageError(\n `fake cloud storage: no object stored for CID ${cid}`,\n ),\n );\n }\n return ok(bytes);\n },\n async computeCid(data) {\n return cidOf(toBytes(data));\n },\n };\n}\n\nfunction makeUnconfiguredChain(): ChainApi {\n const fail = (): never => {\n throw new Error(\n \"createFakeApp: `chain` is not configured. Pass a `chain` override in options. \" +\n \"There is no chain-read fake — the host owns RPC selection; test chain-reading \" +\n \"logic behind your own interface and cover the real wiring in e2e.\",\n );\n };\n // Reads throw (fail fast, no silent undefined); state queries stay quiet.\n return {\n getClient: fail,\n getRawClient: fail,\n connect: fail,\n isConnected: () => false,\n destroyAll: () => {},\n };\n}\n\n/**\n * Create a fake {@link App}. Wallet, local-storage, and cloud-storage are working\n * in-memory fakes; `chain` is unconfigured until you override it. Every sub-API\n * is overridable.\n *\n * @example\n * ```ts\n * import { createFakeApp } from \"@parity/product-sdk/testing\";\n *\n * const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n * await app.wallet.connect();\n * expect(app.wallet.getAccounts()).toHaveLength(2);\n * ```\n *\n * For React, feed the fake to the exported context:\n * ```tsx\n * import { ProductSDKContext } from \"@parity/product-sdk/react\";\n * render(<ProductSDKContext.Provider value={app}><AccountPicker /></ProductSDKContext.Provider>);\n * ```\n */\nexport function createFakeApp(options?: CreateFakeAppOptions): App {\n const name = options?.name ?? \"fake-app\";\n return {\n wallet: makeFakeWallet(options?.wallet),\n localStorage: options?.localStorage ?? makeFakeLocalStorage(),\n chain: options?.chain ?? makeUnconfiguredChain(),\n cloudStorage:\n options?.cloudStorage !== undefined ? options.cloudStorage : makeFakeCloudStorage(),\n getAppInfo: () => ({ name }),\n };\n}\n\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n const alice: Account = { address: \"5Alice\", name: \"Alice\", source: \"dev\" };\n const bob: Account = { address: \"5Bob\", name: \"Bob\", source: \"dev\" };\n\n describe(\"createFakeApp\", () => {\n test(\"wallet lists, selects, and notifies on account change\", async () => {\n const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n expect(app.wallet.getAccounts()).toHaveLength(2);\n expect(app.wallet.getSelectedAccount()).toEqual(alice);\n\n let changed: Account | null = null;\n app.wallet.onAccountChange((a) => {\n changed = a;\n });\n app.wallet.selectAccount(\"5Bob\");\n expect(app.wallet.getSelectedAccount()).toEqual(bob);\n expect(changed).toEqual(bob);\n\n const { accounts } = await app.wallet.connect();\n expect(accounts).toHaveLength(2);\n });\n\n test(\"localStorage round-trips and remove deletes a key\", async () => {\n const app = createFakeApp();\n await app.localStorage.set(\"k\", \"v\");\n await app.localStorage.setJSON(\"o\", { n: 1 });\n expect(await app.localStorage.get(\"k\")).toBe(\"v\");\n expect(await app.localStorage.getJSON(\"o\")).toEqual({ n: 1 });\n expect(await app.localStorage.get(\"missing\")).toBeNull();\n\n await app.localStorage.remove(\"k\");\n expect(await app.localStorage.get(\"k\")).toBeNull();\n // Untouched keys stay — there is no clear-all.\n expect(await app.localStorage.getJSON(\"o\")).toEqual({ n: 1 });\n });\n\n test(\"cloudStorage round-trips upload -> fetch; computeCid matches upload\", async () => {\n const cs = createFakeApp().cloudStorage;\n if (!cs) throw new Error(\"expected default cloud storage\");\n const cid = unwrapOk(await cs.upload(\"hello\"));\n expect(await cs.computeCid(\"hello\")).toBe(cid);\n expect(new TextDecoder().decode(unwrapOk(await cs.fetch(cid)))).toBe(\"hello\");\n expect(unwrapErr(await cs.fetch(\"bafyfakemissing\"))).toBeInstanceOf(\n ProductCloudStorageError,\n );\n });\n\n test(\"cloudStorage can be disabled with null\", () => {\n expect(createFakeApp({ cloudStorage: null }).cloudStorage).toBeNull();\n });\n\n test(\"chain is unconfigured by default\", () => {\n const app = createFakeApp();\n expect(app.chain.isConnected({} as never)).toBe(false);\n expect(() => app.chain.getClient({} as never)).toThrow(/not configured/);\n });\n\n test(\"getAppInfo reports the name\", () => {\n expect(createFakeApp({ name: \"my-app\" }).getAppInfo().name).toBe(\"my-app\");\n });\n });\n}\n"]}
@@ -2,7 +2,7 @@ import { LogLevel } from '@parity/product-sdk-logger';
2
2
  import { ProductCloudStorageError, CloudStorageEnvironment } from '@parity/product-sdk-cloud-storage';
3
3
  import { Result } from '@parity/result';
4
4
  import { ChainClient } from '@parity/product-sdk-chain-client';
5
- import { P as PeopleUsernameChain } from './dotns-bswWAmR2.js';
5
+ import { P as PeopleUsernameChain } from './dotns-CtmOwVQW.js';
6
6
  import { ChainDefinition, TypedApi, PolkadotClient } from 'polkadot-api';
7
7
 
8
8
  /**
@@ -16,8 +16,8 @@ interface CloudStorageConfig {
16
16
  }
17
17
  /** Configuration for createApp */
18
18
  interface AppConfig {
19
- /** Application name - used to derive product accounts and namespace storage */
20
- name: string;
19
+ /** @deprecated Ignored with a warning. The host product ID supplies the app name. */
20
+ name?: string;
21
21
  /** Log level for SDK operations (default: 'info') */
22
22
  logLevel?: LogLevel;
23
23
  /**
@@ -27,6 +27,11 @@ interface AppConfig {
27
27
  */
28
28
  cloudStorage?: CloudStorageConfig | false;
29
29
  }
30
+ /** App configuration with the identity resolved from the host. */
31
+ interface AppInfo extends Omit<AppConfig, "name"> {
32
+ /** App name and storage prefix, omitting the host ID's final domain suffix. Local host IDs stay unchanged. */
33
+ name: string;
34
+ }
30
35
  /** Wallet API exposed by the SDK */
31
36
  interface WalletApi {
32
37
  /** Connect to available wallet providers */
@@ -61,7 +66,14 @@ interface WalletApi {
61
66
  /** Create Ring VRF proof (container mode only) */
62
67
  createProof(message: Uint8Array): Promise<Uint8Array>;
63
68
  }
64
- /** Storage API exposed by the SDK */
69
+ /**
70
+ * Storage API exposed by the SDK: per-key get / set / remove, string and JSON.
71
+ *
72
+ * There is no `clear()`. Host localStorage exposes no key enumeration (only
73
+ * per-key read / write / remove), so a clear-all cannot be implemented — it was
74
+ * a silent no-op in a host container. Remove keys individually with `remove`,
75
+ * or track the keys your app writes and remove them.
76
+ */
65
77
  interface LocalStorageApi {
66
78
  /** Get a value by key */
67
79
  get(key: string): Promise<string | null>;
@@ -73,8 +85,6 @@ interface LocalStorageApi {
73
85
  setJSON<T = unknown>(key: string, value: T): Promise<void>;
74
86
  /** Remove a value by key */
75
87
  remove(key: string): Promise<void>;
76
- /** Clear all values */
77
- clear(): Promise<void>;
78
88
  }
79
89
  /** Chain API exposed by the SDK */
80
90
  interface ChainApi {
@@ -153,8 +163,8 @@ interface App {
153
163
  chain: ChainApi;
154
164
  /** Cloud Storage operations (null if disabled via config) */
155
165
  cloudStorage: CloudStorageApi | null;
156
- /** Get app configuration */
157
- getAppInfo(): AppConfig;
166
+ /** Get app configuration with the host-derived name. */
167
+ getAppInfo(): AppInfo;
158
168
  }
159
169
  /** Account information */
160
170
  interface Account {
@@ -208,4 +218,4 @@ interface DotNsIdentitySignature {
208
218
  signature: Uint8Array;
209
219
  }
210
220
 
211
- export type { Account as A, ChainApi as C, DotNsIdentitySignature as D, LocalStorageApi as L, SignMessageWithDotNsIdentityArgs as S, WalletApi as W, CloudStorageApi as a, App as b, AppConfig as c, CloudStorageConfig as d };
221
+ export type { Account as A, ChainApi as C, DotNsIdentitySignature as D, LocalStorageApi as L, SignMessageWithDotNsIdentityArgs as S, WalletApi as W, CloudStorageApi as a, App as b, AppConfig as c, AppInfo as d, CloudStorageConfig as e };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parity/product-sdk",
3
- "version": "0.0.0-dev.312.0",
3
+ "version": "0.0.0-dev.329.0",
4
4
  "description": "Unified SDK for building products in the Polkadot ecosystem - umbrella package",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -48,6 +48,10 @@
48
48
  "import": "./dist/individuality/index.js",
49
49
  "types": "./dist/individuality/index.d.ts"
50
50
  },
51
+ "./nfts": {
52
+ "import": "./dist/nfts/index.js",
53
+ "types": "./dist/nfts/index.d.ts"
54
+ },
51
55
  "./react": {
52
56
  "import": "./dist/react/index.js",
53
57
  "types": "./dist/react/index.d.ts"
@@ -56,6 +60,10 @@
56
60
  "import": "./dist/local-storage/index.js",
57
61
  "types": "./dist/local-storage/index.d.ts"
58
62
  },
63
+ "./renderer": {
64
+ "import": "./dist/renderer/index.js",
65
+ "types": "./dist/renderer/index.d.ts"
66
+ },
59
67
  "./wallet": {
60
68
  "import": "./dist/wallet/index.js",
61
69
  "types": "./dist/wallet/index.d.ts"
@@ -71,20 +79,22 @@
71
79
  ],
72
80
  "dependencies": {
73
81
  "polkadot-api": "^2.1.6",
74
- "@parity/product-sdk-cloud-storage": "0.0.0-dev.312.0",
75
- "@parity/product-sdk-chain-client": "0.0.0-dev.312.0",
76
- "@parity/product-sdk-contracts": "0.0.0-dev.312.0",
77
- "@parity/product-sdk-host": "0.0.0-dev.312.0",
82
+ "@parity/product-sdk-address": "0.2.0",
83
+ "@parity/product-sdk-cloud-storage": "0.0.0-dev.329.0",
84
+ "@parity/product-sdk-chain-client": "0.0.0-dev.329.0",
85
+ "@parity/product-sdk-contracts": "0.10.11",
78
86
  "@parity/product-sdk-crypto": "0.1.1",
79
- "@parity/product-sdk-address": "0.1.1",
80
- "@parity/product-sdk-individuality": "0.0.0-dev.312.0",
81
- "@parity/product-sdk-keys": "0.0.0-dev.312.0",
87
+ "@parity/product-sdk-host": "0.23.0",
88
+ "@parity/product-sdk-individuality": "0.6.0",
89
+ "@parity/product-sdk-keys": "0.4.1",
82
90
  "@parity/product-sdk-logger": "0.1.1",
83
91
  "@parity/product-sdk-errors": "0.2.0",
84
92
  "@parity/result": "0.2.0",
85
- "@parity/product-sdk-signer": "0.0.0-dev.312.0",
86
- "@parity/product-sdk-tx": "0.0.0-dev.312.0",
87
- "@parity/product-sdk-local-storage": "0.0.0-dev.312.0"
93
+ "@parity/product-sdk-nfts": "0.0.0-dev.329.0",
94
+ "@parity/product-sdk-signer": "0.15.1",
95
+ "@parity/product-sdk-local-storage": "0.3.13",
96
+ "@parity/product-sdk-renderer": "0.3.0",
97
+ "@parity/product-sdk-tx": "0.4.11"
88
98
  },
89
99
  "peerDependencies": {
90
100
  "react": "^18.0.0 || ^19.0.0"
@@ -97,6 +107,7 @@
97
107
  "devDependencies": {
98
108
  "@types/node": "^22.0.0",
99
109
  "@types/react": "^18.0.0",
110
+ "neverthrow": "^8.2.0",
100
111
  "react": "^18.0.0",
101
112
  "typescript": "^5.7.0",
102
113
  "vitest": "^3.0.0"
@@ -0,0 +1,194 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import {
4
+ afterEach,
5
+ beforeEach,
6
+ describe,
7
+ expect,
8
+ expectTypeOf,
9
+ it,
10
+ vi,
11
+ type MockInstance,
12
+ } from "vitest";
13
+ import { errAsync, okAsync } from "neverthrow";
14
+ import { HostUnavailableError, type TruApi } from "@parity/product-sdk-host";
15
+ import {
16
+ createFakeHost,
17
+ createFakeTruApiClient,
18
+ setTruApiClient,
19
+ } from "@parity/product-sdk-host/testing";
20
+ import { configure, type LogEntry } from "@parity/product-sdk-logger";
21
+ import { createApp } from "./createApp.js";
22
+ import type { App } from "./types.js";
23
+ import type { ProductSDKProviderProps } from "../react/provider.js";
24
+
25
+ describe("host-derived app identity", () => {
26
+ let client: TruApi;
27
+ let entries: LogEntry[];
28
+ const apps: App[] = [];
29
+ let getProductContext: MockInstance<TruApi["system"]["getProductContext"]>;
30
+
31
+ beforeEach(() => {
32
+ client = createFakeTruApiClient();
33
+ getProductContext = vi.spyOn(client.system, "getProductContext");
34
+ getProductContext.mockReturnValue(okAsync({ productId: "session.paseo" }));
35
+ setTruApiClient(client);
36
+ entries = [];
37
+ configure({ level: "warn", namespaces: [], handler: (entry) => entries.push(entry) });
38
+ });
39
+
40
+ afterEach(async () => {
41
+ for (const app of apps.splice(0)) await app.wallet.disconnect();
42
+ setTruApiClient(null);
43
+ vi.restoreAllMocks();
44
+ });
45
+
46
+ it("works with the public fake host without overriding protocol methods", async () => {
47
+ using host = createFakeHost();
48
+ const app = await createApp({ cloudStorage: false });
49
+ apps.push(app);
50
+ const { accounts } = await app.wallet.connect();
51
+ await app.localStorage.set("key", "value");
52
+ expect({
53
+ info: app.getAppInfo(),
54
+ accountCount: accounts.length,
55
+ stored: (await host.client.localStorage.read({ key: "fake-app:key" }))._unsafeUnwrap(),
56
+ }).toEqual({
57
+ info: { name: "fake-app", cloudStorage: false },
58
+ accountCount: 1,
59
+ stored: { value: "0x76616c7565" },
60
+ });
61
+ });
62
+
63
+ it.each([
64
+ ["my-app.dot", "my-app"],
65
+ ["session.paseo", "session"],
66
+ ["nested.app.dot", "nested.app"],
67
+ ["localhost", "localhost"],
68
+ ["localhost:3000", "localhost:3000"],
69
+ ["127.0.0.1", "127.0.0.1"],
70
+ ["127.0.0.1:3000", "127.0.0.1:3000"],
71
+ ["app.localhost", "app.localhost"],
72
+ ["app.localhost:3000", "app.localhost:3000"],
73
+ ])(
74
+ "keeps wallet identity %s while using %s for app info and storage",
75
+ async (productId, appName) => {
76
+ getProductContext.mockReturnValue(okAsync({ productId }));
77
+ const getAccount = vi.spyOn(client.account, "getAccount");
78
+ const write = vi.spyOn(client.localStorage, "write");
79
+ const app = await createApp({ cloudStorage: false });
80
+ apps.push(app);
81
+ const { accounts } = await app.wallet.connect();
82
+ await app.localStorage.set("key", "value");
83
+ const name: string = app.getAppInfo().name;
84
+
85
+ expect({
86
+ name,
87
+ accountCount: accounts.length,
88
+ accountRequests: getAccount.mock.calls,
89
+ storageWrite: write.mock.calls.at(-1),
90
+ stored: await app.localStorage.get("key"),
91
+ }).toEqual({
92
+ name: appName,
93
+ accountCount: 1,
94
+ accountRequests: [
95
+ [
96
+ {
97
+ productAccountId: {
98
+ dotNsIdentifier: productId,
99
+ derivationIndex: { tag: "Index", value: 0 },
100
+ },
101
+ },
102
+ ],
103
+ ],
104
+ storageWrite: [{ key: `${appName}:key`, value: "0x76616c7565" }],
105
+ stored: "value",
106
+ });
107
+ },
108
+ );
109
+
110
+ it("keeps existing bare-name storage readable and writes to the same prefix", async () => {
111
+ getProductContext.mockReturnValue(okAsync({ productId: "my-app.dot" }));
112
+ await client.localStorage.write({ key: "my-app:theme", value: "0x6461726b" });
113
+ const app = await createApp({ cloudStorage: false });
114
+ apps.push(app);
115
+ const previous = await app.localStorage.get("theme");
116
+ await app.localStorage.set("theme", "light");
117
+
118
+ expect({
119
+ previous,
120
+ current: (await client.localStorage.read({ key: "my-app:theme" }))._unsafeUnwrap(),
121
+ fullIdPrefix: (
122
+ await client.localStorage.read({ key: "my-app.dot:theme" })
123
+ )._unsafeUnwrap(),
124
+ }).toEqual({
125
+ previous: "dark",
126
+ current: { value: "0x6c69676874" },
127
+ fullIdPrefix: { value: undefined },
128
+ });
129
+ });
130
+
131
+ it("requests the host identity without configuration or a deprecation warning", async () => {
132
+ expectTypeOf({ children: null }).toMatchTypeOf<ProductSDKProviderProps>();
133
+ const error = { tag: "Unsupported" } as const;
134
+ getProductContext.mockReturnValue(errAsync(error));
135
+ await expect(createApp()).rejects.toMatchObject({
136
+ name: "HostCallFailedError",
137
+ cause: error,
138
+ });
139
+ expect(entries.filter((entry) => entry.namespace === "app")).toEqual([]);
140
+ });
141
+
142
+ it.each(["wrong-app", ""])("ignores and warns about the deprecated name %j", async (name) => {
143
+ const app = await createApp({ name, cloudStorage: false });
144
+ apps.push(app);
145
+ await app.localStorage.set("key", "retained");
146
+ const unnamed = await createApp({ cloudStorage: false });
147
+ apps.push(unnamed);
148
+ expect({
149
+ info: app.getAppInfo(),
150
+ storedWithoutName: await unnamed.localStorage.get("key"),
151
+ warnings: entries
152
+ .filter((entry) => entry.namespace === "app")
153
+ .map(({ level, message }) => ({ level, message })),
154
+ }).toEqual({
155
+ info: { name: "session", cloudStorage: false },
156
+ storedWithoutName: "retained",
157
+ warnings: [
158
+ {
159
+ level: "warn",
160
+ message:
161
+ "createApp: name is deprecated and ignored. Remove the name option. The SDK resolves the app name from system.getProductContext(), dropping the product ID's final domain suffix (my-app.dot -> my-app). Local development IDs stay unchanged.",
162
+ },
163
+ ],
164
+ });
165
+ });
166
+
167
+ it("rejects unavailable hosts even when a deprecated name is supplied", async () => {
168
+ setTruApiClient(null);
169
+ await expect(createApp({ name: "fallback", cloudStorage: false })).rejects.toBeInstanceOf(
170
+ HostUnavailableError,
171
+ );
172
+ });
173
+
174
+ it("preserves a refused context instead of using the deprecated name", async () => {
175
+ const error = { tag: "Unsupported" } as const;
176
+ getProductContext.mockReturnValue(errAsync(error));
177
+ await expect(createApp({ name: "fallback", cloudStorage: false })).rejects.toMatchObject({
178
+ name: "HostCallFailedError",
179
+ message: "system.getProductContext: Unsupported",
180
+ payload: error,
181
+ cause: error,
182
+ });
183
+ });
184
+
185
+ it("preserves a context transport rejection", async () => {
186
+ const error = new Error("host connection closed");
187
+ getProductContext.mockImplementation(() =>
188
+ okAsync(undefined).map(() => {
189
+ throw error;
190
+ }),
191
+ );
192
+ await expect(createApp({ cloudStorage: false })).rejects.toBe(error);
193
+ });
194
+ });