@tangle-network/blueprint-ui 0.5.2 → 0.5.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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/web3.ts","../src/stores/session.ts","../src/blueprints/registry.ts","../src/hooks/useOperators.ts","../src/hooks/useServiceValidation.ts","../src/hooks/useAuthenticatedFetch.ts","../src/hooks/useSessionAuth.ts","../src/hooks/useProvisionProgress.ts","../src/hooks/useSidecarAuth.ts","../src/hooks/useWagmiSidecarAuth.ts","../src/hooks/useWalletEthBalance.ts"],"sourcesContent":["import type { Chain } from 'viem';\nimport { http } from 'wagmi';\nimport { mainnet, rpcUrl, tangleLocal, tangleMainnet, tangleTestnet } from '../contracts/chains';\n\nexport function getTangleWalletChains(localChain: Chain = tangleLocal): readonly [Chain, ...Chain[]] {\n return [localChain, tangleTestnet, tangleMainnet, mainnet];\n}\n\nexport const tangleWalletChains: readonly [Chain, ...Chain[]] = getTangleWalletChains();\n\nexport function createTangleTransports(localChain: Pick<Chain, 'id' | 'rpcUrls'> = tangleLocal) {\n const localRpcUrl = localChain.rpcUrls.default.http[0] ?? rpcUrl;\n\n return {\n [localChain.id]: http(localRpcUrl),\n [tangleTestnet.id]: http('https://testnet-rpc.tangle.tools'),\n [tangleMainnet.id]: http('https://rpc.tangle.tools'),\n [mainnet.id]: http(),\n };\n}\n\nexport const defaultConnectKitOptions = {\n hideBalance: false,\n hideTooltips: false,\n hideQuestionMarkCTA: true,\n overlayBlur: 4,\n} as const;\n","import { persistedAtom } from './persistedAtom';\n\nexport interface SessionEntry {\n token: string;\n address: string;\n expiresAt: number;\n sandboxId: string;\n}\n\n/**\n * Persisted session tokens keyed by sandbox ID.\n * Auto-cleaned on read if expired.\n */\nexport const sessionMapStore = persistedAtom<Record<string, SessionEntry>>({\n key: 'bp_sessions',\n initial: {},\n});\n\n/** Active session for a given sandbox. */\nexport function getSession(sandboxId: string): SessionEntry | null {\n const map = sessionMapStore.get();\n const entry = map[sandboxId];\n if (!entry) return null;\n\n // Check expiry with 60s buffer\n if (Date.now() / 1000 > entry.expiresAt - 60) {\n removeSession(sandboxId);\n return null;\n }\n\n return entry;\n}\n\nexport function setSession(entry: SessionEntry) {\n const map = { ...sessionMapStore.get() };\n map[entry.sandboxId] = entry;\n sessionMapStore.set(map);\n}\n\nexport function removeSession(sandboxId: string) {\n const map = { ...sessionMapStore.get() };\n delete map[sandboxId];\n sessionMapStore.set(map);\n}\n\n/** Clean up all expired sessions. */\nexport function gcSessions() {\n const now = Date.now() / 1000;\n const map = sessionMapStore.get();\n const cleaned: Record<string, SessionEntry> = {};\n let changed = false;\n\n for (const [key, entry] of Object.entries(map) as [string, SessionEntry][]) {\n if (entry.expiresAt > now) {\n cleaned[key] = entry;\n } else {\n changed = true;\n }\n }\n\n if (changed) {\n sessionMapStore.set(cleaned);\n }\n}\n","import type { Address } from 'viem';\n\n/**\n * Blueprint Registry — defines the metadata layer for Tangle blueprints.\n *\n * Each blueprint exposes a set of jobs. The registry maps on-chain job IDs\n * to human-readable metadata: labels, descriptions, categories, form fields,\n * and pricing info. This enables the UI to render appropriate forms for each\n * job without procedurally generating UI from raw ABI data.\n *\n * Third-party blueprints can register here to appear in the wizard.\n */\n\n// ── Types ──\n\nexport type JobCategory = 'lifecycle' | 'execution' | 'batch' | 'workflow' | 'ssh' | 'management';\n\nexport interface JobFieldDef {\n name: string;\n label: string;\n type: 'text' | 'textarea' | 'number' | 'boolean' | 'select' | 'json' | 'combobox';\n placeholder?: string;\n required?: boolean;\n defaultValue?: string | number | boolean;\n options?: { label: string; value: string }[];\n helperText?: string;\n /** Minimum allowed value for number fields */\n min?: number;\n /** Maximum allowed value for number fields */\n max?: number;\n /** Step increment for number fields */\n step?: number;\n /** Solidity ABI type for encoding (e.g. 'string', 'uint64', 'bool', 'uint8') */\n abiType?: string;\n /** ABI param name if different from `name` (e.g. 'agent_identifier' vs 'agentIdentifier') */\n abiParam?: string;\n /** Field is included in ABI encoding but never shown in form (e.g. sidecar_token) */\n internal?: boolean;\n}\n\n/** ABI param injected from runtime context, not user input (e.g. sidecar_url, sandbox_id) */\nexport interface AbiContextParam {\n abiName: string;\n abiType: string;\n}\n\nexport interface JobDefinition {\n id: number;\n name: string;\n label: string;\n description: string;\n category: JobCategory;\n icon: string;\n pricingMultiplier: number;\n /** Fields the user needs to fill for this job */\n fields: JobFieldDef[];\n /** Whether this job requires an existing sandbox to target */\n requiresSandbox: boolean;\n /** Optional warning shown before submission */\n warning?: string;\n /** ABI params prepended from runtime context (e.g. sidecar_url for sandbox jobs) */\n contextParams?: AbiContextParam[];\n /** Override for jobs with complex ABI encoding (e.g. nested structs) */\n customEncoder?: (values: Record<string, unknown>, context?: Record<string, unknown>) => `0x${string}`;\n}\n\nexport interface BlueprintDefinition {\n id: string;\n name: string;\n version: string;\n description: string;\n icon: string;\n color: string;\n /** Contract address per chain ID — resolved at runtime */\n contracts: Record<number, Address>;\n /** Supported job definitions */\n jobs: JobDefinition[];\n /** Category ordering for the UI */\n categories: { key: JobCategory; label: string; icon: string }[];\n}\n\n// ── Registry ──\n\nconst blueprintRegistry = new Map<string, BlueprintDefinition>();\n\nexport function registerBlueprint(bp: BlueprintDefinition) {\n blueprintRegistry.set(bp.id, bp);\n}\n\nexport function getBlueprint(id: string): BlueprintDefinition | undefined {\n return blueprintRegistry.get(id);\n}\n\nexport function getAllBlueprints(): BlueprintDefinition[] {\n return Array.from(blueprintRegistry.values());\n}\n\nexport function getBlueprintJobs(blueprintId: string, category?: JobCategory): JobDefinition[] {\n const bp = blueprintRegistry.get(blueprintId);\n if (!bp) return [];\n return category ? bp.jobs.filter((j) => j.category === category) : bp.jobs;\n}\n\nexport function getJobById(blueprintId: string, jobId: number): JobDefinition | undefined {\n const bp = blueprintRegistry.get(blueprintId);\n return bp?.jobs.find((j) => j.id === jobId);\n}\n","import { useState, useEffect } from 'react';\nimport type { Address } from 'viem';\nimport { tangleOperatorsAbi } from '../contracts/abi';\nimport { publicClient, getAddresses } from '../contracts/publicClient';\n\nexport interface DiscoveredOperator {\n address: Address;\n ecdsaPublicKey: string;\n rpcAddress: string;\n}\n\ninterface OperatorDiscoveryClient {\n readContract(args: Record<string, unknown>): Promise<unknown>;\n getLogs(args: Record<string, unknown>): Promise<Array<Record<string, unknown>>>;\n multicall(args: Record<string, unknown>): Promise<Array<Record<string, unknown>>>;\n}\n\ninterface OperatorDiscoveryResult {\n operators: DiscoveredOperator[];\n operatorCount: bigint;\n}\n\nfunction readPreferenceValue(\n result: unknown,\n field: 'ecdsaPublicKey' | 'rpcAddress',\n): string {\n if (Array.isArray(result)) {\n return String(result[field === 'ecdsaPublicKey' ? 0 : 1] ?? '');\n }\n if (result && typeof result === 'object') {\n return String((result as Record<string, unknown>)[field] ?? '');\n }\n return '';\n}\n\nasync function verifyCandidatesWithMulticall(\n client: OperatorDiscoveryClient,\n servicesAddress: Address,\n blueprintId: bigint,\n candidates: DiscoveredOperator[],\n): Promise<DiscoveredOperator[] | null> {\n const [registrationResults, preferencesResults] = await Promise.all([\n client.multicall({\n contracts: candidates.map((op) => ({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'isOperatorRegistered' as const,\n args: [blueprintId, op.address] as const,\n })),\n }),\n client.multicall({\n contracts: candidates.map((op) => ({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'getOperatorPreferences' as const,\n args: [blueprintId, op.address] as const,\n })),\n }),\n ]);\n\n const hadRegistrationFailure = registrationResults.some((result) => result?.status === 'failure');\n const hadPreferenceFailure = preferencesResults.some((result) => result?.status === 'failure');\n\n const active: DiscoveredOperator[] = [];\n candidates.forEach((op, i) => {\n if (registrationResults[i]?.result !== true) return;\n const prefs = preferencesResults[i];\n if (prefs?.status === 'success' && prefs.result != null) {\n active.push({\n ...op,\n ecdsaPublicKey: readPreferenceValue(prefs.result, 'ecdsaPublicKey') || op.ecdsaPublicKey,\n rpcAddress: readPreferenceValue(prefs.result, 'rpcAddress') || op.rpcAddress,\n });\n return;\n }\n active.push(op);\n });\n\n if (active.length === 0 && (hadRegistrationFailure || hadPreferenceFailure)) {\n return null;\n }\n\n return active;\n}\n\nasync function verifyCandidatesDirectly(\n client: OperatorDiscoveryClient,\n servicesAddress: Address,\n blueprintId: bigint,\n candidates: DiscoveredOperator[],\n): Promise<DiscoveredOperator[]> {\n const results = await Promise.allSettled(\n candidates.map(async (op) => {\n const registration = await client.readContract({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'isOperatorRegistered',\n args: [blueprintId, op.address],\n });\n\n if (registration !== true) {\n return null;\n }\n\n try {\n const preferences = await client.readContract({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'getOperatorPreferences',\n args: [blueprintId, op.address],\n });\n\n return {\n ...op,\n ecdsaPublicKey: readPreferenceValue(preferences, 'ecdsaPublicKey') || op.ecdsaPublicKey,\n rpcAddress: readPreferenceValue(preferences, 'rpcAddress') || op.rpcAddress,\n };\n } catch {\n return op;\n }\n }),\n );\n\n const active = results\n .filter((result): result is PromiseFulfilledResult<DiscoveredOperator | null> => result.status === 'fulfilled')\n .map((result) => result.value)\n .filter((op): op is DiscoveredOperator => op != null);\n\n if (active.length > 0) {\n return active;\n }\n\n const failure = results.find((result): result is PromiseRejectedResult => result.status === 'rejected');\n if (failure) {\n throw failure.reason instanceof Error ? failure.reason : new Error(String(failure.reason));\n }\n\n return [];\n}\n\n/**\n * Shared discovery logic for operator lookup.\n * Tries multicall first for efficiency, then falls back to direct reads when\n * multicall is unavailable in local/dev environments.\n */\nexport async function discoverOperatorsWithClient(\n client: OperatorDiscoveryClient,\n servicesAddress: Address,\n blueprintId: bigint,\n): Promise<OperatorDiscoveryResult> {\n const count = await client.readContract({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'blueprintOperatorCount',\n args: [blueprintId],\n });\n const operatorCount = count as bigint;\n\n if (operatorCount === 0n) {\n return { operators: [], operatorCount };\n }\n\n const registeredLogs = await client.getLogs({\n address: servicesAddress,\n event: {\n type: 'event' as const,\n name: 'OperatorRegistered',\n inputs: [\n { name: 'blueprintId', type: 'uint64', indexed: true },\n { name: 'operator', type: 'address', indexed: true },\n { name: 'ecdsaPublicKey', type: 'bytes', indexed: false },\n { name: 'rpcAddress', type: 'string', indexed: false },\n ],\n },\n args: { blueprintId },\n fromBlock: 0n,\n toBlock: 'latest',\n });\n\n const byAddress = new Map<Address, DiscoveredOperator>();\n for (const log of registeredLogs) {\n const args = (log.args ?? {}) as Record<string, unknown>;\n const addr = args.operator as Address | undefined;\n if (!addr) continue;\n byAddress.set(addr, {\n address: addr,\n ecdsaPublicKey: String(args.ecdsaPublicKey ?? '0x'),\n rpcAddress: String(args.rpcAddress ?? ''),\n });\n }\n\n const candidates = Array.from(byAddress.values());\n if (candidates.length === 0) {\n return { operators: [], operatorCount };\n }\n\n try {\n const active = await verifyCandidatesWithMulticall(client, servicesAddress, blueprintId, candidates);\n if (active != null) {\n return { operators: active, operatorCount };\n }\n } catch {\n // Fall through to direct reads below.\n }\n\n const active = await verifyCandidatesDirectly(client, servicesAddress, blueprintId, candidates);\n return { operators: active, operatorCount };\n}\n\n/**\n * Discover operators registered for a blueprint by scanning OperatorRegistered\n * events, then verifying each is still active. Falls back to direct reads when\n * multicall is unavailable.\n */\nexport function useOperators(blueprintId: bigint) {\n const [operators, setOperators] = useState<DiscoveredOperator[]>([]);\n const [operatorCount, setOperatorCount] = useState<bigint>(0n);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n const addrs = getAddresses();\n\n async function discover() {\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await discoverOperatorsWithClient(publicClient, addrs.services, blueprintId);\n if (cancelled) return;\n setOperatorCount(result.operatorCount);\n setOperators(result.operators);\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n if (!cancelled) setIsLoading(false);\n }\n }\n\n discover();\n return () => { cancelled = true; };\n }, [blueprintId]);\n\n return { operators, isLoading, error, operatorCount };\n}\n","import { useState, useCallback } from 'react';\nimport type { Address } from 'viem';\nimport { tangleServicesAbi } from '../contracts/abi';\nimport { publicClient, getAddresses } from '../contracts/publicClient';\n\nexport interface ServiceInfo {\n active: boolean;\n blueprintId: bigint;\n owner: Address;\n operatorCount: number;\n operators: Address[];\n permitted: boolean;\n ttl: bigint;\n createdAt: bigint;\n}\n\n/**\n * Validate a service on-chain: check if active, fetch operators,\n * verify the current user is a permitted caller.\n */\nexport function useServiceValidation() {\n const [isValidating, setIsValidating] = useState(false);\n const [serviceInfo, setServiceInfo] = useState<ServiceInfo | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const validate = useCallback(async (serviceId: bigint, userAddress?: Address) => {\n setIsValidating(true);\n setError(null);\n setServiceInfo(null);\n\n const addrs = getAddresses();\n\n try {\n // Run reads in parallel without multicall to avoid type union issues\n const [isActiveResult, serviceDataResult, operatorsResult, permittedResult] = await Promise.all([\n publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'isServiceActive',\n args: [serviceId],\n }).catch(() => false),\n\n publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'getService',\n args: [serviceId],\n }).catch(() => null),\n\n publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'getServiceOperators',\n args: [serviceId],\n }).catch(() => [] as readonly Address[]),\n\n userAddress\n ? publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'isPermittedCaller',\n args: [serviceId, userAddress],\n }).catch(() => false)\n : Promise.resolve(true),\n ]);\n\n const isActive = isActiveResult as boolean;\n const serviceData = serviceDataResult as Record<string, any> | null;\n const operators = (operatorsResult ?? []) as readonly Address[];\n const permitted = permittedResult as boolean;\n\n if (!serviceData) {\n setError('Service not found');\n setIsValidating(false);\n return null;\n }\n\n const info: ServiceInfo = {\n active: isActive,\n blueprintId: serviceData.blueprintId ?? serviceData[0] ?? 0n,\n owner: serviceData.owner ?? serviceData[1] ?? ('0x0' as Address),\n operatorCount: operators.length,\n operators: [...operators],\n permitted,\n ttl: serviceData.ttl ?? serviceData[3] ?? 0n,\n createdAt: serviceData.createdAt ?? serviceData[2] ?? 0n,\n };\n\n setServiceInfo(info);\n\n if (!isActive) {\n setError('Service is not active');\n } else if (!permitted && userAddress) {\n setError('You are not a permitted caller for this service');\n }\n\n setIsValidating(false);\n return info;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n setError(msg);\n setIsValidating(false);\n return null;\n }\n }, []);\n\n const reset = useCallback(() => {\n setServiceInfo(null);\n setError(null);\n }, []);\n\n return { validate, reset, isValidating, serviceInfo, error };\n}\n","import { useCallback } from 'react';\nimport { getSession } from '../stores/session';\nimport { useSessionAuth } from './useSessionAuth';\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\ninterface UseAuthenticatedFetchOptions {\n sandboxId: string;\n apiUrl?: string;\n}\n\n/**\n * Returns a `fetch` wrapper that injects the Bearer session token.\n * If the token is expired or a 401 is received, triggers re-authentication.\n */\nexport function useAuthenticatedFetch({ sandboxId, apiUrl }: UseAuthenticatedFetchOptions) {\n const { authenticate } = useSessionAuth({ sandboxId, apiUrl });\n\n const authFetch = useCallback(\n async (url: string, init?: RequestInit): Promise<Response> => {\n let session = getSession(sandboxId);\n\n // If no session, authenticate first\n if (!session) {\n session = await authenticate();\n if (!session) {\n throw new Error('Authentication required');\n }\n }\n\n // Make request with token\n const headers = new Headers(init?.headers);\n headers.set('Authorization', `Bearer ${session.token}`);\n\n const res = await fetch(url, { ...init, headers });\n\n // If 401, try re-authenticating once\n if (res.status === 401) {\n session = await authenticate();\n if (!session) {\n throw new Error('Re-authentication failed');\n }\n\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set('Authorization', `Bearer ${session.token}`);\n return fetch(url, { ...init, headers: retryHeaders });\n }\n\n return res;\n },\n [sandboxId, authenticate],\n );\n\n return { authFetch };\n}\n","import { useCallback, useState } from 'react';\nimport { useSignMessage } from 'wagmi';\nimport { getSession, setSession, removeSession, type SessionEntry } from '../stores/session';\nimport { getEnvVar } from '../utils/env';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ChallengeResponse {\n nonce: string;\n message: string;\n expires_at: number;\n}\n\ninterface SessionResponse {\n token: string;\n address: string;\n expires_at: number;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\ninterface UseSessionAuthOptions {\n sandboxId: string;\n apiUrl?: string;\n}\n\nexport function useSessionAuth({ sandboxId, apiUrl }: UseSessionAuthOptions) {\n const baseUrl = apiUrl ?? getEnvVar('VITE_OPERATOR_API_URL') ?? 'http://localhost:9090';\n const { signMessageAsync } = useSignMessage();\n\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Get cached session\n const session = getSession(sandboxId);\n\n const authenticate = useCallback(async (): Promise<SessionEntry | null> => {\n setIsAuthenticating(true);\n setError(null);\n\n try {\n // Step 1: Request challenge\n const challengeRes = await fetch(`${baseUrl}/api/auth/challenge`, {\n method: 'POST',\n });\n if (!challengeRes.ok) {\n throw new Error(`Challenge request failed: HTTP ${challengeRes.status}`);\n }\n const challenge: ChallengeResponse = await challengeRes.json();\n\n // Step 2: Sign with wallet\n const signature = await signMessageAsync({ message: challenge.message });\n\n // Step 3: Exchange signature for session token\n const sessionRes = await fetch(`${baseUrl}/api/auth/session`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n nonce: challenge.nonce,\n signature,\n }),\n });\n if (!sessionRes.ok) {\n const body = await sessionRes.json().catch(() => ({}));\n throw new Error(body.error ?? `Session exchange failed: HTTP ${sessionRes.status}`);\n }\n const sessionData: SessionResponse = await sessionRes.json();\n\n // Step 4: Store session\n const entry: SessionEntry = {\n token: sessionData.token,\n address: sessionData.address,\n expiresAt: sessionData.expires_at,\n sandboxId,\n };\n setSession(entry);\n\n return entry;\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Authentication failed';\n setError(msg);\n return null;\n } finally {\n setIsAuthenticating(false);\n }\n }, [baseUrl, sandboxId, signMessageAsync]);\n\n const logout = useCallback(() => {\n removeSession(sandboxId);\n }, [sandboxId]);\n\n return {\n session,\n isAuthenticated: session !== null,\n isAuthenticating,\n error,\n authenticate,\n logout,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { getEnvVar } from '../utils/env';\n\n// ---------------------------------------------------------------------------\n// Types matching sandbox-runtime/src/provision_progress.rs\n// ---------------------------------------------------------------------------\n\nexport type ProvisionPhase =\n | 'queued'\n | 'image_pull'\n | 'container_create'\n | 'container_start'\n | 'health_check'\n | 'ready'\n | 'failed';\n\nexport interface ProvisionStatus {\n call_id: number;\n sandbox_id: string | null;\n phase: ProvisionPhase;\n message: string | null;\n started_at: number;\n updated_at: number;\n progress_pct: number;\n sidecar_url: string | null;\n}\n\nconst PHASE_LABELS: Record<ProvisionPhase, string> = {\n queued: 'Queued',\n image_pull: 'Pulling image',\n container_create: 'Creating container',\n container_start: 'Starting container',\n health_check: 'Health check',\n ready: 'Ready',\n failed: 'Failed',\n};\n\nexport function getPhaseLabel(phase: ProvisionPhase): string {\n return PHASE_LABELS[phase] ?? phase;\n}\n\nexport function isTerminalPhase(phase: ProvisionPhase): boolean {\n return phase === 'ready' || phase === 'failed';\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nconst POLL_INTERVAL = 2000;\n\ninterface UseProvisionProgressOptions {\n callId: number | null;\n apiUrl?: string;\n enabled?: boolean;\n}\n\nexport function useProvisionProgress({\n callId,\n apiUrl,\n enabled = true,\n}: UseProvisionProgressOptions) {\n const [status, setStatus] = useState<ProvisionStatus | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [isPolling, setIsPolling] = useState(false);\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const baseUrl = apiUrl ?? getEnvVar('VITE_OPERATOR_API_URL') ?? 'http://localhost:9090';\n\n const fetchProgress = useCallback(async () => {\n if (callId == null) return;\n\n try {\n const res = await fetch(`${baseUrl}/api/provisions/${callId}`);\n if (res.status === 404) {\n // Not yet tracked — keep polling\n return;\n }\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n const data: ProvisionStatus = await res.json();\n setStatus(data);\n setError(null);\n\n // Stop polling on terminal phase\n if (isTerminalPhase(data.phase) && intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n setIsPolling(false);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to fetch provision status');\n }\n }, [callId, baseUrl]);\n\n useEffect(() => {\n if (!enabled || callId == null) return;\n\n setIsPolling(true);\n fetchProgress(); // Initial fetch\n\n intervalRef.current = setInterval(fetchProgress, POLL_INTERVAL);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n setIsPolling(false);\n };\n }, [enabled, callId, fetchProgress]);\n\n return {\n status,\n error,\n isPolling,\n phase: status?.phase ?? null,\n progressPct: status?.progress_pct ?? 0,\n sandboxId: status?.sandbox_id ?? null,\n sidecarUrl: status?.sidecar_url ?? null,\n message: status?.message ?? null,\n isReady: status?.phase === 'ready',\n isFailed: status?.phase === 'failed',\n };\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseSidecarAuthOptions {\n /** Scoping key for token storage (e.g. botId, sandboxId). */\n resourceId: string;\n /** Base URL of the sidecar or operator API. */\n apiUrl: string;\n /**\n * Sign a plaintext message and return the hex signature.\n * Consuming apps wire this to their wallet library (e.g. wagmi's signMessageAsync).\n */\n signMessage: (message: string) => Promise<string>;\n}\n\nexport interface SidecarAuth {\n token: string | null;\n isAuthenticated: boolean;\n isAuthenticating: boolean;\n authenticate: () => Promise<string | null>;\n clearCachedToken: () => void;\n error: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// localStorage helpers\n// ---------------------------------------------------------------------------\n\nfunction storageKey(resourceId: string, apiUrl: string): string {\n return `sidecar_session_${resourceId}__${apiUrl}`;\n}\n\nfunction loadSession(resourceId: string, apiUrl: string): { token: string; expiresAt: number } | null {\n if (typeof window === 'undefined') return null;\n try {\n const raw = localStorage.getItem(storageKey(resourceId, apiUrl));\n if (!raw) return null;\n const data = JSON.parse(raw) as { token: string; expiresAt: number };\n // Discard if within 60s of expiry\n if (data.expiresAt * 1000 - Date.now() < 60_000) {\n localStorage.removeItem(storageKey(resourceId, apiUrl));\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\nfunction saveSession(resourceId: string, apiUrl: string, token: string, expiresAt: number) {\n if (typeof window === 'undefined') return;\n try {\n localStorage.setItem(storageKey(resourceId, apiUrl), JSON.stringify({ token, expiresAt }));\n } catch {\n // storage full — ignore\n }\n}\n\nfunction clearSession(resourceId: string, apiUrl: string) {\n if (typeof window === 'undefined') return;\n localStorage.removeItem(storageKey(resourceId, apiUrl));\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Generic sidecar PASETO challenge/response auth.\n *\n * Flow:\n * 1. POST /api/auth/challenge -> { nonce, message, expires_at }\n * 2. signMessage(message) -> signature (provided by consuming app)\n * 3. POST /api/auth/session -> { token, address, expires_at }\n *\n * Tokens are cached in localStorage and auto-refreshed 5 minutes before expiry.\n */\nexport function useSidecarAuth({ resourceId, apiUrl, signMessage }: UseSidecarAuthOptions): SidecarAuth {\n const cached = loadSession(resourceId, apiUrl);\n const [token, setToken] = useState<string | null>(cached?.token ?? null);\n const [expiresAt, setExpiresAt] = useState<number>(cached?.expiresAt ?? 0);\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const refreshTimerRef = useRef<ReturnType<typeof setTimeout>>();\n\n const clearCachedToken = useCallback(() => {\n setToken(null);\n setExpiresAt(0);\n clearSession(resourceId, apiUrl);\n }, [resourceId, apiUrl]);\n\n const authenticate = useCallback(async (): Promise<string | null> => {\n if (!apiUrl) return null;\n setIsAuthenticating(true);\n setError(null);\n\n try {\n // Step 1: Get challenge\n const challengeRes = await fetch(`${apiUrl}/api/auth/challenge`, {\n method: 'POST',\n });\n if (!challengeRes.ok) {\n throw new Error(`Challenge failed: ${challengeRes.status}`);\n }\n const { nonce, message } = await challengeRes.json();\n\n // Step 2: Sign with wallet (injected)\n const signature = await signMessage(message);\n\n // Step 3: Exchange for session token\n const sessionRes = await fetch(`${apiUrl}/api/auth/session`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ nonce, signature }),\n });\n if (!sessionRes.ok) {\n const text = await sessionRes.text();\n throw new Error(text || `Session exchange failed: ${sessionRes.status}`);\n }\n\n const { token: newToken, expires_at } = await sessionRes.json();\n setToken(newToken);\n setExpiresAt(expires_at);\n saveSession(resourceId, apiUrl, newToken, expires_at);\n return newToken;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Authentication failed');\n clearCachedToken();\n return null;\n } finally {\n setIsAuthenticating(false);\n }\n }, [resourceId, apiUrl, signMessage, clearCachedToken]);\n\n // Auto-refresh token 5 minutes before expiry\n useEffect(() => {\n if (refreshTimerRef.current) {\n clearTimeout(refreshTimerRef.current);\n }\n\n if (!token || !expiresAt) return;\n\n const msUntilRefresh = (expiresAt - 300) * 1000 - Date.now();\n if (msUntilRefresh <= 0) {\n clearCachedToken();\n return;\n }\n\n refreshTimerRef.current = setTimeout(() => {\n authenticate().catch(() => {\n clearCachedToken();\n });\n }, msUntilRefresh);\n\n return () => {\n if (refreshTimerRef.current) {\n clearTimeout(refreshTimerRef.current);\n }\n };\n }, [token, expiresAt, authenticate, clearCachedToken]);\n\n return {\n token,\n isAuthenticated: token !== null,\n isAuthenticating,\n authenticate,\n clearCachedToken,\n error,\n };\n}\n","import { useSignMessage } from 'wagmi';\nimport { useSidecarAuth } from './useSidecarAuth';\n\nexport function useWagmiSidecarAuth(resourceId: string, apiUrl: string) {\n const { signMessageAsync } = useSignMessage();\n return useSidecarAuth({\n resourceId,\n apiUrl,\n signMessage: (msg: string) => signMessageAsync({ message: msg }),\n });\n}\n","import { useEffect, useState } from 'react';\n\nconst WEI_PER_ETH = 1_000_000_000_000_000_000n;\nconst DISPLAY_SCALE = 1_000n; // 3 decimal places\n\nfunction formatEthBalance(wei: bigint): string {\n const whole = wei / WEI_PER_ETH;\n const fraction = ((wei % WEI_PER_ETH) * DISPLAY_SCALE) / WEI_PER_ETH;\n return `${whole.toString()}.${fraction.toString().padStart(3, '0')}`;\n}\n\ninterface UseWalletEthBalanceOptions {\n address?: string;\n refreshKey?: number | string;\n readBalance: (address: string) => Promise<bigint>;\n pollMs?: number;\n onError?: (error: unknown) => void;\n}\n\ninterface UseWalletEthBalanceResult {\n balance: string | null;\n hasError: boolean;\n}\n\nexport function useWalletEthBalance({\n address,\n refreshKey,\n readBalance,\n pollMs = 15_000,\n onError,\n}: UseWalletEthBalanceOptions): UseWalletEthBalanceResult {\n const [balance, setBalance] = useState<string | null>(null);\n const [hasError, setHasError] = useState(false);\n\n useEffect(() => {\n if (!address) {\n setBalance(null);\n setHasError(false);\n return;\n }\n\n let cancelled = false;\n\n const fetchBalance = () => {\n readBalance(address)\n .then((wei) => {\n if (cancelled) return;\n setBalance(formatEthBalance(wei));\n setHasError(false);\n })\n .catch((error: unknown) => {\n if (cancelled) return;\n setHasError(true);\n onError?.(error);\n });\n };\n\n fetchBalance();\n const interval = setInterval(fetchBalance, pollMs);\n\n return () => {\n cancelled = true;\n clearInterval(interval);\n };\n }, [address, refreshKey, readBalance, pollMs, onError]);\n\n return { balance, hasError };\n}\n"],"mappings":"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","names":["active","useState","useState","useCallback","useCallback","useState","useState","useCallback","useCallback","useCallback","useEffect","useState","useState","useCallback","useEffect","useState","useCallback","useEffect","useRef","useSignMessage","useSignMessage","useEffect","useState"]}
1
+ {"version":3,"sources":["../src/utils/web3.ts","../src/stores/session.ts","../src/blueprints/registry.ts","../src/hooks/useOperators.ts","../src/hooks/useServiceValidation.ts","../src/hooks/useAuthenticatedFetch.ts","../src/hooks/useSessionAuth.ts","../src/hooks/useProvisionProgress.ts","../src/hooks/useSidecarAuth.ts","../src/hooks/useWagmiSidecarAuth.ts","../src/hooks/useWalletEthBalance.ts","../src/hooks/useServiceRequest.ts"],"sourcesContent":["import type { Chain } from 'viem';\nimport { http } from 'wagmi';\nimport { mainnet, rpcUrl, tangleLocal, tangleMainnet, tangleTestnet } from '../contracts/chains';\n\nexport function getTangleWalletChains(localChain: Chain = tangleLocal): readonly [Chain, ...Chain[]] {\n return [localChain, tangleTestnet, tangleMainnet, mainnet];\n}\n\nexport const tangleWalletChains: readonly [Chain, ...Chain[]] = getTangleWalletChains();\n\nexport function createTangleTransports(localChain: Pick<Chain, 'id' | 'rpcUrls'> = tangleLocal) {\n const localRpcUrl = localChain.rpcUrls.default.http[0] ?? rpcUrl;\n\n return {\n [localChain.id]: http(localRpcUrl),\n [tangleTestnet.id]: http('https://testnet-rpc.tangle.tools'),\n [tangleMainnet.id]: http('https://rpc.tangle.tools'),\n [mainnet.id]: http(),\n };\n}\n\nexport const defaultConnectKitOptions = {\n hideBalance: false,\n hideTooltips: false,\n hideQuestionMarkCTA: true,\n overlayBlur: 4,\n} as const;\n","import { persistedAtom } from './persistedAtom';\n\nexport interface SessionEntry {\n token: string;\n address: string;\n expiresAt: number;\n sandboxId: string;\n}\n\n/**\n * Persisted session tokens keyed by sandbox ID.\n * Auto-cleaned on read if expired.\n */\nexport const sessionMapStore = persistedAtom<Record<string, SessionEntry>>({\n key: 'bp_sessions',\n initial: {},\n});\n\n/** Active session for a given sandbox. */\nexport function getSession(sandboxId: string): SessionEntry | null {\n const map = sessionMapStore.get();\n const entry = map[sandboxId];\n if (!entry) return null;\n\n // Check expiry with 60s buffer\n if (Date.now() / 1000 > entry.expiresAt - 60) {\n removeSession(sandboxId);\n return null;\n }\n\n return entry;\n}\n\nexport function setSession(entry: SessionEntry) {\n const map = { ...sessionMapStore.get() };\n map[entry.sandboxId] = entry;\n sessionMapStore.set(map);\n}\n\nexport function removeSession(sandboxId: string) {\n const map = { ...sessionMapStore.get() };\n delete map[sandboxId];\n sessionMapStore.set(map);\n}\n\n/** Clean up all expired sessions. */\nexport function gcSessions() {\n const now = Date.now() / 1000;\n const map = sessionMapStore.get();\n const cleaned: Record<string, SessionEntry> = {};\n let changed = false;\n\n for (const [key, entry] of Object.entries(map) as [string, SessionEntry][]) {\n if (entry.expiresAt > now) {\n cleaned[key] = entry;\n } else {\n changed = true;\n }\n }\n\n if (changed) {\n sessionMapStore.set(cleaned);\n }\n}\n","import type { Address } from 'viem';\n\n/**\n * Blueprint Registry — defines the metadata layer for Tangle blueprints.\n *\n * Each blueprint exposes a set of jobs. The registry maps on-chain job IDs\n * to human-readable metadata: labels, descriptions, categories, form fields,\n * and pricing info. This enables the UI to render appropriate forms for each\n * job without procedurally generating UI from raw ABI data.\n *\n * Third-party blueprints can register here to appear in the wizard.\n */\n\n// ── Types ──\n\nexport type JobCategory = 'lifecycle' | 'execution' | 'batch' | 'workflow' | 'ssh' | 'management';\n\nexport interface JobFieldDef {\n name: string;\n label: string;\n type: 'text' | 'textarea' | 'number' | 'boolean' | 'select' | 'json' | 'combobox';\n placeholder?: string;\n required?: boolean;\n defaultValue?: string | number | boolean;\n options?: { label: string; value: string }[];\n helperText?: string;\n /** Minimum allowed value for number fields */\n min?: number;\n /** Maximum allowed value for number fields */\n max?: number;\n /** Step increment for number fields */\n step?: number;\n /** Solidity ABI type for encoding (e.g. 'string', 'uint64', 'bool', 'uint8') */\n abiType?: string;\n /** ABI param name if different from `name` (e.g. 'agent_identifier' vs 'agentIdentifier') */\n abiParam?: string;\n /** Field is included in ABI encoding but never shown in form (e.g. sidecar_token) */\n internal?: boolean;\n}\n\n/** ABI param injected from runtime context, not user input (e.g. sidecar_url, sandbox_id) */\nexport interface AbiContextParam {\n abiName: string;\n abiType: string;\n}\n\nexport interface JobDefinition {\n id: number;\n name: string;\n label: string;\n description: string;\n category: JobCategory;\n icon: string;\n pricingMultiplier: number;\n /** Fields the user needs to fill for this job */\n fields: JobFieldDef[];\n /** Whether this job requires an existing sandbox to target */\n requiresSandbox: boolean;\n /** Optional warning shown before submission */\n warning?: string;\n /** ABI params prepended from runtime context (e.g. sidecar_url for sandbox jobs) */\n contextParams?: AbiContextParam[];\n /** Override for jobs with complex ABI encoding (e.g. nested structs) */\n customEncoder?: (values: Record<string, unknown>, context?: Record<string, unknown>) => `0x${string}`;\n}\n\nexport interface BlueprintDefinition {\n id: string;\n name: string;\n version: string;\n description: string;\n icon: string;\n color: string;\n /** Contract address per chain ID — resolved at runtime */\n contracts: Record<number, Address>;\n /** Supported job definitions */\n jobs: JobDefinition[];\n /** Category ordering for the UI */\n categories: { key: JobCategory; label: string; icon: string }[];\n}\n\n// ── Registry ──\n\nconst blueprintRegistry = new Map<string, BlueprintDefinition>();\n\nexport function registerBlueprint(bp: BlueprintDefinition) {\n blueprintRegistry.set(bp.id, bp);\n}\n\nexport function getBlueprint(id: string): BlueprintDefinition | undefined {\n return blueprintRegistry.get(id);\n}\n\nexport function getAllBlueprints(): BlueprintDefinition[] {\n return Array.from(blueprintRegistry.values());\n}\n\nexport function getBlueprintJobs(blueprintId: string, category?: JobCategory): JobDefinition[] {\n const bp = blueprintRegistry.get(blueprintId);\n if (!bp) return [];\n return category ? bp.jobs.filter((j) => j.category === category) : bp.jobs;\n}\n\nexport function getJobById(blueprintId: string, jobId: number): JobDefinition | undefined {\n const bp = blueprintRegistry.get(blueprintId);\n return bp?.jobs.find((j) => j.id === jobId);\n}\n","import { useState, useEffect } from 'react';\nimport type { Address } from 'viem';\nimport { tangleOperatorsAbi } from '../contracts/abi';\nimport { publicClient, getAddresses } from '../contracts/publicClient';\n\nexport interface DiscoveredOperator {\n address: Address;\n ecdsaPublicKey: string;\n rpcAddress: string;\n}\n\ninterface OperatorDiscoveryClient {\n readContract(args: Record<string, unknown>): Promise<unknown>;\n getLogs(args: Record<string, unknown>): Promise<Array<Record<string, unknown>>>;\n multicall(args: Record<string, unknown>): Promise<Array<Record<string, unknown>>>;\n}\n\ninterface OperatorDiscoveryResult {\n operators: DiscoveredOperator[];\n operatorCount: bigint;\n}\n\nfunction readPreferenceValue(\n result: unknown,\n field: 'ecdsaPublicKey' | 'rpcAddress',\n): string {\n if (Array.isArray(result)) {\n return String(result[field === 'ecdsaPublicKey' ? 0 : 1] ?? '');\n }\n if (result && typeof result === 'object') {\n return String((result as Record<string, unknown>)[field] ?? '');\n }\n return '';\n}\n\nasync function verifyCandidatesWithMulticall(\n client: OperatorDiscoveryClient,\n servicesAddress: Address,\n blueprintId: bigint,\n candidates: DiscoveredOperator[],\n): Promise<DiscoveredOperator[] | null> {\n const [registrationResults, preferencesResults] = await Promise.all([\n client.multicall({\n contracts: candidates.map((op) => ({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'isOperatorRegistered' as const,\n args: [blueprintId, op.address] as const,\n })),\n }),\n client.multicall({\n contracts: candidates.map((op) => ({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'getOperatorPreferences' as const,\n args: [blueprintId, op.address] as const,\n })),\n }),\n ]);\n\n const hadRegistrationFailure = registrationResults.some((result) => result?.status === 'failure');\n const hadPreferenceFailure = preferencesResults.some((result) => result?.status === 'failure');\n\n const active: DiscoveredOperator[] = [];\n candidates.forEach((op, i) => {\n if (registrationResults[i]?.result !== true) return;\n const prefs = preferencesResults[i];\n if (prefs?.status === 'success' && prefs.result != null) {\n active.push({\n ...op,\n ecdsaPublicKey: readPreferenceValue(prefs.result, 'ecdsaPublicKey') || op.ecdsaPublicKey,\n rpcAddress: readPreferenceValue(prefs.result, 'rpcAddress') || op.rpcAddress,\n });\n return;\n }\n active.push(op);\n });\n\n if (active.length === 0 && (hadRegistrationFailure || hadPreferenceFailure)) {\n return null;\n }\n\n return active;\n}\n\nasync function verifyCandidatesDirectly(\n client: OperatorDiscoveryClient,\n servicesAddress: Address,\n blueprintId: bigint,\n candidates: DiscoveredOperator[],\n): Promise<DiscoveredOperator[]> {\n const results = await Promise.allSettled(\n candidates.map(async (op) => {\n const registration = await client.readContract({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'isOperatorRegistered',\n args: [blueprintId, op.address],\n });\n\n if (registration !== true) {\n return null;\n }\n\n try {\n const preferences = await client.readContract({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'getOperatorPreferences',\n args: [blueprintId, op.address],\n });\n\n return {\n ...op,\n ecdsaPublicKey: readPreferenceValue(preferences, 'ecdsaPublicKey') || op.ecdsaPublicKey,\n rpcAddress: readPreferenceValue(preferences, 'rpcAddress') || op.rpcAddress,\n };\n } catch {\n return op;\n }\n }),\n );\n\n const active = results\n .filter((result): result is PromiseFulfilledResult<DiscoveredOperator | null> => result.status === 'fulfilled')\n .map((result) => result.value)\n .filter((op): op is DiscoveredOperator => op != null);\n\n if (active.length > 0) {\n return active;\n }\n\n const failure = results.find((result): result is PromiseRejectedResult => result.status === 'rejected');\n if (failure) {\n throw failure.reason instanceof Error ? failure.reason : new Error(String(failure.reason));\n }\n\n return [];\n}\n\n/**\n * Shared discovery logic for operator lookup.\n * Tries multicall first for efficiency, then falls back to direct reads when\n * multicall is unavailable in local/dev environments.\n */\nexport async function discoverOperatorsWithClient(\n client: OperatorDiscoveryClient,\n servicesAddress: Address,\n blueprintId: bigint,\n): Promise<OperatorDiscoveryResult> {\n const count = await client.readContract({\n address: servicesAddress,\n abi: tangleOperatorsAbi,\n functionName: 'blueprintOperatorCount',\n args: [blueprintId],\n });\n const operatorCount = count as bigint;\n\n if (operatorCount === 0n) {\n return { operators: [], operatorCount };\n }\n\n const registeredLogs = await client.getLogs({\n address: servicesAddress,\n event: {\n type: 'event' as const,\n name: 'OperatorRegistered',\n inputs: [\n { name: 'blueprintId', type: 'uint64', indexed: true },\n { name: 'operator', type: 'address', indexed: true },\n { name: 'ecdsaPublicKey', type: 'bytes', indexed: false },\n { name: 'rpcAddress', type: 'string', indexed: false },\n ],\n },\n args: { blueprintId },\n fromBlock: 0n,\n toBlock: 'latest',\n });\n\n const byAddress = new Map<Address, DiscoveredOperator>();\n for (const log of registeredLogs) {\n const args = (log.args ?? {}) as Record<string, unknown>;\n const addr = args.operator as Address | undefined;\n if (!addr) continue;\n byAddress.set(addr, {\n address: addr,\n ecdsaPublicKey: String(args.ecdsaPublicKey ?? '0x'),\n rpcAddress: String(args.rpcAddress ?? ''),\n });\n }\n\n const candidates = Array.from(byAddress.values());\n if (candidates.length === 0) {\n return { operators: [], operatorCount };\n }\n\n try {\n const active = await verifyCandidatesWithMulticall(client, servicesAddress, blueprintId, candidates);\n if (active != null) {\n return { operators: active, operatorCount };\n }\n } catch {\n // Fall through to direct reads below.\n }\n\n const active = await verifyCandidatesDirectly(client, servicesAddress, blueprintId, candidates);\n return { operators: active, operatorCount };\n}\n\n/**\n * Discover operators registered for a blueprint by scanning OperatorRegistered\n * events, then verifying each is still active. Falls back to direct reads when\n * multicall is unavailable.\n */\nexport function useOperators(blueprintId: bigint) {\n const [operators, setOperators] = useState<DiscoveredOperator[]>([]);\n const [operatorCount, setOperatorCount] = useState<bigint>(0n);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n const addrs = getAddresses();\n\n async function discover() {\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await discoverOperatorsWithClient(publicClient, addrs.services, blueprintId);\n if (cancelled) return;\n setOperatorCount(result.operatorCount);\n setOperators(result.operators);\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n if (!cancelled) setIsLoading(false);\n }\n }\n\n discover();\n return () => { cancelled = true; };\n }, [blueprintId]);\n\n return { operators, isLoading, error, operatorCount };\n}\n","import { useState, useCallback } from 'react';\nimport type { Address } from 'viem';\nimport { tangleServicesAbi } from '../contracts/abi';\nimport { publicClient, getAddresses } from '../contracts/publicClient';\n\nexport interface ServiceInfo {\n active: boolean;\n blueprintId: bigint;\n owner: Address;\n operatorCount: number;\n operators: Address[];\n permitted: boolean;\n ttl: bigint;\n createdAt: bigint;\n}\n\n/**\n * Validate a service on-chain: check if active, fetch operators,\n * verify the current user is a permitted caller.\n */\nexport function useServiceValidation() {\n const [isValidating, setIsValidating] = useState(false);\n const [serviceInfo, setServiceInfo] = useState<ServiceInfo | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const validate = useCallback(async (serviceId: bigint, userAddress?: Address) => {\n setIsValidating(true);\n setError(null);\n setServiceInfo(null);\n\n const addrs = getAddresses();\n\n try {\n // Run reads in parallel without multicall to avoid type union issues\n const [isActiveResult, serviceDataResult, operatorsResult, permittedResult] = await Promise.all([\n publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'isServiceActive',\n args: [serviceId],\n }).catch(() => false),\n\n publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'getService',\n args: [serviceId],\n }).catch(() => null),\n\n publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'getServiceOperators',\n args: [serviceId],\n }).catch(() => [] as readonly Address[]),\n\n userAddress\n ? publicClient.readContract({\n address: addrs.services,\n abi: tangleServicesAbi,\n functionName: 'isPermittedCaller',\n args: [serviceId, userAddress],\n }).catch(() => false)\n : Promise.resolve(true),\n ]);\n\n const isActive = isActiveResult as boolean;\n const serviceData = serviceDataResult as Record<string, any> | null;\n const operators = (operatorsResult ?? []) as readonly Address[];\n const permitted = permittedResult as boolean;\n\n if (!serviceData) {\n setError('Service not found');\n setIsValidating(false);\n return null;\n }\n\n const info: ServiceInfo = {\n active: isActive,\n blueprintId: serviceData.blueprintId ?? serviceData[0] ?? 0n,\n owner: serviceData.owner ?? serviceData[1] ?? ('0x0' as Address),\n operatorCount: operators.length,\n operators: [...operators],\n permitted,\n ttl: serviceData.ttl ?? serviceData[3] ?? 0n,\n createdAt: serviceData.createdAt ?? serviceData[2] ?? 0n,\n };\n\n setServiceInfo(info);\n\n if (!isActive) {\n setError('Service is not active');\n } else if (!permitted && userAddress) {\n setError('You are not a permitted caller for this service');\n }\n\n setIsValidating(false);\n return info;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n setError(msg);\n setIsValidating(false);\n return null;\n }\n }, []);\n\n const reset = useCallback(() => {\n setServiceInfo(null);\n setError(null);\n }, []);\n\n return { validate, reset, isValidating, serviceInfo, error };\n}\n","import { useCallback } from 'react';\nimport { getSession } from '../stores/session';\nimport { useSessionAuth } from './useSessionAuth';\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\ninterface UseAuthenticatedFetchOptions {\n sandboxId: string;\n apiUrl?: string;\n}\n\n/**\n * Returns a `fetch` wrapper that injects the Bearer session token.\n * If the token is expired or a 401 is received, triggers re-authentication.\n */\nexport function useAuthenticatedFetch({ sandboxId, apiUrl }: UseAuthenticatedFetchOptions) {\n const { authenticate } = useSessionAuth({ sandboxId, apiUrl });\n\n const authFetch = useCallback(\n async (url: string, init?: RequestInit): Promise<Response> => {\n let session = getSession(sandboxId);\n\n // If no session, authenticate first\n if (!session) {\n session = await authenticate();\n if (!session) {\n throw new Error('Authentication required');\n }\n }\n\n // Make request with token\n const headers = new Headers(init?.headers);\n headers.set('Authorization', `Bearer ${session.token}`);\n\n const res = await fetch(url, { ...init, headers });\n\n // If 401, try re-authenticating once\n if (res.status === 401) {\n session = await authenticate();\n if (!session) {\n throw new Error('Re-authentication failed');\n }\n\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set('Authorization', `Bearer ${session.token}`);\n return fetch(url, { ...init, headers: retryHeaders });\n }\n\n return res;\n },\n [sandboxId, authenticate],\n );\n\n return { authFetch };\n}\n","import { useCallback, useState } from 'react';\nimport { useSignMessage } from 'wagmi';\nimport { getSession, setSession, removeSession, type SessionEntry } from '../stores/session';\nimport { getEnvVar } from '../utils/env';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ChallengeResponse {\n nonce: string;\n message: string;\n expires_at: number;\n}\n\ninterface SessionResponse {\n token: string;\n address: string;\n expires_at: number;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\ninterface UseSessionAuthOptions {\n sandboxId: string;\n apiUrl?: string;\n}\n\nexport function useSessionAuth({ sandboxId, apiUrl }: UseSessionAuthOptions) {\n const baseUrl = apiUrl ?? getEnvVar('VITE_OPERATOR_API_URL') ?? 'http://localhost:9090';\n const { signMessageAsync } = useSignMessage();\n\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Get cached session\n const session = getSession(sandboxId);\n\n const authenticate = useCallback(async (): Promise<SessionEntry | null> => {\n setIsAuthenticating(true);\n setError(null);\n\n try {\n // Step 1: Request challenge\n const challengeRes = await fetch(`${baseUrl}/api/auth/challenge`, {\n method: 'POST',\n });\n if (!challengeRes.ok) {\n throw new Error(`Challenge request failed: HTTP ${challengeRes.status}`);\n }\n const challenge: ChallengeResponse = await challengeRes.json();\n\n // Step 2: Sign with wallet\n const signature = await signMessageAsync({ message: challenge.message });\n\n // Step 3: Exchange signature for session token\n const sessionRes = await fetch(`${baseUrl}/api/auth/session`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n nonce: challenge.nonce,\n signature,\n }),\n });\n if (!sessionRes.ok) {\n const body = await sessionRes.json().catch(() => ({}));\n throw new Error(body.error ?? `Session exchange failed: HTTP ${sessionRes.status}`);\n }\n const sessionData: SessionResponse = await sessionRes.json();\n\n // Step 4: Store session\n const entry: SessionEntry = {\n token: sessionData.token,\n address: sessionData.address,\n expiresAt: sessionData.expires_at,\n sandboxId,\n };\n setSession(entry);\n\n return entry;\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Authentication failed';\n setError(msg);\n return null;\n } finally {\n setIsAuthenticating(false);\n }\n }, [baseUrl, sandboxId, signMessageAsync]);\n\n const logout = useCallback(() => {\n removeSession(sandboxId);\n }, [sandboxId]);\n\n return {\n session,\n isAuthenticated: session !== null,\n isAuthenticating,\n error,\n authenticate,\n logout,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { getEnvVar } from '../utils/env';\n\n// ---------------------------------------------------------------------------\n// Types matching sandbox-runtime/src/provision_progress.rs\n// ---------------------------------------------------------------------------\n\nexport type ProvisionPhase =\n | 'queued'\n | 'image_pull'\n | 'container_create'\n | 'container_start'\n | 'health_check'\n | 'ready'\n | 'failed';\n\nexport interface ProvisionStatus {\n call_id: number;\n sandbox_id: string | null;\n phase: ProvisionPhase;\n message: string | null;\n started_at: number;\n updated_at: number;\n progress_pct: number;\n sidecar_url: string | null;\n}\n\nconst PHASE_LABELS: Record<ProvisionPhase, string> = {\n queued: 'Queued',\n image_pull: 'Pulling image',\n container_create: 'Creating container',\n container_start: 'Starting container',\n health_check: 'Health check',\n ready: 'Ready',\n failed: 'Failed',\n};\n\nexport function getPhaseLabel(phase: ProvisionPhase): string {\n return PHASE_LABELS[phase] ?? phase;\n}\n\nexport function isTerminalPhase(phase: ProvisionPhase): boolean {\n return phase === 'ready' || phase === 'failed';\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nconst POLL_INTERVAL = 2000;\n\ninterface UseProvisionProgressOptions {\n callId: number | null;\n apiUrl?: string;\n enabled?: boolean;\n}\n\nexport function useProvisionProgress({\n callId,\n apiUrl,\n enabled = true,\n}: UseProvisionProgressOptions) {\n const [status, setStatus] = useState<ProvisionStatus | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [isPolling, setIsPolling] = useState(false);\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const baseUrl = apiUrl ?? getEnvVar('VITE_OPERATOR_API_URL') ?? 'http://localhost:9090';\n\n const fetchProgress = useCallback(async () => {\n if (callId == null) return;\n\n try {\n const res = await fetch(`${baseUrl}/api/provisions/${callId}`);\n if (res.status === 404) {\n // Not yet tracked — keep polling\n return;\n }\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n const data: ProvisionStatus = await res.json();\n setStatus(data);\n setError(null);\n\n // Stop polling on terminal phase\n if (isTerminalPhase(data.phase) && intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n setIsPolling(false);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to fetch provision status');\n }\n }, [callId, baseUrl]);\n\n useEffect(() => {\n if (!enabled || callId == null) return;\n\n setIsPolling(true);\n fetchProgress(); // Initial fetch\n\n intervalRef.current = setInterval(fetchProgress, POLL_INTERVAL);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n setIsPolling(false);\n };\n }, [enabled, callId, fetchProgress]);\n\n return {\n status,\n error,\n isPolling,\n phase: status?.phase ?? null,\n progressPct: status?.progress_pct ?? 0,\n sandboxId: status?.sandbox_id ?? null,\n sidecarUrl: status?.sidecar_url ?? null,\n message: status?.message ?? null,\n isReady: status?.phase === 'ready',\n isFailed: status?.phase === 'failed',\n };\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseSidecarAuthOptions {\n /** Scoping key for token storage (e.g. botId, sandboxId). */\n resourceId: string;\n /** Base URL of the sidecar or operator API. */\n apiUrl: string;\n /**\n * Sign a plaintext message and return the hex signature.\n * Consuming apps wire this to their wallet library (e.g. wagmi's signMessageAsync).\n */\n signMessage: (message: string) => Promise<string>;\n}\n\nexport interface SidecarAuth {\n token: string | null;\n isAuthenticated: boolean;\n isAuthenticating: boolean;\n authenticate: () => Promise<string | null>;\n clearCachedToken: () => void;\n error: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// localStorage helpers\n// ---------------------------------------------------------------------------\n\nfunction storageKey(resourceId: string, apiUrl: string): string {\n return `sidecar_session_${resourceId}__${apiUrl}`;\n}\n\nfunction loadSession(resourceId: string, apiUrl: string): { token: string; expiresAt: number } | null {\n if (typeof window === 'undefined') return null;\n try {\n const raw = localStorage.getItem(storageKey(resourceId, apiUrl));\n if (!raw) return null;\n const data = JSON.parse(raw) as { token: string; expiresAt: number };\n // Discard if within 60s of expiry\n if (data.expiresAt * 1000 - Date.now() < 60_000) {\n localStorage.removeItem(storageKey(resourceId, apiUrl));\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\nfunction saveSession(resourceId: string, apiUrl: string, token: string, expiresAt: number) {\n if (typeof window === 'undefined') return;\n try {\n localStorage.setItem(storageKey(resourceId, apiUrl), JSON.stringify({ token, expiresAt }));\n } catch {\n // storage full — ignore\n }\n}\n\nfunction clearSession(resourceId: string, apiUrl: string) {\n if (typeof window === 'undefined') return;\n localStorage.removeItem(storageKey(resourceId, apiUrl));\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Generic sidecar PASETO challenge/response auth.\n *\n * Flow:\n * 1. POST /api/auth/challenge -> { nonce, message, expires_at }\n * 2. signMessage(message) -> signature (provided by consuming app)\n * 3. POST /api/auth/session -> { token, address, expires_at }\n *\n * Tokens are cached in localStorage and auto-refreshed 5 minutes before expiry.\n */\nexport function useSidecarAuth({ resourceId, apiUrl, signMessage }: UseSidecarAuthOptions): SidecarAuth {\n const cached = loadSession(resourceId, apiUrl);\n const [token, setToken] = useState<string | null>(cached?.token ?? null);\n const [expiresAt, setExpiresAt] = useState<number>(cached?.expiresAt ?? 0);\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const refreshTimerRef = useRef<ReturnType<typeof setTimeout>>();\n\n const clearCachedToken = useCallback(() => {\n setToken(null);\n setExpiresAt(0);\n clearSession(resourceId, apiUrl);\n }, [resourceId, apiUrl]);\n\n const authenticate = useCallback(async (): Promise<string | null> => {\n if (!apiUrl) return null;\n setIsAuthenticating(true);\n setError(null);\n\n try {\n // Step 1: Get challenge\n const challengeRes = await fetch(`${apiUrl}/api/auth/challenge`, {\n method: 'POST',\n });\n if (!challengeRes.ok) {\n throw new Error(`Challenge failed: ${challengeRes.status}`);\n }\n const { nonce, message } = await challengeRes.json();\n\n // Step 2: Sign with wallet (injected)\n const signature = await signMessage(message);\n\n // Step 3: Exchange for session token\n const sessionRes = await fetch(`${apiUrl}/api/auth/session`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ nonce, signature }),\n });\n if (!sessionRes.ok) {\n const text = await sessionRes.text();\n throw new Error(text || `Session exchange failed: ${sessionRes.status}`);\n }\n\n const { token: newToken, expires_at } = await sessionRes.json();\n setToken(newToken);\n setExpiresAt(expires_at);\n saveSession(resourceId, apiUrl, newToken, expires_at);\n return newToken;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Authentication failed');\n clearCachedToken();\n return null;\n } finally {\n setIsAuthenticating(false);\n }\n }, [resourceId, apiUrl, signMessage, clearCachedToken]);\n\n // Auto-refresh token 5 minutes before expiry\n useEffect(() => {\n if (refreshTimerRef.current) {\n clearTimeout(refreshTimerRef.current);\n }\n\n if (!token || !expiresAt) return;\n\n const msUntilRefresh = (expiresAt - 300) * 1000 - Date.now();\n if (msUntilRefresh <= 0) {\n clearCachedToken();\n return;\n }\n\n refreshTimerRef.current = setTimeout(() => {\n authenticate().catch(() => {\n clearCachedToken();\n });\n }, msUntilRefresh);\n\n return () => {\n if (refreshTimerRef.current) {\n clearTimeout(refreshTimerRef.current);\n }\n };\n }, [token, expiresAt, authenticate, clearCachedToken]);\n\n return {\n token,\n isAuthenticated: token !== null,\n isAuthenticating,\n authenticate,\n clearCachedToken,\n error,\n };\n}\n","import { useSignMessage } from 'wagmi';\nimport { useSidecarAuth } from './useSidecarAuth';\n\nexport function useWagmiSidecarAuth(resourceId: string, apiUrl: string) {\n const { signMessageAsync } = useSignMessage();\n return useSidecarAuth({\n resourceId,\n apiUrl,\n signMessage: (msg: string) => signMessageAsync({ message: msg }),\n });\n}\n","import { useEffect, useState } from 'react';\n\nconst WEI_PER_ETH = 1_000_000_000_000_000_000n;\nconst DISPLAY_SCALE = 1_000n; // 3 decimal places\n\nfunction formatEthBalance(wei: bigint): string {\n const whole = wei / WEI_PER_ETH;\n const fraction = ((wei % WEI_PER_ETH) * DISPLAY_SCALE) / WEI_PER_ETH;\n return `${whole.toString()}.${fraction.toString().padStart(3, '0')}`;\n}\n\ninterface UseWalletEthBalanceOptions {\n address?: string;\n refreshKey?: number | string;\n readBalance: (address: string) => Promise<bigint>;\n pollMs?: number;\n onError?: (error: unknown) => void;\n}\n\ninterface UseWalletEthBalanceResult {\n balance: string | null;\n hasError: boolean;\n}\n\nexport function useWalletEthBalance({\n address,\n refreshKey,\n readBalance,\n pollMs = 15_000,\n onError,\n}: UseWalletEthBalanceOptions): UseWalletEthBalanceResult {\n const [balance, setBalance] = useState<string | null>(null);\n const [hasError, setHasError] = useState(false);\n\n useEffect(() => {\n if (!address) {\n setBalance(null);\n setHasError(false);\n return;\n }\n\n let cancelled = false;\n\n const fetchBalance = () => {\n readBalance(address)\n .then((wei) => {\n if (cancelled) return;\n setBalance(formatEthBalance(wei));\n setHasError(false);\n })\n .catch((error: unknown) => {\n if (cancelled) return;\n setHasError(true);\n onError?.(error);\n });\n };\n\n fetchBalance();\n const interval = setInterval(fetchBalance, pollMs);\n\n return () => {\n cancelled = true;\n clearInterval(interval);\n };\n }, [address, refreshKey, readBalance, pollMs, onError]);\n\n return { balance, hasError };\n}\n","/**\n * Hook to request a service instance on-chain.\n * Thin wrapper around wagmi's useWriteContract + the existing tangleServicesAbi.\n */\nimport { useWriteContract } from 'wagmi';\nimport { tangleServicesAbi } from '../contracts/abi';\nimport { getAddresses } from '../contracts/publicClient';\nimport type { Address } from 'viem';\nimport { useCallback } from 'react';\n\nexport interface ServiceRequestParams {\n blueprintId: bigint;\n operators: Address[];\n config: `0x${string}`;\n permittedCallers: Address[];\n ttl: bigint;\n paymentToken: Address;\n paymentAmount: bigint;\n}\n\nexport function useServiceRequest(): {\n requestService: (params: ServiceRequestParams) => Promise<`0x${string}`>;\n isPending: boolean;\n error: Error | null;\n txHash: `0x${string}` | undefined;\n} {\n const { writeContractAsync, isPending, error, data: txHash } =\n useWriteContract();\n\n const requestService = useCallback(\n async (params: ServiceRequestParams) => {\n const addresses = getAddresses();\n return writeContractAsync({\n address: addresses.services,\n abi: tangleServicesAbi,\n functionName: 'requestService',\n args: [\n params.blueprintId,\n params.operators,\n params.config,\n params.permittedCallers,\n params.ttl,\n params.paymentToken,\n params.paymentAmount,\n ],\n });\n },\n [writeContractAsync],\n );\n\n return { requestService, isPending, error, txHash };\n}\n"],"mappings":"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","names":["active","useState","useState","useCallback","useCallback","useState","useState","useCallback","useCallback","useCallback","useEffect","useState","useState","useCallback","useEffect","useState","useCallback","useEffect","useRef","useSignMessage","useSignMessage","useEffect","useState","useCallback"]}
package/dist/styles.css CHANGED
@@ -245,6 +245,7 @@
245
245
  .leading-none{--un-leading:var(--leading-none);line-height:var(--leading-none);}
246
246
  .tracking-wider{--un-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);}
247
247
  .font-medium{--un-font-weight:var(--fontWeight-medium);font-weight:var(--fontWeight-medium);}
248
+ .font-mono{font-family:var(--font-mono);}
248
249
  .font-semibold{--un-font-weight:var(--fontWeight-semibold);font-weight:var(--fontWeight-semibold);}
249
250
  .tab{-moz-tab-size:4;-o-tab-size:4;tab-size:4;}
250
251
  .mx-auto{margin-inline:auto;}
@@ -293,6 +294,7 @@
293
294
  .outline-none{--un-outline-style:none;outline-style:none;}
294
295
  .focus\:outline-none:focus{--un-outline-style:none;outline-style:none;}
295
296
  .\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px;}
297
+ .b,
296
298
  .border{border-width:1px;}
297
299
  .border-2{border-width:2px;}
298
300
  .border-b{border-bottom-width:1px;}
@@ -412,6 +414,8 @@
412
414
  .resize-y{resize:vertical;}
413
415
  .select-none{-webkit-user-select:none;user-select:none;}
414
416
  .whitespace-nowrap{white-space:nowrap;}
417
+ .whitespace-pre-wrap{white-space:pre-wrap;}
418
+ .break-all{word-break:break-all;}
415
419
  .truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
416
420
  .uppercase{text-transform:uppercase;}
417
421
  .focus-within\:ring-2:focus-within{--un-ring-shadow:var(--un-ring-inset,) 0 0 0 calc(2px + var(--un-ring-offset-width)) var(--un-ring-color, currentColor);box-shadow:var(--un-inset-shadow), var(--un-inset-ring-shadow), var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
@@ -464,6 +468,7 @@
464
468
  .z-50{z-index:50;}
465
469
  .overflow-auto{overflow:auto;}
466
470
  .overflow-hidden{overflow:hidden;}
471
+ .overflow-x-auto{overflow-x:auto;}
467
472
  .overflow-y-auto{overflow-y:auto;}
468
473
  .fill-bp-elements-textPrimary{fill:color-mix(in srgb, var(--bp-elements-textPrimary) var(--un-fill-opacity), transparent);}
469
474
  .stroke-none{stroke:none;}
@@ -121,4 +121,31 @@ type BlueprintHostPanelProps = {
121
121
  };
122
122
  declare function BlueprintHostPanel({ title, children, className, }: BlueprintHostPanelProps): react_jsx_runtime.JSX.Element;
123
123
 
124
- export { type AbiContextParam as A, type BlueprintDefinition as B, type JobDefinition as J, BlueprintHostHero as a, type BlueprintHostHeroProps as b, BlueprintHostPanel as c, type BlueprintHostPanelProps as d, type JobCategory as e, type JobFieldDef as f, getAllBlueprints as g, getBlueprint as h, getBlueprintJobs as i, getJobById as j, Button as k, buttonVariants as l, registerBlueprint as r };
124
+ type RegistrationMode = 'cargo-tangle' | 'cast';
125
+ interface RegistrationCommandOptions {
126
+ blueprintId: bigint;
127
+ rpcAddress: string;
128
+ ecdsaPublicKey: string;
129
+ rpcUrl: string;
130
+ registrationInputs?: string;
131
+ mode?: RegistrationMode;
132
+ /** Contract address for cast mode (defaults to TANGLE_CORE placeholder). */
133
+ servicesAddress?: string;
134
+ }
135
+ interface RegistrationCommandResult {
136
+ /** The copy-paste command for the operator to run on their VPS. */
137
+ command: string;
138
+ /** A human-readable label for the command type. */
139
+ label: string;
140
+ /** The blueprint id as a plain number (for display). */
141
+ blueprintIdNumber: number;
142
+ }
143
+ /**
144
+ * Builds the operator registration command string for the given blueprint.
145
+ * Two modes:
146
+ * - `cargo-tangle` (default) — the canonical `cargo tangle blueprint register` flow.
147
+ * - `cast` — raw `cast send` for operators who manage their own keys.
148
+ */
149
+ declare function useRegistrationCommand(options: RegistrationCommandOptions): RegistrationCommandResult;
150
+
151
+ export { type AbiContextParam as A, type BlueprintDefinition as B, type JobDefinition as J, type RegistrationCommandOptions as R, BlueprintHostHero as a, type BlueprintHostHeroProps as b, BlueprintHostPanel as c, type BlueprintHostPanelProps as d, type JobCategory as e, type JobFieldDef as f, type RegistrationCommandResult as g, type RegistrationMode as h, getAllBlueprints as i, getBlueprint as j, getBlueprintJobs as k, getJobById as l, Button as m, buttonVariants as n, registerBlueprint as r, useRegistrationCommand as u };
@@ -1,8 +1,48 @@
1
1
  export { T as TANGLE_CLOUD_ORIGINS_DEFAULT, d as detectTangleCloudParentOrigin } from '../detectParentOrigin-BYruoIdc.js';
2
2
  import * as wagmi from 'wagmi';
3
+ import { CreateConnectorFn } from 'wagmi';
3
4
  import { Address } from 'viem';
4
5
  export { A as AccountChanged, C as CallJobRequest, a as ChainChanged, b as ChainContext, H as HandshakeAck, c as HandshakeRequest, I as IframeRequest, J as JobInputs, d as JobResultEvent, e as JobResultStatus, N as NO_WALLET_ADDRESS, P as ParentMessage, R as ReadAccountRequest, f as ReadAccountResult, S as ServiceContextBroadcast, g as ServiceContextJob, h as ServiceContextOperator, i as SignMessageRequest, j as SignMessageResult, k as SignTransactionRequest, l as SignTransactionResult, m as SignTypedDataRequest, n as SignTypedDataResult, o as SwitchChainRequest, p as SwitchChainResult, T as TANGLE_IFRAME_PROTOCOL_PREFIX, q as TANGLE_IFRAME_PROTOCOL_VERSION, r as makeCorrelationId } from '../parentBridgeProtocol-BSgLXg9g.js';
5
6
 
7
+ interface TangleBlueprintConnectorsOptions {
8
+ /** App id reported to the parent dapp on handshake (when embedded). */
9
+ appId: string;
10
+ /**
11
+ * Connectors used when running STANDALONE (the app's own domain) — e.g.
12
+ * `[injected(), walletConnect({ projectId })]`. Ignored when embedded.
13
+ */
14
+ standalone: CreateConnectorFn[];
15
+ /** Extra trusted parent origins (staging / preview deploys). */
16
+ extraOrigins?: readonly string[];
17
+ /** Override the bridged-request timeout (ms). */
18
+ requestTimeoutMs?: number;
19
+ }
20
+ /**
21
+ * One connector list, two deployment modes — so a blueprint app can ship a
22
+ * single build that runs both standalone and embedded in Tangle Cloud:
23
+ *
24
+ * - **Embedded** (a trusted Tangle Cloud parent is detected): the
25
+ * parent-bridge connector is the *only* connector. The sandboxed iframe
26
+ * can't inject a wallet extension, so it inherits / drives the parent's
27
+ * wallet over the postMessage bridge — surfacing injected/WalletConnect
28
+ * here would just dead-end.
29
+ * - **Standalone** (no trusted parent): the app's own `standalone`
30
+ * connectors, exactly as a normal dapp.
31
+ *
32
+ * The choice is made at runtime from the embedding context, so the same
33
+ * artifact works in both places with no build flags.
34
+ *
35
+ * createConfig({
36
+ * chains,
37
+ * transports,
38
+ * connectors: tangleBlueprintConnectors({
39
+ * appId: 'trading-arena',
40
+ * standalone: [injected(), walletConnect({ projectId })],
41
+ * }),
42
+ * })
43
+ */
44
+ declare function tangleBlueprintConnectors(options: TangleBlueprintConnectorsOptions): CreateConnectorFn[];
45
+
6
46
  type EventName = 'accountsChanged' | 'chainChanged' | 'connect' | 'disconnect' | 'message';
7
47
  type Listener = (...args: unknown[]) => void;
8
48
  type ParentBridgeOptions = {
@@ -91,4 +131,4 @@ declare class ParentBridgeProvider {
91
131
  type ParentBridgeConnectorOptions = ParentBridgeOptions;
92
132
  declare function parentBridgeConnector(options: ParentBridgeConnectorOptions): wagmi.CreateConnectorFn<ParentBridgeProvider, Record<string, unknown>, Record<string, unknown>>;
93
133
 
94
- export { type ParentBridgeConnectorOptions, type ParentBridgeOptions, ParentBridgeProvider, isRunningInIframe, parentBridgeConnector };
134
+ export { type ParentBridgeConnectorOptions, type ParentBridgeOptions, ParentBridgeProvider, type TangleBlueprintConnectorsOptions, isRunningInIframe, parentBridgeConnector, tangleBlueprintConnectors };
@@ -440,6 +440,23 @@ function parentBridgeConnector(options) {
440
440
  };
441
441
  });
442
442
  }
443
+
444
+ // src/wallet/tangleConnectors.ts
445
+ function tangleBlueprintConnectors(options) {
446
+ const parentOrigin = detectTangleCloudParentOrigin({
447
+ extraOrigins: options.extraOrigins
448
+ });
449
+ if (parentOrigin === null) {
450
+ return options.standalone;
451
+ }
452
+ return [
453
+ parentBridgeConnector({
454
+ parentOrigin,
455
+ appId: options.appId,
456
+ ...options.requestTimeoutMs !== void 0 ? { requestTimeoutMs: options.requestTimeoutMs } : {}
457
+ })
458
+ ];
459
+ }
443
460
  export {
444
461
  NO_WALLET_ADDRESS,
445
462
  ParentBridgeProvider,
@@ -449,6 +466,7 @@ export {
449
466
  detectTangleCloudParentOrigin,
450
467
  isRunningInIframe,
451
468
  makeCorrelationId,
452
- parentBridgeConnector
469
+ parentBridgeConnector,
470
+ tangleBlueprintConnectors
453
471
  };
454
472
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/wallet/parentBridgeConnector.ts","../../src/wallet/parentBridgeProvider.ts"],"sourcesContent":["// Wagmi connector that proxies wallet operations to the Tangle Cloud parent\n// dapp via the iframe postMessage bridge. Becomes the autoConnect target\n// when this app is loaded inside an iframe sandbox without a window.ethereum\n// — i.e. always, when embedded by cloud.tangle.tools.\n//\n// Architecture: the connector owns one `ParentBridgeProvider` (singleton),\n// forwards every wagmi method to it, and reflects the provider's EIP-1193\n// events back to wagmi's emitter so the rest of the dapp (ConnectKit's\n// account chip, hooks like useAccount/useChainId) reacts to parent-state\n// changes without polling.\n\nimport type { Address, Chain } from 'viem';\nimport { createConnector } from 'wagmi';\n\nimport { ParentBridgeProvider, type ParentBridgeOptions } from './parentBridgeProvider';\n\nexport type ParentBridgeConnectorOptions = ParentBridgeOptions;\n\nexport function parentBridgeConnector(options: ParentBridgeConnectorOptions) {\n let provider: ParentBridgeProvider | undefined;\n let installed = false;\n\n return createConnector<ParentBridgeProvider>((config) => {\n const ensureProvider = (): ParentBridgeProvider => {\n if (!provider) provider = new ParentBridgeProvider(options);\n if (!installed) {\n provider.install();\n installed = true;\n // Wire the provider's EIP-1193 events to wagmi's emitter so\n // ConnectKit and useAccount/useChainId reflect parent-state changes\n // without polling.\n provider.on('accountsChanged', (accounts) => {\n config.emitter.emit('change', {\n accounts: Array.isArray(accounts)\n ? (accounts as readonly Address[])\n : ([] as readonly Address[]),\n });\n });\n provider.on('chainChanged', (chainIdHex) => {\n const chainId =\n typeof chainIdHex === 'string'\n ? Number.parseInt(chainIdHex, 16)\n : Number(chainIdHex);\n if (Number.isFinite(chainId)) {\n config.emitter.emit('change', { chainId });\n }\n });\n provider.on('disconnect', () => {\n config.emitter.emit('disconnect');\n });\n }\n return provider;\n };\n\n return {\n id: 'tangleParentBridge',\n name: 'Tangle Cloud',\n type: 'parentBridge',\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async connect(): Promise<any> {\n // wagmi v3's connect() return type is a conditional based on\n // `withCapabilities`. We always return plain addresses; cast through\n // `any` rather than re-implementing the type predicate.\n const p = ensureProvider();\n const accountsResult = (await p.request({\n method: 'eth_requestAccounts',\n })) as readonly Address[];\n const chainIdHex = (await p.request({ method: 'eth_chainId' })) as string;\n const chainId = Number.parseInt(chainIdHex, 16);\n return {\n accounts: accountsResult,\n chainId: Number.isFinite(chainId) ? chainId : 0,\n };\n },\n\n async disconnect() {\n // Disconnect from the iframe's perspective is a local-only state\n // reset — we can't ask the parent dapp to disconnect its wallet on\n // our behalf, and a real disconnect should be initiated from the\n // parent's UI. Tear down listeners + the message bridge so a future\n // reconnect re-handshakes cleanly.\n if (provider) provider.uninstall();\n installed = false;\n provider = undefined;\n },\n\n async getAccounts() {\n const p = ensureProvider();\n const cached = p.getCachedAccount();\n if (cached) return [cached];\n const accounts = (await p.request({\n method: 'eth_accounts',\n })) as readonly Address[];\n return accounts;\n },\n\n async getChainId() {\n const p = ensureProvider();\n const cached = p.getCachedChainId();\n if (cached !== null) return cached;\n const chainIdHex = (await p.request({ method: 'eth_chainId' })) as string;\n const chainId = Number.parseInt(chainIdHex, 16);\n return Number.isFinite(chainId) ? chainId : 0;\n },\n\n async getProvider() {\n return ensureProvider();\n },\n\n async isAuthorized() {\n // Always authorized when in iframe mode — the parent dapp has\n // already gated access by being the embedder. Returning `true`\n // makes wagmi auto-reconnect on every page load, which is the\n // right UX (iframe → parent wallet is always-on).\n try {\n const p = ensureProvider();\n const accounts = (await p.request({\n method: 'eth_accounts',\n })) as readonly Address[];\n return accounts.length > 0;\n } catch {\n return false;\n }\n },\n\n async switchChain({ chainId }): Promise<Chain> {\n const p = ensureProvider();\n await p.request({\n method: 'wallet_switchEthereumChain',\n params: [{ chainId: `0x${chainId.toString(16)}` }],\n });\n const chain = config.chains.find((c) => c.id === chainId);\n if (!chain) {\n throw new Error(`Chain ${chainId} not configured for this app`);\n }\n return chain;\n },\n\n onAccountsChanged(accounts) {\n config.emitter.emit('change', {\n accounts: accounts as readonly Address[],\n });\n },\n onChainChanged(chainIdHex) {\n const chainId = Number.parseInt(chainIdHex, 16);\n if (Number.isFinite(chainId)) {\n config.emitter.emit('change', { chainId });\n }\n },\n onDisconnect() {\n config.emitter.emit('disconnect');\n },\n };\n });\n}\n","// EIP-1193 provider implementation that proxies wallet calls to the parent\n// dapp via window.postMessage. The iframe doesn't talk to a wallet directly\n// — it inherits the parent's connected account + chain, and forwards signing\n// requests through the existing tangle.app.* protocol.\n//\n// This is the lowest layer of the parent-bridge stack. Wagmi sees this as a\n// regular Ethereum provider and routes `eth_accounts`, `eth_chainId`,\n// `personal_sign`, `eth_sendTransaction`, `wallet_switchEthereumChain`, etc.\n// through it.\n\nimport type { Address, Hex } from 'viem';\n\nimport {\n makeCorrelationId,\n NO_WALLET_ADDRESS,\n TANGLE_IFRAME_PROTOCOL_VERSION,\n type ConnectResult,\n type ParentMessage,\n type ReadAccountResult,\n type SignMessageResult,\n type SignTransactionResult,\n type SwitchChainResult,\n} from './parentBridgeProtocol';\n\ntype EventName = 'accountsChanged' | 'chainChanged' | 'connect' | 'disconnect' | 'message';\ntype Listener = (...args: unknown[]) => void;\n\ntype PendingRequest<T> = {\n resolve: (value: T) => void;\n reject: (reason: Error) => void;\n expectedKind: ParentMessage['kind'];\n};\n\nexport type ParentBridgeOptions = {\n /**\n * Origin of the parent dapp that hosts this iframe. The provider posts to\n * `window.parent` with this exact origin and rejects inbound messages from\n * any other origin. Pass `'*'` only in development; production must pin to\n * the real parent (`https://cloud.tangle.tools` or its develop equivalent).\n */\n parentOrigin: string;\n /**\n * Stable identifier for this iframe app. The parent includes this in the\n * handshake ack so dev tooling can correlate logs across the two windows.\n */\n appId: string;\n /**\n * Optional ms timeout for each bridged request. Defaults to 60 seconds —\n * long enough for a user to read + approve a signing prompt in the parent.\n */\n requestTimeoutMs?: number;\n};\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000;\n// Connecting is gated on the user interacting with the parent's modal — allow\n// a generous window rather than the standard per-request timeout.\nconst CONNECT_REQUEST_TIMEOUT_MS = 300_000;\n\n/**\n * Detect iframe execution context. When this returns `false` the bridge\n * connector should not be installed and the host app should fall back to its\n * normal wallet config (ConnectKit + injected/walletConnect).\n *\n * `window.parent !== window` is the most reliable signal that works across\n * sandbox-iframe contexts where direct property access to parent throws.\n */\nexport function isRunningInIframe(): boolean {\n if (typeof window === 'undefined') return false;\n try {\n return window.parent !== undefined && window.parent !== window;\n } catch {\n // Cross-origin read of `window.parent` shouldn't throw, but be defensive.\n return true;\n }\n}\n\n/**\n * EIP-1193 provider backed by the Tangle Cloud iframe protocol. One instance\n * lives per iframe app; the wagmi connector owns the singleton.\n */\nexport class ParentBridgeProvider {\n private listeners = new Map<EventName, Set<Listener>>();\n private pending = new Map<string, PendingRequest<unknown>>();\n private cachedAccount: Address | null = null;\n private cachedChainId: number | null = null;\n private handshakeAcked = false;\n private handshakeWaiters: Array<() => void> = [];\n private installed = false;\n\n constructor(private readonly options: ParentBridgeOptions) {}\n\n /**\n * Wire up the global message listener and send the initial handshake.\n * Idempotent — safe to call repeatedly during reconnect attempts.\n */\n install(): void {\n if (this.installed || typeof window === 'undefined') return;\n this.installed = true;\n window.addEventListener('message', this.handleParentMessage);\n this.postToParent({\n kind: 'tangle.app.handshake',\n appId: this.options.appId,\n version: TANGLE_IFRAME_PROTOCOL_VERSION,\n });\n }\n\n uninstall(): void {\n if (!this.installed || typeof window === 'undefined') return;\n this.installed = false;\n window.removeEventListener('message', this.handleParentMessage);\n // Reject every pending request so callers don't hang forever.\n for (const [, pending] of this.pending) {\n pending.reject(new Error('Parent bridge uninstalled'));\n }\n this.pending.clear();\n }\n\n // ── EIP-1193 surface ────────────────────────────────────────────────────\n\n async request(req: { method: string; params?: unknown[] }): Promise<unknown> {\n const method = req.method;\n const params = (req.params ?? []) as unknown[];\n switch (method) {\n case 'eth_chainId': {\n await this.ensureBootstrapped();\n return this.cachedChainId !== null ? `0x${this.cachedChainId.toString(16)}` : '0x0';\n }\n case 'eth_accounts': {\n // Passive read — never opens a modal.\n await this.ensureBootstrapped();\n return this.cachedAccount !== null ? [this.cachedAccount] : [];\n }\n case 'eth_requestAccounts': {\n // Active connect (the wallet \"Connect\" button). If the parent has no\n // wallet yet, delegate to it to open its connect modal and wait.\n await this.ensureBootstrapped();\n if (this.cachedAccount !== null) return [this.cachedAccount];\n const account = await this.requestConnect();\n return account !== null ? [account] : [];\n }\n case 'personal_sign': {\n const [message, _signer] = params as [string, Address];\n return this.requestSignMessage(message);\n }\n case 'eth_signTypedData_v4': {\n // The current protocol doesn't carry typed-data — surface a clear\n // error rather than silently producing a personal_sign. Publishers\n // that need typed-data signing should upgrade the protocol.\n throw bridgeError(\n 4200,\n 'eth_signTypedData_v4 is not supported by the parent-bridge protocol yet.',\n );\n }\n case 'eth_sendTransaction': {\n const [tx] = params as [\n { to?: Address; data?: Hex; value?: Hex | string; chainId?: Hex | number },\n ];\n if (!tx?.to || !tx.data) {\n throw bridgeError(-32602, 'eth_sendTransaction requires `to` and `data`.');\n }\n return this.requestSignTransaction(tx);\n }\n case 'wallet_switchEthereumChain': {\n const [{ chainId }] = params as [{ chainId: Hex }];\n const numeric = Number.parseInt(chainId, 16);\n if (!Number.isFinite(numeric) || numeric <= 0) {\n throw bridgeError(-32602, `Invalid chainId: ${chainId}`);\n }\n await this.requestSwitchChain(numeric);\n return null;\n }\n case 'wallet_addEthereumChain': {\n // The parent owns the chain registry; iframes can't add chains the\n // dapp doesn't already know about.\n throw bridgeError(\n 4200,\n 'wallet_addEthereumChain is not supported through the parent bridge.',\n );\n }\n default:\n throw bridgeError(4200, `Method ${method} not supported by parent bridge.`);\n }\n }\n\n on(event: EventName, listener: Listener): void {\n const set = this.listeners.get(event) ?? new Set();\n set.add(listener);\n this.listeners.set(event, set);\n }\n\n removeListener(event: EventName, listener: Listener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n // ── Internal: dispatch + book-keeping ───────────────────────────────────\n\n private postToParent(message: object): void {\n if (typeof window === 'undefined') return;\n try {\n window.parent.postMessage(message, this.options.parentOrigin);\n } catch {\n // Cross-origin / sandboxed; parent.postMessage shouldn't actually throw\n // but be defensive against future browser changes.\n }\n }\n\n private handleParentMessage = (event: MessageEvent): void => {\n // Origin gate first; never parse untrusted payloads.\n if (event.origin !== this.options.parentOrigin) return;\n const data = event.data;\n if (typeof data !== 'object' || data === null) return;\n const message = data as ParentMessage;\n switch (message.kind) {\n case 'tangle.app.handshakeAck':\n this.handshakeAcked = true;\n for (const resolve of this.handshakeWaiters) resolve();\n this.handshakeWaiters = [];\n // After ack, ask for the current account so cached state reflects\n // reality before any consumer queries. Fire-and-forget — explicit\n // calls (`eth_accounts`, etc.) await their own request.\n this.sendReadAccount().catch(() => {\n // The first read commonly races with bridge teardown in tests\n // and isn't user-facing; swallow rather than producing unhandled\n // rejections. Subsequent `eth_accounts` calls retry on demand.\n });\n return;\n case 'tangle.app.readAccountResult':\n case 'tangle.app.connectResult':\n this.resolvePending(message);\n if (message.ok) {\n this.updateAccount(\n message.data.account === NO_WALLET_ADDRESS\n ? null\n : message.data.account,\n );\n this.updateChainId(message.data.chainId);\n }\n return;\n case 'tangle.app.switchChainResult':\n this.resolvePending(message);\n if (message.ok) this.updateChainId(message.data.chainId);\n return;\n case 'tangle.app.signMessageResult':\n case 'tangle.app.signTransactionResult':\n this.resolvePending(message);\n return;\n case 'tangle.app.accountChanged':\n this.updateAccount(message.account);\n return;\n case 'tangle.app.chainChanged':\n this.updateChainId(message.chainId);\n return;\n }\n };\n\n private sendReadAccount(): Promise<{ account: Address; chainId: number }> {\n return this.dispatch({\n kind: 'tangle.app.readAccount',\n expectedKind: 'tangle.app.readAccountResult',\n }) as Promise<{ account: Address; chainId: number }>;\n }\n\n /**\n * Ask the parent to connect a wallet (opening its modal if needed) and wait\n * for the result. Long timeout — the user is interacting with the modal.\n */\n private requestConnect(): Promise<Address | null> {\n return this.dispatch({\n kind: 'tangle.app.requestConnect',\n expectedKind: 'tangle.app.connectResult',\n timeoutMs: CONNECT_REQUEST_TIMEOUT_MS,\n }).then((data) => {\n const { account } = data as { account: Address; chainId: number };\n return account === NO_WALLET_ADDRESS ? null : account;\n });\n }\n\n private requestSignMessage(message: string): Promise<Hex> {\n const chainId = this.cachedChainId ?? 1;\n return this.dispatch({\n kind: 'tangle.app.signMessage',\n expectedKind: 'tangle.app.signMessageResult',\n payload: { chainId, message },\n }).then((data) => (data as { signature: Hex }).signature);\n }\n\n private requestSignTransaction(tx: {\n to?: Address;\n data?: Hex;\n value?: Hex | string;\n }): Promise<Hex> {\n const chainId = this.cachedChainId ?? 1;\n const value =\n typeof tx.value === 'string' && tx.value.startsWith('0x')\n ? BigInt(tx.value).toString(10)\n : typeof tx.value === 'string'\n ? tx.value\n : undefined;\n return this.dispatch({\n kind: 'tangle.app.signTransaction',\n expectedKind: 'tangle.app.signTransactionResult',\n payload: {\n chainId,\n to: tx.to as Address,\n data: tx.data as Hex,\n ...(value !== undefined ? { value } : {}),\n },\n }).then((data) => (data as { txHash: Hex }).txHash);\n }\n\n private requestSwitchChain(chainId: number): Promise<number> {\n return this.dispatch({\n kind: 'tangle.app.switchChain',\n expectedKind: 'tangle.app.switchChainResult',\n payload: { chainId },\n }).then((data) => (data as { chainId: number }).chainId);\n }\n\n private async dispatch(req: {\n kind:\n | 'tangle.app.readAccount'\n | 'tangle.app.switchChain'\n | 'tangle.app.signMessage'\n | 'tangle.app.signTransaction'\n | 'tangle.app.requestConnect';\n expectedKind: ParentMessage['kind'];\n payload?: Record<string, unknown>;\n timeoutMs?: number;\n }): Promise<unknown> {\n await this.ensureBootstrapped();\n const correlationId = makeCorrelationId(req.kind);\n const timeout = req.timeoutMs ?? this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n return new Promise<unknown>((resolve, reject) => {\n const timer = window.setTimeout(() => {\n this.pending.delete(correlationId);\n reject(bridgeError(4900, `Parent did not respond to ${req.kind} within ${timeout}ms`));\n }, timeout);\n this.pending.set(correlationId, {\n resolve: (v) => {\n window.clearTimeout(timer);\n resolve(v);\n },\n reject: (e) => {\n window.clearTimeout(timer);\n reject(e);\n },\n expectedKind: req.expectedKind,\n });\n this.postToParent({\n kind: req.kind,\n correlationId,\n ...(req.payload ?? {}),\n });\n });\n }\n\n /**\n * Resolves wallet-shape responses (`{ ok, data | error }`). Job results\n * use a different envelope (`{ status, data?, chunk?, error? }`) and are\n * routed through a separate listener registered by `useCallJob` / the SDK\n * — the provider doesn't double-handle them.\n */\n private resolvePending(\n message:\n | ReadAccountResult\n | ConnectResult\n | SwitchChainResult\n | SignMessageResult\n | SignTransactionResult,\n ): void {\n const entry = this.pending.get(message.correlationId);\n if (!entry) return;\n this.pending.delete(message.correlationId);\n if (entry.expectedKind !== message.kind) {\n entry.reject(\n bridgeError(\n -32000,\n `Parent replied with ${message.kind} but ${entry.expectedKind} was expected`,\n ),\n );\n return;\n }\n if (message.ok) {\n entry.resolve(message.data);\n } else {\n entry.reject(bridgeError(4001, message.error));\n }\n }\n\n private async ensureBootstrapped(): Promise<void> {\n if (this.handshakeAcked) return;\n this.install();\n await new Promise<void>((resolve) => {\n this.handshakeWaiters.push(resolve);\n // Re-send handshake every 500ms while we wait — covers a parent that\n // mounted after the iframe and missed the initial post.\n const retry = window.setInterval(() => {\n if (this.handshakeAcked) {\n window.clearInterval(retry);\n return;\n }\n this.postToParent({\n kind: 'tangle.app.handshake',\n appId: this.options.appId,\n version: TANGLE_IFRAME_PROTOCOL_VERSION,\n });\n }, 500);\n // Safety stop — handshake won't be re-attempted indefinitely.\n window.setTimeout(() => window.clearInterval(retry), 10_000);\n });\n }\n\n private updateAccount(next: Address | null): void {\n if (this.cachedAccount === next) return;\n const prev = this.cachedAccount;\n this.cachedAccount = next;\n if (next === null && prev !== null) {\n this.emit('disconnect');\n this.emit('accountsChanged', []);\n } else if (next !== null) {\n this.emit('accountsChanged', [next]);\n if (prev === null) {\n this.emit('connect', { chainId: this.cachedChainId ?? 0 });\n }\n }\n }\n\n private updateChainId(next: number): void {\n if (this.cachedChainId === next) return;\n this.cachedChainId = next;\n this.emit('chainChanged', `0x${next.toString(16)}`);\n }\n\n private emit(event: EventName, ...args: unknown[]): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const listener of [...set]) {\n try {\n listener(...args);\n } catch {\n // Listener bugs shouldn't break the bridge.\n }\n }\n }\n\n // ── Test seams ──────────────────────────────────────────────────────────\n\n /** Visible for tests + the connector's `getAccounts()` shortcut. */\n getCachedAccount(): Address | null {\n return this.cachedAccount;\n }\n /** Visible for tests + the connector's `getChainId()` shortcut. */\n getCachedChainId(): number | null {\n return this.cachedChainId;\n }\n}\n\nfunction bridgeError(code: number, message: string): Error {\n const err = new Error(message) as Error & { code?: number };\n err.code = code;\n return err;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/wallet/parentBridgeConnector.ts","../../src/wallet/parentBridgeProvider.ts","../../src/wallet/tangleConnectors.ts"],"sourcesContent":["// Wagmi connector that proxies wallet operations to the Tangle Cloud parent\n// dapp via the iframe postMessage bridge. Becomes the autoConnect target\n// when this app is loaded inside an iframe sandbox without a window.ethereum\n// — i.e. always, when embedded by cloud.tangle.tools.\n//\n// Architecture: the connector owns one `ParentBridgeProvider` (singleton),\n// forwards every wagmi method to it, and reflects the provider's EIP-1193\n// events back to wagmi's emitter so the rest of the dapp (ConnectKit's\n// account chip, hooks like useAccount/useChainId) reacts to parent-state\n// changes without polling.\n\nimport type { Address, Chain } from 'viem';\nimport { createConnector } from 'wagmi';\n\nimport { ParentBridgeProvider, type ParentBridgeOptions } from './parentBridgeProvider';\n\nexport type ParentBridgeConnectorOptions = ParentBridgeOptions;\n\nexport function parentBridgeConnector(options: ParentBridgeConnectorOptions) {\n let provider: ParentBridgeProvider | undefined;\n let installed = false;\n\n return createConnector<ParentBridgeProvider>((config) => {\n const ensureProvider = (): ParentBridgeProvider => {\n if (!provider) provider = new ParentBridgeProvider(options);\n if (!installed) {\n provider.install();\n installed = true;\n // Wire the provider's EIP-1193 events to wagmi's emitter so\n // ConnectKit and useAccount/useChainId reflect parent-state changes\n // without polling.\n provider.on('accountsChanged', (accounts) => {\n config.emitter.emit('change', {\n accounts: Array.isArray(accounts)\n ? (accounts as readonly Address[])\n : ([] as readonly Address[]),\n });\n });\n provider.on('chainChanged', (chainIdHex) => {\n const chainId =\n typeof chainIdHex === 'string'\n ? Number.parseInt(chainIdHex, 16)\n : Number(chainIdHex);\n if (Number.isFinite(chainId)) {\n config.emitter.emit('change', { chainId });\n }\n });\n provider.on('disconnect', () => {\n config.emitter.emit('disconnect');\n });\n }\n return provider;\n };\n\n return {\n id: 'tangleParentBridge',\n name: 'Tangle Cloud',\n type: 'parentBridge',\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async connect(): Promise<any> {\n // wagmi v3's connect() return type is a conditional based on\n // `withCapabilities`. We always return plain addresses; cast through\n // `any` rather than re-implementing the type predicate.\n const p = ensureProvider();\n const accountsResult = (await p.request({\n method: 'eth_requestAccounts',\n })) as readonly Address[];\n const chainIdHex = (await p.request({ method: 'eth_chainId' })) as string;\n const chainId = Number.parseInt(chainIdHex, 16);\n return {\n accounts: accountsResult,\n chainId: Number.isFinite(chainId) ? chainId : 0,\n };\n },\n\n async disconnect() {\n // Disconnect from the iframe's perspective is a local-only state\n // reset — we can't ask the parent dapp to disconnect its wallet on\n // our behalf, and a real disconnect should be initiated from the\n // parent's UI. Tear down listeners + the message bridge so a future\n // reconnect re-handshakes cleanly.\n if (provider) provider.uninstall();\n installed = false;\n provider = undefined;\n },\n\n async getAccounts() {\n const p = ensureProvider();\n const cached = p.getCachedAccount();\n if (cached) return [cached];\n const accounts = (await p.request({\n method: 'eth_accounts',\n })) as readonly Address[];\n return accounts;\n },\n\n async getChainId() {\n const p = ensureProvider();\n const cached = p.getCachedChainId();\n if (cached !== null) return cached;\n const chainIdHex = (await p.request({ method: 'eth_chainId' })) as string;\n const chainId = Number.parseInt(chainIdHex, 16);\n return Number.isFinite(chainId) ? chainId : 0;\n },\n\n async getProvider() {\n return ensureProvider();\n },\n\n async isAuthorized() {\n // Always authorized when in iframe mode — the parent dapp has\n // already gated access by being the embedder. Returning `true`\n // makes wagmi auto-reconnect on every page load, which is the\n // right UX (iframe → parent wallet is always-on).\n try {\n const p = ensureProvider();\n const accounts = (await p.request({\n method: 'eth_accounts',\n })) as readonly Address[];\n return accounts.length > 0;\n } catch {\n return false;\n }\n },\n\n async switchChain({ chainId }): Promise<Chain> {\n const p = ensureProvider();\n await p.request({\n method: 'wallet_switchEthereumChain',\n params: [{ chainId: `0x${chainId.toString(16)}` }],\n });\n const chain = config.chains.find((c) => c.id === chainId);\n if (!chain) {\n throw new Error(`Chain ${chainId} not configured for this app`);\n }\n return chain;\n },\n\n onAccountsChanged(accounts) {\n config.emitter.emit('change', {\n accounts: accounts as readonly Address[],\n });\n },\n onChainChanged(chainIdHex) {\n const chainId = Number.parseInt(chainIdHex, 16);\n if (Number.isFinite(chainId)) {\n config.emitter.emit('change', { chainId });\n }\n },\n onDisconnect() {\n config.emitter.emit('disconnect');\n },\n };\n });\n}\n","// EIP-1193 provider implementation that proxies wallet calls to the parent\n// dapp via window.postMessage. The iframe doesn't talk to a wallet directly\n// — it inherits the parent's connected account + chain, and forwards signing\n// requests through the existing tangle.app.* protocol.\n//\n// This is the lowest layer of the parent-bridge stack. Wagmi sees this as a\n// regular Ethereum provider and routes `eth_accounts`, `eth_chainId`,\n// `personal_sign`, `eth_sendTransaction`, `wallet_switchEthereumChain`, etc.\n// through it.\n\nimport type { Address, Hex } from 'viem';\n\nimport {\n makeCorrelationId,\n NO_WALLET_ADDRESS,\n TANGLE_IFRAME_PROTOCOL_VERSION,\n type ConnectResult,\n type ParentMessage,\n type ReadAccountResult,\n type SignMessageResult,\n type SignTransactionResult,\n type SwitchChainResult,\n} from './parentBridgeProtocol';\n\ntype EventName = 'accountsChanged' | 'chainChanged' | 'connect' | 'disconnect' | 'message';\ntype Listener = (...args: unknown[]) => void;\n\ntype PendingRequest<T> = {\n resolve: (value: T) => void;\n reject: (reason: Error) => void;\n expectedKind: ParentMessage['kind'];\n};\n\nexport type ParentBridgeOptions = {\n /**\n * Origin of the parent dapp that hosts this iframe. The provider posts to\n * `window.parent` with this exact origin and rejects inbound messages from\n * any other origin. Pass `'*'` only in development; production must pin to\n * the real parent (`https://cloud.tangle.tools` or its develop equivalent).\n */\n parentOrigin: string;\n /**\n * Stable identifier for this iframe app. The parent includes this in the\n * handshake ack so dev tooling can correlate logs across the two windows.\n */\n appId: string;\n /**\n * Optional ms timeout for each bridged request. Defaults to 60 seconds —\n * long enough for a user to read + approve a signing prompt in the parent.\n */\n requestTimeoutMs?: number;\n};\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000;\n// Connecting is gated on the user interacting with the parent's modal — allow\n// a generous window rather than the standard per-request timeout.\nconst CONNECT_REQUEST_TIMEOUT_MS = 300_000;\n\n/**\n * Detect iframe execution context. When this returns `false` the bridge\n * connector should not be installed and the host app should fall back to its\n * normal wallet config (ConnectKit + injected/walletConnect).\n *\n * `window.parent !== window` is the most reliable signal that works across\n * sandbox-iframe contexts where direct property access to parent throws.\n */\nexport function isRunningInIframe(): boolean {\n if (typeof window === 'undefined') return false;\n try {\n return window.parent !== undefined && window.parent !== window;\n } catch {\n // Cross-origin read of `window.parent` shouldn't throw, but be defensive.\n return true;\n }\n}\n\n/**\n * EIP-1193 provider backed by the Tangle Cloud iframe protocol. One instance\n * lives per iframe app; the wagmi connector owns the singleton.\n */\nexport class ParentBridgeProvider {\n private listeners = new Map<EventName, Set<Listener>>();\n private pending = new Map<string, PendingRequest<unknown>>();\n private cachedAccount: Address | null = null;\n private cachedChainId: number | null = null;\n private handshakeAcked = false;\n private handshakeWaiters: Array<() => void> = [];\n private installed = false;\n\n constructor(private readonly options: ParentBridgeOptions) {}\n\n /**\n * Wire up the global message listener and send the initial handshake.\n * Idempotent — safe to call repeatedly during reconnect attempts.\n */\n install(): void {\n if (this.installed || typeof window === 'undefined') return;\n this.installed = true;\n window.addEventListener('message', this.handleParentMessage);\n this.postToParent({\n kind: 'tangle.app.handshake',\n appId: this.options.appId,\n version: TANGLE_IFRAME_PROTOCOL_VERSION,\n });\n }\n\n uninstall(): void {\n if (!this.installed || typeof window === 'undefined') return;\n this.installed = false;\n window.removeEventListener('message', this.handleParentMessage);\n // Reject every pending request so callers don't hang forever.\n for (const [, pending] of this.pending) {\n pending.reject(new Error('Parent bridge uninstalled'));\n }\n this.pending.clear();\n }\n\n // ── EIP-1193 surface ────────────────────────────────────────────────────\n\n async request(req: { method: string; params?: unknown[] }): Promise<unknown> {\n const method = req.method;\n const params = (req.params ?? []) as unknown[];\n switch (method) {\n case 'eth_chainId': {\n await this.ensureBootstrapped();\n return this.cachedChainId !== null ? `0x${this.cachedChainId.toString(16)}` : '0x0';\n }\n case 'eth_accounts': {\n // Passive read — never opens a modal.\n await this.ensureBootstrapped();\n return this.cachedAccount !== null ? [this.cachedAccount] : [];\n }\n case 'eth_requestAccounts': {\n // Active connect (the wallet \"Connect\" button). If the parent has no\n // wallet yet, delegate to it to open its connect modal and wait.\n await this.ensureBootstrapped();\n if (this.cachedAccount !== null) return [this.cachedAccount];\n const account = await this.requestConnect();\n return account !== null ? [account] : [];\n }\n case 'personal_sign': {\n const [message, _signer] = params as [string, Address];\n return this.requestSignMessage(message);\n }\n case 'eth_signTypedData_v4': {\n // The current protocol doesn't carry typed-data — surface a clear\n // error rather than silently producing a personal_sign. Publishers\n // that need typed-data signing should upgrade the protocol.\n throw bridgeError(\n 4200,\n 'eth_signTypedData_v4 is not supported by the parent-bridge protocol yet.',\n );\n }\n case 'eth_sendTransaction': {\n const [tx] = params as [\n { to?: Address; data?: Hex; value?: Hex | string; chainId?: Hex | number },\n ];\n if (!tx?.to || !tx.data) {\n throw bridgeError(-32602, 'eth_sendTransaction requires `to` and `data`.');\n }\n return this.requestSignTransaction(tx);\n }\n case 'wallet_switchEthereumChain': {\n const [{ chainId }] = params as [{ chainId: Hex }];\n const numeric = Number.parseInt(chainId, 16);\n if (!Number.isFinite(numeric) || numeric <= 0) {\n throw bridgeError(-32602, `Invalid chainId: ${chainId}`);\n }\n await this.requestSwitchChain(numeric);\n return null;\n }\n case 'wallet_addEthereumChain': {\n // The parent owns the chain registry; iframes can't add chains the\n // dapp doesn't already know about.\n throw bridgeError(\n 4200,\n 'wallet_addEthereumChain is not supported through the parent bridge.',\n );\n }\n default:\n throw bridgeError(4200, `Method ${method} not supported by parent bridge.`);\n }\n }\n\n on(event: EventName, listener: Listener): void {\n const set = this.listeners.get(event) ?? new Set();\n set.add(listener);\n this.listeners.set(event, set);\n }\n\n removeListener(event: EventName, listener: Listener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n // ── Internal: dispatch + book-keeping ───────────────────────────────────\n\n private postToParent(message: object): void {\n if (typeof window === 'undefined') return;\n try {\n window.parent.postMessage(message, this.options.parentOrigin);\n } catch {\n // Cross-origin / sandboxed; parent.postMessage shouldn't actually throw\n // but be defensive against future browser changes.\n }\n }\n\n private handleParentMessage = (event: MessageEvent): void => {\n // Origin gate first; never parse untrusted payloads.\n if (event.origin !== this.options.parentOrigin) return;\n const data = event.data;\n if (typeof data !== 'object' || data === null) return;\n const message = data as ParentMessage;\n switch (message.kind) {\n case 'tangle.app.handshakeAck':\n this.handshakeAcked = true;\n for (const resolve of this.handshakeWaiters) resolve();\n this.handshakeWaiters = [];\n // After ack, ask for the current account so cached state reflects\n // reality before any consumer queries. Fire-and-forget — explicit\n // calls (`eth_accounts`, etc.) await their own request.\n this.sendReadAccount().catch(() => {\n // The first read commonly races with bridge teardown in tests\n // and isn't user-facing; swallow rather than producing unhandled\n // rejections. Subsequent `eth_accounts` calls retry on demand.\n });\n return;\n case 'tangle.app.readAccountResult':\n case 'tangle.app.connectResult':\n this.resolvePending(message);\n if (message.ok) {\n this.updateAccount(\n message.data.account === NO_WALLET_ADDRESS\n ? null\n : message.data.account,\n );\n this.updateChainId(message.data.chainId);\n }\n return;\n case 'tangle.app.switchChainResult':\n this.resolvePending(message);\n if (message.ok) this.updateChainId(message.data.chainId);\n return;\n case 'tangle.app.signMessageResult':\n case 'tangle.app.signTransactionResult':\n this.resolvePending(message);\n return;\n case 'tangle.app.accountChanged':\n this.updateAccount(message.account);\n return;\n case 'tangle.app.chainChanged':\n this.updateChainId(message.chainId);\n return;\n }\n };\n\n private sendReadAccount(): Promise<{ account: Address; chainId: number }> {\n return this.dispatch({\n kind: 'tangle.app.readAccount',\n expectedKind: 'tangle.app.readAccountResult',\n }) as Promise<{ account: Address; chainId: number }>;\n }\n\n /**\n * Ask the parent to connect a wallet (opening its modal if needed) and wait\n * for the result. Long timeout — the user is interacting with the modal.\n */\n private requestConnect(): Promise<Address | null> {\n return this.dispatch({\n kind: 'tangle.app.requestConnect',\n expectedKind: 'tangle.app.connectResult',\n timeoutMs: CONNECT_REQUEST_TIMEOUT_MS,\n }).then((data) => {\n const { account } = data as { account: Address; chainId: number };\n return account === NO_WALLET_ADDRESS ? null : account;\n });\n }\n\n private requestSignMessage(message: string): Promise<Hex> {\n const chainId = this.cachedChainId ?? 1;\n return this.dispatch({\n kind: 'tangle.app.signMessage',\n expectedKind: 'tangle.app.signMessageResult',\n payload: { chainId, message },\n }).then((data) => (data as { signature: Hex }).signature);\n }\n\n private requestSignTransaction(tx: {\n to?: Address;\n data?: Hex;\n value?: Hex | string;\n }): Promise<Hex> {\n const chainId = this.cachedChainId ?? 1;\n const value =\n typeof tx.value === 'string' && tx.value.startsWith('0x')\n ? BigInt(tx.value).toString(10)\n : typeof tx.value === 'string'\n ? tx.value\n : undefined;\n return this.dispatch({\n kind: 'tangle.app.signTransaction',\n expectedKind: 'tangle.app.signTransactionResult',\n payload: {\n chainId,\n to: tx.to as Address,\n data: tx.data as Hex,\n ...(value !== undefined ? { value } : {}),\n },\n }).then((data) => (data as { txHash: Hex }).txHash);\n }\n\n private requestSwitchChain(chainId: number): Promise<number> {\n return this.dispatch({\n kind: 'tangle.app.switchChain',\n expectedKind: 'tangle.app.switchChainResult',\n payload: { chainId },\n }).then((data) => (data as { chainId: number }).chainId);\n }\n\n private async dispatch(req: {\n kind:\n | 'tangle.app.readAccount'\n | 'tangle.app.switchChain'\n | 'tangle.app.signMessage'\n | 'tangle.app.signTransaction'\n | 'tangle.app.requestConnect';\n expectedKind: ParentMessage['kind'];\n payload?: Record<string, unknown>;\n timeoutMs?: number;\n }): Promise<unknown> {\n await this.ensureBootstrapped();\n const correlationId = makeCorrelationId(req.kind);\n const timeout = req.timeoutMs ?? this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n return new Promise<unknown>((resolve, reject) => {\n const timer = window.setTimeout(() => {\n this.pending.delete(correlationId);\n reject(bridgeError(4900, `Parent did not respond to ${req.kind} within ${timeout}ms`));\n }, timeout);\n this.pending.set(correlationId, {\n resolve: (v) => {\n window.clearTimeout(timer);\n resolve(v);\n },\n reject: (e) => {\n window.clearTimeout(timer);\n reject(e);\n },\n expectedKind: req.expectedKind,\n });\n this.postToParent({\n kind: req.kind,\n correlationId,\n ...(req.payload ?? {}),\n });\n });\n }\n\n /**\n * Resolves wallet-shape responses (`{ ok, data | error }`). Job results\n * use a different envelope (`{ status, data?, chunk?, error? }`) and are\n * routed through a separate listener registered by `useCallJob` / the SDK\n * — the provider doesn't double-handle them.\n */\n private resolvePending(\n message:\n | ReadAccountResult\n | ConnectResult\n | SwitchChainResult\n | SignMessageResult\n | SignTransactionResult,\n ): void {\n const entry = this.pending.get(message.correlationId);\n if (!entry) return;\n this.pending.delete(message.correlationId);\n if (entry.expectedKind !== message.kind) {\n entry.reject(\n bridgeError(\n -32000,\n `Parent replied with ${message.kind} but ${entry.expectedKind} was expected`,\n ),\n );\n return;\n }\n if (message.ok) {\n entry.resolve(message.data);\n } else {\n entry.reject(bridgeError(4001, message.error));\n }\n }\n\n private async ensureBootstrapped(): Promise<void> {\n if (this.handshakeAcked) return;\n this.install();\n await new Promise<void>((resolve) => {\n this.handshakeWaiters.push(resolve);\n // Re-send handshake every 500ms while we wait — covers a parent that\n // mounted after the iframe and missed the initial post.\n const retry = window.setInterval(() => {\n if (this.handshakeAcked) {\n window.clearInterval(retry);\n return;\n }\n this.postToParent({\n kind: 'tangle.app.handshake',\n appId: this.options.appId,\n version: TANGLE_IFRAME_PROTOCOL_VERSION,\n });\n }, 500);\n // Safety stop — handshake won't be re-attempted indefinitely.\n window.setTimeout(() => window.clearInterval(retry), 10_000);\n });\n }\n\n private updateAccount(next: Address | null): void {\n if (this.cachedAccount === next) return;\n const prev = this.cachedAccount;\n this.cachedAccount = next;\n if (next === null && prev !== null) {\n this.emit('disconnect');\n this.emit('accountsChanged', []);\n } else if (next !== null) {\n this.emit('accountsChanged', [next]);\n if (prev === null) {\n this.emit('connect', { chainId: this.cachedChainId ?? 0 });\n }\n }\n }\n\n private updateChainId(next: number): void {\n if (this.cachedChainId === next) return;\n this.cachedChainId = next;\n this.emit('chainChanged', `0x${next.toString(16)}`);\n }\n\n private emit(event: EventName, ...args: unknown[]): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const listener of [...set]) {\n try {\n listener(...args);\n } catch {\n // Listener bugs shouldn't break the bridge.\n }\n }\n }\n\n // ── Test seams ──────────────────────────────────────────────────────────\n\n /** Visible for tests + the connector's `getAccounts()` shortcut. */\n getCachedAccount(): Address | null {\n return this.cachedAccount;\n }\n /** Visible for tests + the connector's `getChainId()` shortcut. */\n getCachedChainId(): number | null {\n return this.cachedChainId;\n }\n}\n\nfunction bridgeError(code: number, message: string): Error {\n const err = new Error(message) as Error & { code?: number };\n err.code = code;\n return err;\n}\n","import type { CreateConnectorFn } from 'wagmi';\n\nimport { detectTangleCloudParentOrigin } from './detectParentOrigin';\nimport { parentBridgeConnector } from './parentBridgeConnector';\n\nexport interface TangleBlueprintConnectorsOptions {\n /** App id reported to the parent dapp on handshake (when embedded). */\n appId: string;\n /**\n * Connectors used when running STANDALONE (the app's own domain) — e.g.\n * `[injected(), walletConnect({ projectId })]`. Ignored when embedded.\n */\n standalone: CreateConnectorFn[];\n /** Extra trusted parent origins (staging / preview deploys). */\n extraOrigins?: readonly string[];\n /** Override the bridged-request timeout (ms). */\n requestTimeoutMs?: number;\n}\n\n/**\n * One connector list, two deployment modes — so a blueprint app can ship a\n * single build that runs both standalone and embedded in Tangle Cloud:\n *\n * - **Embedded** (a trusted Tangle Cloud parent is detected): the\n * parent-bridge connector is the *only* connector. The sandboxed iframe\n * can't inject a wallet extension, so it inherits / drives the parent's\n * wallet over the postMessage bridge — surfacing injected/WalletConnect\n * here would just dead-end.\n * - **Standalone** (no trusted parent): the app's own `standalone`\n * connectors, exactly as a normal dapp.\n *\n * The choice is made at runtime from the embedding context, so the same\n * artifact works in both places with no build flags.\n *\n * createConfig({\n * chains,\n * transports,\n * connectors: tangleBlueprintConnectors({\n * appId: 'trading-arena',\n * standalone: [injected(), walletConnect({ projectId })],\n * }),\n * })\n */\nexport function tangleBlueprintConnectors(\n options: TangleBlueprintConnectorsOptions,\n): CreateConnectorFn[] {\n const parentOrigin = detectTangleCloudParentOrigin({\n extraOrigins: options.extraOrigins,\n });\n if (parentOrigin === null) {\n return options.standalone;\n }\n return [\n parentBridgeConnector({\n parentOrigin,\n appId: options.appId,\n ...(options.requestTimeoutMs !== undefined\n ? { requestTimeoutMs: options.requestTimeoutMs }\n : {}),\n }),\n ];\n}\n"],"mappings":";;;;;;;;;;AAYA,SAAS,uBAAuB;;;ACyChC,IAAM,6BAA6B;AAGnC,IAAM,6BAA6B;AAU5B,SAAS,oBAA6B;AAC3C,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI;AACF,WAAO,OAAO,WAAW,UAAa,OAAO,WAAW;AAAA,EAC1D,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAMO,IAAM,uBAAN,MAA2B;AAAA,EAShC,YAA6B,SAA8B;AAA9B;AAAA,EAA+B;AAAA,EAA/B;AAAA,EARrB,YAAY,oBAAI,IAA8B;AAAA,EAC9C,UAAU,oBAAI,IAAqC;AAAA,EACnD,gBAAgC;AAAA,EAChC,gBAA+B;AAAA,EAC/B,iBAAiB;AAAA,EACjB,mBAAsC,CAAC;AAAA,EACvC,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpB,UAAgB;AACd,QAAI,KAAK,aAAa,OAAO,WAAW,YAAa;AACrD,SAAK,YAAY;AACjB,WAAO,iBAAiB,WAAW,KAAK,mBAAmB;AAC3D,SAAK,aAAa;AAAA,MAChB,MAAM;AAAA,MACN,OAAO,KAAK,QAAQ;AAAA,MACpB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,YAAkB;AAChB,QAAI,CAAC,KAAK,aAAa,OAAO,WAAW,YAAa;AACtD,SAAK,YAAY;AACjB,WAAO,oBAAoB,WAAW,KAAK,mBAAmB;AAE9D,eAAW,CAAC,EAAE,OAAO,KAAK,KAAK,SAAS;AACtC,cAAQ,OAAO,IAAI,MAAM,2BAA2B,CAAC;AAAA,IACvD;AACA,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA,EAIA,MAAM,QAAQ,KAA+D;AAC3E,UAAM,SAAS,IAAI;AACnB,UAAM,SAAU,IAAI,UAAU,CAAC;AAC/B,YAAQ,QAAQ;AAAA,MACd,KAAK,eAAe;AAClB,cAAM,KAAK,mBAAmB;AAC9B,eAAO,KAAK,kBAAkB,OAAO,KAAK,KAAK,cAAc,SAAS,EAAE,CAAC,KAAK;AAAA,MAChF;AAAA,MACA,KAAK,gBAAgB;AAEnB,cAAM,KAAK,mBAAmB;AAC9B,eAAO,KAAK,kBAAkB,OAAO,CAAC,KAAK,aAAa,IAAI,CAAC;AAAA,MAC/D;AAAA,MACA,KAAK,uBAAuB;AAG1B,cAAM,KAAK,mBAAmB;AAC9B,YAAI,KAAK,kBAAkB,KAAM,QAAO,CAAC,KAAK,aAAa;AAC3D,cAAM,UAAU,MAAM,KAAK,eAAe;AAC1C,eAAO,YAAY,OAAO,CAAC,OAAO,IAAI,CAAC;AAAA,MACzC;AAAA,MACA,KAAK,iBAAiB;AACpB,cAAM,CAAC,SAAS,OAAO,IAAI;AAC3B,eAAO,KAAK,mBAAmB,OAAO;AAAA,MACxC;AAAA,MACA,KAAK,wBAAwB;AAI3B,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA,KAAK,uBAAuB;AAC1B,cAAM,CAAC,EAAE,IAAI;AAGb,YAAI,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM;AACvB,gBAAM,YAAY,QAAQ,+CAA+C;AAAA,QAC3E;AACA,eAAO,KAAK,uBAAuB,EAAE;AAAA,MACvC;AAAA,MACA,KAAK,8BAA8B;AACjC,cAAM,CAAC,EAAE,QAAQ,CAAC,IAAI;AACtB,cAAM,UAAU,OAAO,SAAS,SAAS,EAAE;AAC3C,YAAI,CAAC,OAAO,SAAS,OAAO,KAAK,WAAW,GAAG;AAC7C,gBAAM,YAAY,QAAQ,oBAAoB,OAAO,EAAE;AAAA,QACzD;AACA,cAAM,KAAK,mBAAmB,OAAO;AACrC,eAAO;AAAA,MACT;AAAA,MACA,KAAK,2BAA2B;AAG9B,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA;AACE,cAAM,YAAY,MAAM,UAAU,MAAM,kCAAkC;AAAA,IAC9E;AAAA,EACF;AAAA,EAEA,GAAG,OAAkB,UAA0B;AAC7C,UAAM,MAAM,KAAK,UAAU,IAAI,KAAK,KAAK,oBAAI,IAAI;AACjD,QAAI,IAAI,QAAQ;AAChB,SAAK,UAAU,IAAI,OAAO,GAAG;AAAA,EAC/B;AAAA,EAEA,eAAe,OAAkB,UAA0B;AACzD,SAAK,UAAU,IAAI,KAAK,GAAG,OAAO,QAAQ;AAAA,EAC5C;AAAA;AAAA,EAIQ,aAAa,SAAuB;AAC1C,QAAI,OAAO,WAAW,YAAa;AACnC,QAAI;AACF,aAAO,OAAO,YAAY,SAAS,KAAK,QAAQ,YAAY;AAAA,IAC9D,QAAQ;AAAA,IAGR;AAAA,EACF;AAAA,EAEQ,sBAAsB,CAAC,UAA8B;AAE3D,QAAI,MAAM,WAAW,KAAK,QAAQ,aAAc;AAChD,UAAM,OAAO,MAAM;AACnB,QAAI,OAAO,SAAS,YAAY,SAAS,KAAM;AAC/C,UAAM,UAAU;AAChB,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK;AACH,aAAK,iBAAiB;AACtB,mBAAW,WAAW,KAAK,iBAAkB,SAAQ;AACrD,aAAK,mBAAmB,CAAC;AAIzB,aAAK,gBAAgB,EAAE,MAAM,MAAM;AAAA,QAInC,CAAC;AACD;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,aAAK,eAAe,OAAO;AAC3B,YAAI,QAAQ,IAAI;AACd,eAAK;AAAA,YACH,QAAQ,KAAK,YAAY,oBACrB,OACA,QAAQ,KAAK;AAAA,UACnB;AACA,eAAK,cAAc,QAAQ,KAAK,OAAO;AAAA,QACzC;AACA;AAAA,MACF,KAAK;AACH,aAAK,eAAe,OAAO;AAC3B,YAAI,QAAQ,GAAI,MAAK,cAAc,QAAQ,KAAK,OAAO;AACvD;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,aAAK,eAAe,OAAO;AAC3B;AAAA,MACF,KAAK;AACH,aAAK,cAAc,QAAQ,OAAO;AAClC;AAAA,MACF,KAAK;AACH,aAAK,cAAc,QAAQ,OAAO;AAClC;AAAA,IACJ;AAAA,EACF;AAAA,EAEQ,kBAAkE;AACxE,WAAO,KAAK,SAAS;AAAA,MACnB,MAAM;AAAA,MACN,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAA0C;AAChD,WAAO,KAAK,SAAS;AAAA,MACnB,MAAM;AAAA,MACN,cAAc;AAAA,MACd,WAAW;AAAA,IACb,CAAC,EAAE,KAAK,CAAC,SAAS;AAChB,YAAM,EAAE,QAAQ,IAAI;AACpB,aAAO,YAAY,oBAAoB,OAAO;AAAA,IAChD,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAmB,SAA+B;AACxD,UAAM,UAAU,KAAK,iBAAiB;AACtC,WAAO,KAAK,SAAS;AAAA,MACnB,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS,EAAE,SAAS,QAAQ;AAAA,IAC9B,CAAC,EAAE,KAAK,CAAC,SAAU,KAA4B,SAAS;AAAA,EAC1D;AAAA,EAEQ,uBAAuB,IAId;AACf,UAAM,UAAU,KAAK,iBAAiB;AACtC,UAAM,QACJ,OAAO,GAAG,UAAU,YAAY,GAAG,MAAM,WAAW,IAAI,IACpD,OAAO,GAAG,KAAK,EAAE,SAAS,EAAE,IAC5B,OAAO,GAAG,UAAU,WAClB,GAAG,QACH;AACR,WAAO,KAAK,SAAS;AAAA,MACnB,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS;AAAA,QACP;AAAA,QACA,IAAI,GAAG;AAAA,QACP,MAAM,GAAG;AAAA,QACT,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,MACzC;AAAA,IACF,CAAC,EAAE,KAAK,CAAC,SAAU,KAAyB,MAAM;AAAA,EACpD;AAAA,EAEQ,mBAAmB,SAAkC;AAC3D,WAAO,KAAK,SAAS;AAAA,MACnB,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS,EAAE,QAAQ;AAAA,IACrB,CAAC,EAAE,KAAK,CAAC,SAAU,KAA6B,OAAO;AAAA,EACzD;AAAA,EAEA,MAAc,SAAS,KAUF;AACnB,UAAM,KAAK,mBAAmB;AAC9B,UAAM,gBAAgB,kBAAkB,IAAI,IAAI;AAChD,UAAM,UAAU,IAAI,aAAa,KAAK,QAAQ,oBAAoB;AAClE,WAAO,IAAI,QAAiB,CAAC,SAAS,WAAW;AAC/C,YAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,aAAK,QAAQ,OAAO,aAAa;AACjC,eAAO,YAAY,MAAM,6BAA6B,IAAI,IAAI,WAAW,OAAO,IAAI,CAAC;AAAA,MACvF,GAAG,OAAO;AACV,WAAK,QAAQ,IAAI,eAAe;AAAA,QAC9B,SAAS,CAAC,MAAM;AACd,iBAAO,aAAa,KAAK;AACzB,kBAAQ,CAAC;AAAA,QACX;AAAA,QACA,QAAQ,CAAC,MAAM;AACb,iBAAO,aAAa,KAAK;AACzB,iBAAO,CAAC;AAAA,QACV;AAAA,QACA,cAAc,IAAI;AAAA,MACpB,CAAC;AACD,WAAK,aAAa;AAAA,QAChB,MAAM,IAAI;AAAA,QACV;AAAA,QACA,GAAI,IAAI,WAAW,CAAC;AAAA,MACtB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,eACN,SAMM;AACN,UAAM,QAAQ,KAAK,QAAQ,IAAI,QAAQ,aAAa;AACpD,QAAI,CAAC,MAAO;AACZ,SAAK,QAAQ,OAAO,QAAQ,aAAa;AACzC,QAAI,MAAM,iBAAiB,QAAQ,MAAM;AACvC,YAAM;AAAA,QACJ;AAAA,UACE;AAAA,UACA,uBAAuB,QAAQ,IAAI,QAAQ,MAAM,YAAY;AAAA,QAC/D;AAAA,MACF;AACA;AAAA,IACF;AACA,QAAI,QAAQ,IAAI;AACd,YAAM,QAAQ,QAAQ,IAAI;AAAA,IAC5B,OAAO;AACL,YAAM,OAAO,YAAY,MAAM,QAAQ,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,MAAc,qBAAoC;AAChD,QAAI,KAAK,eAAgB;AACzB,SAAK,QAAQ;AACb,UAAM,IAAI,QAAc,CAAC,YAAY;AACnC,WAAK,iBAAiB,KAAK,OAAO;AAGlC,YAAM,QAAQ,OAAO,YAAY,MAAM;AACrC,YAAI,KAAK,gBAAgB;AACvB,iBAAO,cAAc,KAAK;AAC1B;AAAA,QACF;AACA,aAAK,aAAa;AAAA,UAChB,MAAM;AAAA,UACN,OAAO,KAAK,QAAQ;AAAA,UACpB,SAAS;AAAA,QACX,CAAC;AAAA,MACH,GAAG,GAAG;AAEN,aAAO,WAAW,MAAM,OAAO,cAAc,KAAK,GAAG,GAAM;AAAA,IAC7D,CAAC;AAAA,EACH;AAAA,EAEQ,cAAc,MAA4B;AAChD,QAAI,KAAK,kBAAkB,KAAM;AACjC,UAAM,OAAO,KAAK;AAClB,SAAK,gBAAgB;AACrB,QAAI,SAAS,QAAQ,SAAS,MAAM;AAClC,WAAK,KAAK,YAAY;AACtB,WAAK,KAAK,mBAAmB,CAAC,CAAC;AAAA,IACjC,WAAW,SAAS,MAAM;AACxB,WAAK,KAAK,mBAAmB,CAAC,IAAI,CAAC;AACnC,UAAI,SAAS,MAAM;AACjB,aAAK,KAAK,WAAW,EAAE,SAAS,KAAK,iBAAiB,EAAE,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAc,MAAoB;AACxC,QAAI,KAAK,kBAAkB,KAAM;AACjC,SAAK,gBAAgB;AACrB,SAAK,KAAK,gBAAgB,KAAK,KAAK,SAAS,EAAE,CAAC,EAAE;AAAA,EACpD;AAAA,EAEQ,KAAK,UAAqB,MAAuB;AACvD,UAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,QAAI,CAAC,IAAK;AACV,eAAW,YAAY,CAAC,GAAG,GAAG,GAAG;AAC/B,UAAI;AACF,iBAAS,GAAG,IAAI;AAAA,MAClB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,mBAAmC;AACjC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAEA,mBAAkC;AAChC,WAAO,KAAK;AAAA,EACd;AACF;AAEA,SAAS,YAAY,MAAc,SAAwB;AACzD,QAAM,MAAM,IAAI,MAAM,OAAO;AAC7B,MAAI,OAAO;AACX,SAAO;AACT;;;AD3bO,SAAS,sBAAsB,SAAuC;AAC3E,MAAI;AACJ,MAAI,YAAY;AAEhB,SAAO,gBAAsC,CAAC,WAAW;AACvD,UAAM,iBAAiB,MAA4B;AACjD,UAAI,CAAC,SAAU,YAAW,IAAI,qBAAqB,OAAO;AAC1D,UAAI,CAAC,WAAW;AACd,iBAAS,QAAQ;AACjB,oBAAY;AAIZ,iBAAS,GAAG,mBAAmB,CAAC,aAAa;AAC3C,iBAAO,QAAQ,KAAK,UAAU;AAAA,YAC5B,UAAU,MAAM,QAAQ,QAAQ,IAC3B,WACA,CAAC;AAAA,UACR,CAAC;AAAA,QACH,CAAC;AACD,iBAAS,GAAG,gBAAgB,CAAC,eAAe;AAC1C,gBAAM,UACJ,OAAO,eAAe,WAClB,OAAO,SAAS,YAAY,EAAE,IAC9B,OAAO,UAAU;AACvB,cAAI,OAAO,SAAS,OAAO,GAAG;AAC5B,mBAAO,QAAQ,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,UAC3C;AAAA,QACF,CAAC;AACD,iBAAS,GAAG,cAAc,MAAM;AAC9B,iBAAO,QAAQ,KAAK,YAAY;AAAA,QAClC,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,MAAM;AAAA;AAAA,MAGN,MAAM,UAAwB;AAI5B,cAAM,IAAI,eAAe;AACzB,cAAM,iBAAkB,MAAM,EAAE,QAAQ;AAAA,UACtC,QAAQ;AAAA,QACV,CAAC;AACD,cAAM,aAAc,MAAM,EAAE,QAAQ,EAAE,QAAQ,cAAc,CAAC;AAC7D,cAAM,UAAU,OAAO,SAAS,YAAY,EAAE;AAC9C,eAAO;AAAA,UACL,UAAU;AAAA,UACV,SAAS,OAAO,SAAS,OAAO,IAAI,UAAU;AAAA,QAChD;AAAA,MACF;AAAA,MAEA,MAAM,aAAa;AAMjB,YAAI,SAAU,UAAS,UAAU;AACjC,oBAAY;AACZ,mBAAW;AAAA,MACb;AAAA,MAEA,MAAM,cAAc;AAClB,cAAM,IAAI,eAAe;AACzB,cAAM,SAAS,EAAE,iBAAiB;AAClC,YAAI,OAAQ,QAAO,CAAC,MAAM;AAC1B,cAAM,WAAY,MAAM,EAAE,QAAQ;AAAA,UAChC,QAAQ;AAAA,QACV,CAAC;AACD,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,aAAa;AACjB,cAAM,IAAI,eAAe;AACzB,cAAM,SAAS,EAAE,iBAAiB;AAClC,YAAI,WAAW,KAAM,QAAO;AAC5B,cAAM,aAAc,MAAM,EAAE,QAAQ,EAAE,QAAQ,cAAc,CAAC;AAC7D,cAAM,UAAU,OAAO,SAAS,YAAY,EAAE;AAC9C,eAAO,OAAO,SAAS,OAAO,IAAI,UAAU;AAAA,MAC9C;AAAA,MAEA,MAAM,cAAc;AAClB,eAAO,eAAe;AAAA,MACxB;AAAA,MAEA,MAAM,eAAe;AAKnB,YAAI;AACF,gBAAM,IAAI,eAAe;AACzB,gBAAM,WAAY,MAAM,EAAE,QAAQ;AAAA,YAChC,QAAQ;AAAA,UACV,CAAC;AACD,iBAAO,SAAS,SAAS;AAAA,QAC3B,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,YAAY,EAAE,QAAQ,GAAmB;AAC7C,cAAM,IAAI,eAAe;AACzB,cAAM,EAAE,QAAQ;AAAA,UACd,QAAQ;AAAA,UACR,QAAQ,CAAC,EAAE,SAAS,KAAK,QAAQ,SAAS,EAAE,CAAC,GAAG,CAAC;AAAA,QACnD,CAAC;AACD,cAAM,QAAQ,OAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;AACxD,YAAI,CAAC,OAAO;AACV,gBAAM,IAAI,MAAM,SAAS,OAAO,8BAA8B;AAAA,QAChE;AACA,eAAO;AAAA,MACT;AAAA,MAEA,kBAAkB,UAAU;AAC1B,eAAO,QAAQ,KAAK,UAAU;AAAA,UAC5B;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,eAAe,YAAY;AACzB,cAAM,UAAU,OAAO,SAAS,YAAY,EAAE;AAC9C,YAAI,OAAO,SAAS,OAAO,GAAG;AAC5B,iBAAO,QAAQ,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,QAC3C;AAAA,MACF;AAAA,MACA,eAAe;AACb,eAAO,QAAQ,KAAK,YAAY;AAAA,MAClC;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AEhHO,SAAS,0BACd,SACqB;AACrB,QAAM,eAAe,8BAA8B;AAAA,IACjD,cAAc,QAAQ;AAAA,EACxB,CAAC;AACD,MAAI,iBAAiB,MAAM;AACzB,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AAAA,IACL,sBAAsB;AAAA,MACpB;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,GAAI,QAAQ,qBAAqB,SAC7B,EAAE,kBAAkB,QAAQ,iBAAiB,IAC7C,CAAC;AAAA,IACP,CAAC;AAAA,EACH;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/blueprint-ui",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Shared blueprint UI components, hooks, and contract utilities for Tangle Network apps",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "repository": {