@burdenoff/microfe-brainyrich 2026.731.2 → 2026.731.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/brainyrich/BrainyRichRoot.d.ts.map +1 -1
- package/dist/brainyrich/BrainyRichRoot.js +60 -53
- package/dist/brainyrich/BrainyRichRoot.js.map +1 -1
- package/dist/brainyrich/BrainyRichRoutes.d.ts.map +1 -1
- package/dist/brainyrich/BrainyRichRoutes.js +20 -16
- package/dist/brainyrich/BrainyRichRoutes.js.map +1 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts +696 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts.map +1 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.js +473 -266
- package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -1
- package/dist/brainyrich/pages/FirmPage.d.ts +2 -0
- package/dist/brainyrich/pages/FirmPage.d.ts.map +1 -0
- package/dist/brainyrich/pages/FirmPage.js +255 -0
- package/dist/brainyrich/pages/FirmPage.js.map +1 -0
- package/dist/brainyrich/pages/ReportsPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/ReportsPage.js +606 -331
- package/dist/brainyrich/pages/ReportsPage.js.map +1 -1
- package/dist/brainyrich/pages/RiskPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/RiskPage.js +619 -403
- package/dist/brainyrich/pages/RiskPage.js.map +1 -1
- package/dist/brainyrich/types/bra.d.ts +161 -0
- package/dist/brainyrich/types/bra.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBrainyRichApi.js","names":[],"sources":["../../../src/brainyrich/hooks/useBrainyRichApi.ts"],"sourcesContent":["/**\n * BrainyRich API hooks\n * @module brainyrich/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-brainyrich-svc`\n * federated GraphQL contract (the `bra*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL (via `BrainyRichRootProps.apiGatewayUrl`,\n * threaded from `useBrainyRich()`) + a workspace-scoped token.\n */\n\nimport { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useBrainyRich } from '../providers/BrainyRichProvider';\nimport { notify, errorMessage } from '../components/notify';\nimport type {\n Connection,\n BraNetWorthSummary,\n BraAccount,\n BraAccountStatus,\n BraPortfolio,\n BraPortfolioStatus,\n BraHolding,\n BraModelPortfolio,\n BraModelAllocation,\n BraGoal,\n BraGoalStatus,\n BraGoalFunding,\n BraHousehold,\n BraHouseholdStatus,\n BraInsight,\n BraInsightSeverity,\n BraInsightStatus,\n BraTransaction,\n BraTransactionType,\n BraRebalanceProposal,\n BraRebalanceStatus,\n BraPortfolioRiskReport,\n BraRiskSummary,\n BraTaxLossReport,\n BraTaxLossThresholds,\n BraCreateAccountInput,\n BraUpdateAccountInput,\n BraCreatePortfolioInput,\n BraUpdatePortfolioInput,\n BraCreateHoldingInput,\n BraUpdateHoldingInput,\n BraCreateModelPortfolioInput,\n BraCreateGoalInput,\n BraUpdateGoalInput,\n BraLinkGoalFundingInput,\n BraCreateHouseholdInput,\n BraUpdateHouseholdInput,\n BraCreateInsightInput,\n BraCreateTransactionInput,\n BraCreateRebalanceProposalInput,\n PaginationInput,\n} from '../types/bra';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in an in-memory cache keyed\n * by operationName+variables for ~15s (mutations are never cached). A read issued\n * right after a write (e.g. the React-Query refetch our `invalidateQueries`\n * triggers) would otherwise return the PRE-mutation response until the TTL\n * expires — making just-created/updated rows invisible until a full reload.\n * fe-libs' documented remedy is that write-performing callers clear those caches;\n * we do exactly that after every bra mutation so every follow-up read is fresh.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\nconst braQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string,\n opts?: { suppressGlobalError?: boolean }\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n // When suppressed, fe-libs does NOT dispatch the global BACKEND_ERROR_EVENT\n // (which the host app-shell auto-toasts). Mutations suppress it so their\n // centralized `onError` (mutationFeedback) is the SINGLE toast source — no\n // double-toast against the shell listener. Reads leave it un-suppressed so a\n // failed read still drives the shell's connection indicator / error toast in\n // addition to the page's own ErrorState.\n suppressGlobalErrorEvent: opts?.suppressGlobalError ?? false,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n return response.data;\n};\n\n/**\n * Mutation transport — identical to `braQuery` but (a) suppresses the global\n * error event so mutation feedback is owned solely by the hooks' `onError`, and\n * (b) clears read caches after so follow-up reads are fresh.\n */\nconst braMutate = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const data = await braQuery<TData>(query, variables, baseUrl, { suppressGlobalError: true });\n clearGraphqlReadCaches();\n return data;\n};\n\n// ============================================================================\n// Centralized mutation feedback (fixes the silent-mutation-failure defect)\n// ============================================================================\n\n/**\n * Compose success/error toast feedback onto a React-Query mutation WITHOUT\n * discarding the hook's existing `onSuccess` side-effects (cache invalidation).\n *\n * - `onError` always fires `notify.error(<friendly message>)` — this is the one\n * place mutation failures surface, for every hook, so pages need no per-call\n * error handling.\n * - `onSuccess` runs the caller's invalidation first, then `notify.success`.\n *\n * Call-site handlers passed to `mutate(vars, { onSuccess, onError })` STILL run\n * (React-Query invokes both the hook-level and call-level callbacks), so pages\n * keep closing dialogs etc. on success.\n */\nfunction mutationFeedback<TData, TVars>(opts: {\n success?: string | ((data: TData, vars: TVars) => string);\n onSuccess?: (data: TData, vars: TVars) => void;\n}): {\n onSuccess: (data: TData, vars: TVars) => void;\n onError: (error: unknown) => void;\n} {\n return {\n onSuccess: (data, vars) => {\n opts.onSuccess?.(data, vars);\n if (opts.success) {\n notify.success(\n typeof opts.success === 'function' ? opts.success(data, vars) : opts.success\n );\n }\n },\n onError: (error) => notify.error(errorMessage(error)),\n };\n}\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n netWorth: ['brainyrich', 'net-worth'] as const,\n accounts: ['brainyrich', 'accounts'] as const,\n account: (id: string) => ['brainyrich', 'account', id] as const,\n portfolios: ['brainyrich', 'portfolios'] as const,\n portfolio: (id: string) => ['brainyrich', 'portfolio', id] as const,\n holdings: ['brainyrich', 'holdings'] as const,\n modelPortfolios: ['brainyrich', 'model-portfolios'] as const,\n modelPortfolio: (id: string) => ['brainyrich', 'model-portfolio', id] as const,\n goals: ['brainyrich', 'goals'] as const,\n goal: (id: string) => ['brainyrich', 'goal', id] as const,\n goalFundings: (goalId: string) => ['brainyrich', 'goal-fundings', goalId] as const,\n households: ['brainyrich', 'households'] as const,\n household: (id: string) => ['brainyrich', 'household', id] as const,\n insights: ['brainyrich', 'insights'] as const,\n insight: (id: string) => ['brainyrich', 'insight', id] as const,\n riskSignals: (portfolioId: string) => ['brainyrich', 'risk-signals', portfolioId] as const,\n riskSummary: (portfolioId: string) => ['brainyrich', 'risk-summary', portfolioId] as const,\n taxLossOpportunities: (portfolioId: string) =>\n ['brainyrich', 'tax-loss-opportunities', portfolioId] as const,\n transactions: ['brainyrich', 'transactions'] as const,\n rebalances: ['brainyrich', 'rebalance-proposals'] as const,\n health: ['brainyrich', 'health'] as const,\n};\n\n/** Gateway is offset-based; OMIT `cursor` on the first page. */\nconst DEFAULT_PAGE: PaginationInput = { limit: 50 };\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness — mirror bra.ts)\n// ============================================================================\n\nconst HOLDING_FIELDS = `\n id workspaceId accountId portfolioId symbol name assetClass quantity lastPrice\n costBasis marketValue currency asOf createdAt updatedAt\n`;\n\nconst TRANSACTION_FIELDS = `\n id workspaceId accountId holdingId type symbol quantity price amount fee currency\n tradeDate settleDate notes createdAt updatedAt\n`;\n\nconst ACCOUNT_FIELDS = `\n id workspaceId ownerId householdId name type status institution accountMask\n cashBalance currency isManual createdAt updatedAt\n`;\n\nconst PORTFOLIO_FIELDS = `\n id workspaceId ownerId householdId name description status baseCurrency\n modelPortfolioId driftThresholdPct targetAllocation tags createdAt updatedAt\n`;\n\nconst MODEL_ALLOCATION_FIELDS = `\n id workspaceId modelPortfolioId assetClass targetPct createdAt updatedAt\n`;\n\nconst MODEL_PORTFOLIO_FIELDS = `\n id workspaceId name description riskProfile baseCurrency isActive createdAt updatedAt\n`;\n\nconst GOAL_FUNDING_FIELDS = `\n id workspaceId goalId accountId allocationPct fixedAmount createdAt updatedAt\n`;\n\nconst GOAL_FIELDS = `\n id workspaceId ownerId householdId name type status projection targetAmount\n targetDate monthlyContribution priority currency notes tags createdAt updatedAt\n`;\n\nconst HOUSEHOLD_FIELDS = `\n id workspaceId name status riskProfile advisorId aum currency primaryContactName\n primaryContactEmail notes tags createdAt updatedAt\n`;\n\nconst INSIGHT_FIELDS = `\n id workspaceId ownerId type severity status title detail metrics subjectId\n subjectType acknowledgedById resolvedAt createdAt updatedAt\n`;\n\nconst REBALANCE_FIELDS = `\n id workspaceId portfolioId householdId status driftPct rationale trades\n proposedById approvedById executedAt createdAt updatedAt\n`;\n\nconst NET_WORTH_FIELDS = `\n workspaceId ownerId totalNetWorth totalMarketValue totalCash accountCount currency\n byAssetClass { assetClass marketValue }\n`;\n\n// ============================================================================\n// Filter param shapes (exported so page agents can type their call sites)\n// ============================================================================\n\nexport interface AccountFilters {\n householdId?: string;\n status?: BraAccountStatus;\n pagination?: PaginationInput;\n}\n\nexport interface PortfolioFilters {\n householdId?: string;\n status?: BraPortfolioStatus;\n pagination?: PaginationInput;\n}\n\nexport interface HoldingFilters {\n accountId?: string;\n portfolioId?: string;\n}\n\nexport interface GoalFilters {\n householdId?: string;\n status?: BraGoalStatus;\n pagination?: PaginationInput;\n}\n\nexport interface HouseholdFilters {\n status?: BraHouseholdStatus;\n pagination?: PaginationInput;\n}\n\nexport interface InsightFilters {\n severity?: BraInsightSeverity;\n status?: BraInsightStatus;\n subjectId?: string;\n subjectType?: string;\n pagination?: PaginationInput;\n}\n\nexport interface TransactionFilters {\n accountId?: string;\n type?: BraTransactionType;\n pagination?: PaginationInput;\n}\n\nexport interface RebalanceFilters {\n householdId?: string;\n portfolioId?: string;\n status?: BraRebalanceStatus;\n}\n\n// ============================================================================\n// Health\n// ============================================================================\n\nexport const useBraHealth = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.health,\n queryFn: async () => {\n const result = await braQuery<{ braHealth: string }>(\n `query BraHealth { braHealth }`,\n {},\n apiGatewayUrl\n );\n return result.braHealth;\n },\n });\n};\n\n// ============================================================================\n// Net worth (Overview)\n// ============================================================================\n\nexport const useNetWorthSummary = (ownerId?: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: [...KEY.netWorth, ownerId ?? 'me'],\n queryFn: async () => {\n const result = await braQuery<{ braNetWorthSummary: BraNetWorthSummary }>(\n `query BraNetWorthSummary($ownerId: ID) {\n braNetWorthSummary(ownerId: $ownerId) { ${NET_WORTH_FIELDS} }\n }`,\n { ownerId },\n apiGatewayUrl\n );\n return result.braNetWorthSummary;\n },\n });\n};\n\n// ============================================================================\n// Accounts\n// ============================================================================\n\nexport const useAccounts = (params: AccountFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.accounts, params],\n queryFn: async () => {\n const result = await braQuery<{ braListAccounts: Connection<BraAccount> }>(\n `query BraListAccounts($householdId: ID, $status: BraAccountStatus, $pagination: PaginationInput) {\n braListAccounts(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${ACCOUNT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n status: params.status,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListAccounts;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\n/** Raw wire shape for `braAccount`: nested `holdings`/`transactions` are Connections. */\ntype BraAccountWire = Omit<BraAccount, 'holdings' | 'transactions'> & {\n holdings: Connection<BraHolding>;\n transactions: Connection<BraTransaction>;\n};\n\nexport const useAccount = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.account(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braAccount: BraAccountWire | null }>(\n `query BraAccount($id: ID!) {\n braAccount(id: $id) {\n ${ACCOUNT_FIELDS}\n holdings { items { ${HOLDING_FIELDS} } pageInfo { cursor hasMore } }\n transactions { items { ${TRANSACTION_FIELDS} } pageInfo { cursor hasMore } }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n if (!result.braAccount) return null;\n const { holdings, transactions, ...rest } = result.braAccount;\n return { ...rest, holdings: holdings.items, transactions: transactions.items } as BraAccount;\n },\n });\n};\n\nexport const useCreateAccount = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateAccountInput) => {\n const result = await braMutate<{ braCreateAccount: BraAccount }>(\n `mutation BraCreateAccount($input: BraCreateAccountInput!) {\n braCreateAccount(input: $input) { ${ACCOUNT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateAccount;\n },\n ...mutationFeedback<BraAccount, BraCreateAccountInput>({\n success: 'Account created',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useUpdateAccount = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateAccountInput }) => {\n const result = await braMutate<{ braUpdateAccount: BraAccount }>(\n `mutation BraUpdateAccount($id: ID!, $input: BraUpdateAccountInput!) {\n braUpdateAccount(id: $id, input: $input) { ${ACCOUNT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateAccount;\n },\n ...mutationFeedback<BraAccount, { id: string; input: BraUpdateAccountInput }>({\n success: 'Account updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.account(data.id) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useArchiveAccount = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchiveAccount: boolean }>(\n `mutation BraArchiveAccount($id: ID!) { braArchiveAccount(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchiveAccount;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Account archived',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\n// ============================================================================\n// Portfolios\n// ============================================================================\n\nexport const usePortfolios = (params: PortfolioFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.portfolios, params],\n queryFn: async () => {\n const result = await braQuery<{ braListPortfolios: Connection<BraPortfolio> }>(\n `query BraListPortfolios($householdId: ID, $status: BraPortfolioStatus, $pagination: PaginationInput) {\n braListPortfolios(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${PORTFOLIO_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n status: params.status,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListPortfolios;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\n/** Raw wire shape for `braPortfolio`: nested `holdings` is a Connection. */\ntype BraPortfolioWire = Omit<BraPortfolio, 'holdings'> & { holdings: Connection<BraHolding> };\n\nexport const usePortfolio = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.portfolio(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braPortfolio: BraPortfolioWire | null }>(\n `query BraPortfolio($id: ID!) {\n braPortfolio(id: $id) {\n ${PORTFOLIO_FIELDS}\n holdings { items { ${HOLDING_FIELDS} } pageInfo { cursor hasMore } }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n if (!result.braPortfolio) return null;\n const { holdings, ...rest } = result.braPortfolio;\n return { ...rest, holdings: holdings.items } as BraPortfolio;\n },\n });\n};\n\nexport const useCreatePortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreatePortfolioInput) => {\n const result = await braMutate<{ braCreatePortfolio: BraPortfolio }>(\n `mutation BraCreatePortfolio($input: BraCreatePortfolioInput!) {\n braCreatePortfolio(input: $input) { ${PORTFOLIO_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreatePortfolio;\n },\n ...mutationFeedback<BraPortfolio, BraCreatePortfolioInput>({\n success: 'Portfolio created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.portfolios }),\n }),\n });\n};\n\nexport const useUpdatePortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdatePortfolioInput }) => {\n const result = await braMutate<{ braUpdatePortfolio: BraPortfolio }>(\n `mutation BraUpdatePortfolio($id: ID!, $input: BraUpdatePortfolioInput!) {\n braUpdatePortfolio(id: $id, input: $input) { ${PORTFOLIO_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdatePortfolio;\n },\n ...mutationFeedback<BraPortfolio, { id: string; input: BraUpdatePortfolioInput }>({\n success: 'Portfolio updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.portfolios });\n qc.invalidateQueries({ queryKey: KEY.portfolio(data.id) });\n },\n }),\n });\n};\n\nexport const useArchivePortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchivePortfolio: boolean }>(\n `mutation BraArchivePortfolio($id: ID!) { braArchivePortfolio(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchivePortfolio;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Portfolio archived',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.portfolios }),\n }),\n });\n};\n\n// ============================================================================\n// Holdings\n// ============================================================================\n\nexport const useHoldings = (params: HoldingFilters) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.holdings, params],\n enabled: Boolean(params.accountId || params.portfolioId),\n queryFn: async () => {\n const result = await braQuery<{ braListHoldings: Connection<BraHolding> }>(\n `query BraListHoldings($accountId: ID, $portfolioId: ID) {\n braListHoldings(accountId: $accountId, portfolioId: $portfolioId) {\n items { ${HOLDING_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { accountId: params.accountId, portfolioId: params.portfolioId },\n apiGatewayUrl\n );\n return result.braListHoldings.items;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateHolding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateHoldingInput) => {\n const result = await braMutate<{ braCreateHolding: BraHolding }>(\n `mutation BraCreateHolding($input: BraCreateHoldingInput!) {\n braCreateHolding(input: $input) { ${HOLDING_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateHolding;\n },\n ...mutationFeedback<BraHolding, BraCreateHoldingInput>({\n success: 'Holding added',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.holdings });\n qc.invalidateQueries({ queryKey: KEY.account(data.accountId) });\n if (data.portfolioId) qc.invalidateQueries({ queryKey: KEY.portfolio(data.portfolioId) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useUpdateHolding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateHoldingInput }) => {\n const result = await braMutate<{ braUpdateHolding: BraHolding }>(\n `mutation BraUpdateHolding($id: ID!, $input: BraUpdateHoldingInput!) {\n braUpdateHolding(id: $id, input: $input) { ${HOLDING_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateHolding;\n },\n ...mutationFeedback<BraHolding, { id: string; input: BraUpdateHoldingInput }>({\n success: 'Holding updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.holdings });\n qc.invalidateQueries({ queryKey: KEY.account(data.accountId) });\n if (data.portfolioId) qc.invalidateQueries({ queryKey: KEY.portfolio(data.portfolioId) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useDeleteHolding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braDeleteHolding: boolean }>(\n `mutation BraDeleteHolding($id: ID!) { braDeleteHolding(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braDeleteHolding;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Holding removed',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.holdings });\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.portfolios });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\n// ============================================================================\n// Model portfolios\n// ============================================================================\n\n/**\n * Raw wire shape for `BraModelPortfolio`: nested `allocations` is a Connection\n * (`BraModelAllocationConnection`), same as `braListModelPortfolios` itself\n * (`BraModelPortfolioConnection`) — both need an `items`/`pageInfo` selection,\n * flattened to a plain array at the hook boundary so pages keep working with\n * `BraModelPortfolio[]` / `BraModelAllocation[]`.\n */\ntype BraModelPortfolioWire = Omit<BraModelPortfolio, 'allocations'> & {\n allocations: Connection<BraModelAllocation>;\n};\n\nconst MODEL_PORTFOLIO_SELECTION = `\n ${MODEL_PORTFOLIO_FIELDS}\n allocations { items { ${MODEL_ALLOCATION_FIELDS} } pageInfo { cursor hasMore } }\n`;\n\nconst flattenModelPortfolio = (m: BraModelPortfolioWire): BraModelPortfolio => ({\n ...m,\n allocations: m.allocations.items,\n});\n\nexport const useModelPortfolios = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.modelPortfolios,\n queryFn: async () => {\n const result = await braQuery<{\n braListModelPortfolios: Connection<BraModelPortfolioWire>;\n }>(\n `query BraListModelPortfolios {\n braListModelPortfolios {\n items { ${MODEL_PORTFOLIO_SELECTION} }\n pageInfo { cursor hasMore }\n }\n }`,\n {},\n apiGatewayUrl\n );\n return result.braListModelPortfolios.items.map(flattenModelPortfolio);\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useModelPortfolio = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.modelPortfolio(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braModelPortfolio: BraModelPortfolioWire | null }>(\n `query BraModelPortfolio($id: ID!) {\n braModelPortfolio(id: $id) {\n ${MODEL_PORTFOLIO_SELECTION}\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braModelPortfolio ? flattenModelPortfolio(result.braModelPortfolio) : null;\n },\n });\n};\n\nexport const useCreateModelPortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateModelPortfolioInput) => {\n const result = await braMutate<{ braCreateModelPortfolio: BraModelPortfolioWire }>(\n `mutation BraCreateModelPortfolio($input: BraCreateModelPortfolioInput!) {\n braCreateModelPortfolio(input: $input) {\n ${MODEL_PORTFOLIO_SELECTION}\n }\n }`,\n { input },\n apiGatewayUrl\n );\n return flattenModelPortfolio(result.braCreateModelPortfolio);\n },\n ...mutationFeedback<BraModelPortfolio, BraCreateModelPortfolioInput>({\n success: 'Model portfolio created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.modelPortfolios }),\n }),\n });\n};\n\n// ============================================================================\n// Goals\n// ============================================================================\n\nexport const useGoals = (params: GoalFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.goals, params],\n queryFn: async () => {\n const result = await braQuery<{ braListGoals: Connection<BraGoal> }>(\n `query BraListGoals($householdId: ID, $status: BraGoalStatus, $pagination: PaginationInput) {\n braListGoals(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${GOAL_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n status: params.status,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListGoals;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\n/** Raw wire shape for `braGoal`: nested `fundings` is a Connection. */\ntype BraGoalWire = Omit<BraGoal, 'fundings'> & { fundings: Connection<BraGoalFunding> };\n\nexport const useGoal = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.goal(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braGoal: BraGoalWire | null }>(\n `query BraGoal($id: ID!) {\n braGoal(id: $id) {\n ${GOAL_FIELDS}\n fundings { items { ${GOAL_FUNDING_FIELDS} } pageInfo { cursor hasMore } }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n if (!result.braGoal) return null;\n const { fundings, ...rest } = result.braGoal;\n return { ...rest, fundings: fundings.items } as BraGoal;\n },\n });\n};\n\nexport const useGoalFundings = (goalId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.goalFundings(goalId ?? ''),\n enabled: Boolean(goalId),\n queryFn: async () => {\n const result = await braQuery<{ braListGoalFundings: Connection<BraGoalFunding> }>(\n `query BraListGoalFundings($goalId: ID!) {\n braListGoalFundings(goalId: $goalId) {\n items { ${GOAL_FUNDING_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { goalId },\n apiGatewayUrl\n );\n return result.braListGoalFundings.items;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateGoal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateGoalInput) => {\n const result = await braMutate<{ braCreateGoal: BraGoal }>(\n `mutation BraCreateGoal($input: BraCreateGoalInput!) {\n braCreateGoal(input: $input) { ${GOAL_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateGoal;\n },\n ...mutationFeedback<BraGoal, BraCreateGoalInput>({\n success: 'Goal created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.goals }),\n }),\n });\n};\n\nexport const useUpdateGoal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateGoalInput }) => {\n const result = await braMutate<{ braUpdateGoal: BraGoal }>(\n `mutation BraUpdateGoal($id: ID!, $input: BraUpdateGoalInput!) {\n braUpdateGoal(id: $id, input: $input) { ${GOAL_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateGoal;\n },\n ...mutationFeedback<BraGoal, { id: string; input: BraUpdateGoalInput }>({\n success: 'Goal updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.goals });\n qc.invalidateQueries({ queryKey: KEY.goal(data.id) });\n },\n }),\n });\n};\n\nexport const useArchiveGoal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchiveGoal: boolean }>(\n `mutation BraArchiveGoal($id: ID!) { braArchiveGoal(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchiveGoal;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Goal archived',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.goals }),\n }),\n });\n};\n\nexport const useRecalcGoalProjection = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; fundedAmount: number }) => {\n const result = await braMutate<{ braRecalcGoalProjection: BraGoal }>(\n `mutation BraRecalcGoalProjection($id: ID!, $fundedAmount: Float!) {\n braRecalcGoalProjection(id: $id, fundedAmount: $fundedAmount) { ${GOAL_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braRecalcGoalProjection;\n },\n ...mutationFeedback<BraGoal, { id: string; fundedAmount: number }>({\n success: 'Projection recalculated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.goals });\n qc.invalidateQueries({ queryKey: KEY.goal(data.id) });\n },\n }),\n });\n};\n\nexport const useLinkGoalFunding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraLinkGoalFundingInput) => {\n const result = await braMutate<{ braLinkGoalFunding: BraGoalFunding }>(\n `mutation BraLinkGoalFunding($input: BraLinkGoalFundingInput!) {\n braLinkGoalFunding(input: $input) { ${GOAL_FUNDING_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braLinkGoalFunding;\n },\n ...mutationFeedback<BraGoalFunding, BraLinkGoalFundingInput>({\n success: 'Funding linked',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.goalFundings(data.goalId) });\n qc.invalidateQueries({ queryKey: KEY.goal(data.goalId) });\n },\n }),\n });\n};\n\nexport const useUnlinkGoalFunding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braUnlinkGoalFunding: boolean }>(\n `mutation BraUnlinkGoalFunding($id: ID!) { braUnlinkGoalFunding(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braUnlinkGoalFunding;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Funding unlinked',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.goals });\n qc.invalidateQueries({ queryKey: [...KEY.goals] });\n qc.invalidateQueries({ queryKey: ['brainyrich', 'goal-fundings'] });\n qc.invalidateQueries({ queryKey: ['brainyrich', 'goal'] });\n },\n }),\n });\n};\n\n// ============================================================================\n// Households\n// ============================================================================\n\nexport const useHouseholds = (params: HouseholdFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.households, params],\n queryFn: async () => {\n const result = await braQuery<{ braListHouseholds: Connection<BraHousehold> }>(\n `query BraListHouseholds($status: BraHouseholdStatus, $pagination: PaginationInput) {\n braListHouseholds(status: $status, pagination: $pagination) {\n items { ${HOUSEHOLD_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status: params.status, pagination: params.pagination ?? DEFAULT_PAGE },\n apiGatewayUrl\n );\n return result.braListHouseholds;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\nexport const useHousehold = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.household(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braHousehold: BraHousehold | null }>(\n `query BraHousehold($id: ID!) {\n braHousehold(id: $id) { ${HOUSEHOLD_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braHousehold;\n },\n });\n};\n\nexport const useCreateHousehold = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateHouseholdInput) => {\n const result = await braMutate<{ braCreateHousehold: BraHousehold }>(\n `mutation BraCreateHousehold($input: BraCreateHouseholdInput!) {\n braCreateHousehold(input: $input) { ${HOUSEHOLD_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateHousehold;\n },\n ...mutationFeedback<BraHousehold, BraCreateHouseholdInput>({\n success: 'Household created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.households }),\n }),\n });\n};\n\nexport const useUpdateHousehold = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateHouseholdInput }) => {\n const result = await braMutate<{ braUpdateHousehold: BraHousehold }>(\n `mutation BraUpdateHousehold($id: ID!, $input: BraUpdateHouseholdInput!) {\n braUpdateHousehold(id: $id, input: $input) { ${HOUSEHOLD_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateHousehold;\n },\n ...mutationFeedback<BraHousehold, { id: string; input: BraUpdateHouseholdInput }>({\n success: 'Household updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.households });\n qc.invalidateQueries({ queryKey: KEY.household(data.id) });\n },\n }),\n });\n};\n\nexport const useArchiveHousehold = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchiveHousehold: boolean }>(\n `mutation BraArchiveHousehold($id: ID!) { braArchiveHousehold(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchiveHousehold;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Household archived',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.households }),\n }),\n });\n};\n\n// ============================================================================\n// Insights\n// ============================================================================\n\nexport const useInsights = (params: InsightFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.insights, params],\n queryFn: async () => {\n const result = await braQuery<{ braListInsights: Connection<BraInsight> }>(\n `query BraListInsights($severity: BraInsightSeverity, $status: BraInsightStatus, $subjectId: ID, $subjectType: String, $pagination: PaginationInput) {\n braListInsights(severity: $severity, status: $status, subjectId: $subjectId, subjectType: $subjectType, pagination: $pagination) {\n items { ${INSIGHT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n severity: params.severity,\n status: params.status,\n subjectId: params.subjectId,\n subjectType: params.subjectType,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListInsights;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\nexport const useInsight = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.insight(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braInsight: BraInsight | null }>(\n `query BraInsight($id: ID!) {\n braInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braInsight;\n },\n });\n};\n\nexport const useCreateInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateInsightInput) => {\n const result = await braMutate<{ braCreateInsight: BraInsight }>(\n `mutation BraCreateInsight($input: BraCreateInsightInput!) {\n braCreateInsight(input: $input) { ${INSIGHT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateInsight;\n },\n ...mutationFeedback<BraInsight, BraCreateInsightInput>({\n success: 'Insight created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.insights }),\n }),\n });\n};\n\nexport const useAcknowledgeInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braAcknowledgeInsight: BraInsight }>(\n `mutation BraAcknowledgeInsight($id: ID!) {\n braAcknowledgeInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braAcknowledgeInsight;\n },\n ...mutationFeedback<BraInsight, string>({\n success: 'Insight acknowledged',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.insight(data.id) });\n },\n }),\n });\n};\n\nexport const useDismissInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braDismissInsight: BraInsight }>(\n `mutation BraDismissInsight($id: ID!) {\n braDismissInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braDismissInsight;\n },\n ...mutationFeedback<BraInsight, string>({\n success: 'Insight dismissed',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.insight(data.id) });\n },\n }),\n });\n};\n\nexport const useResolveInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braResolveInsight: BraInsight }>(\n `mutation BraResolveInsight($id: ID!) {\n braResolveInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braResolveInsight;\n },\n ...mutationFeedback<BraInsight, string>({\n success: 'Insight resolved',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.insight(data.id) });\n },\n }),\n });\n};\n\n// ============================================================================\n// Risk signals (BOFF-4236) — deterministic engine + optional AI summary\n// ============================================================================\n\nconst RISK_SIGNAL_FIELDS = `kind insightType severity title detail metrics`;\n\n/**\n * Real, explainable risk signals computed live from the portfolio's own\n * holdings/allocation data — every signal carries its formula/threshold under\n * `metrics`. Read-only; nothing is persisted until `useGenerateRiskInsights`\n * is called. Disabled until a portfolio is selected.\n */\nexport const usePortfolioRiskSignals = (portfolioId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.riskSignals(portfolioId ?? ''),\n enabled: Boolean(portfolioId),\n queryFn: async () => {\n const result = await braQuery<{ braPortfolioRiskSignals: BraPortfolioRiskReport }>(\n `query BraPortfolioRiskSignals($portfolioId: ID!) {\n braPortfolioRiskSignals(portfolioId: $portfolioId) {\n portfolioId workspaceId asOf totalValue holdingsConsidered\n signals { ${RISK_SIGNAL_FIELDS} }\n }\n }`,\n { portfolioId },\n apiGatewayUrl\n );\n return result.braPortfolioRiskSignals;\n },\n });\n};\n\n/**\n * Persists the currently-computed signals as `BraInsight` rows (idempotent —\n * re-running updates the existing OPEN insight of the same kind). Refreshes\n * both the signals report and the shared insights list on success.\n */\nexport const useGenerateRiskInsights = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (portfolioId: string) => {\n const result = await braMutate<{ braGenerateRiskInsights: BraInsight[] }>(\n `mutation BraGenerateRiskInsights($portfolioId: ID!) {\n braGenerateRiskInsights(portfolioId: $portfolioId) { ${INSIGHT_FIELDS} }\n }`,\n { portfolioId },\n apiGatewayUrl\n );\n return result.braGenerateRiskInsights;\n },\n ...mutationFeedback<BraInsight[], string>({\n success: (data) => `${data.length} risk insight${data.length === 1 ? '' : 's'} recorded`,\n onSuccess: (_data, portfolioId) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.riskSignals(portfolioId) });\n },\n }),\n });\n};\n\n/**\n * OPTIONAL LLM-generated plain-language restatement of the already-computed\n * signals — never the source of the numbers itself. `generated: false` +\n * `reason` when no provider key is configured; the deterministic signals\n * above always work regardless. Fetched on-demand (`refetch`), not on mount,\n * since it invokes an LLM call.\n */\nexport const usePortfolioRiskSummary = (portfolioId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.riskSummary(portfolioId ?? ''),\n enabled: false,\n queryFn: async () => {\n const result = await braQuery<{ braPortfolioRiskSummary: BraRiskSummary }>(\n `query BraPortfolioRiskSummary($portfolioId: ID!) {\n braPortfolioRiskSummary(portfolioId: $portfolioId) {\n generated summary provider reason signalsConsidered\n }\n }`,\n { portfolioId },\n apiGatewayUrl\n );\n return result.braPortfolioRiskSummary;\n },\n });\n};\n\n// ============================================================================\n// Tax-loss-harvesting opportunities (BOFF-4237) — configurable thresholds +\n// wash-sale caution flag, distinct from the generic TAX_LOSS_HARVEST signal\n// inside the risk engine above.\n// ============================================================================\n\nconst TAX_LOSS_OPPORTUNITY_FIELDS = `symbol marketValue costBasis unrealizedLoss lossPctOfPortfolio severity washSaleRisk washSaleReason metrics`;\n\n/**\n * Preview-only: real tax-loss-harvesting opportunities for one portfolio,\n * computed live with the given (or documented default) thresholds. Never\n * persists anything — see `useHarvestTaxLossInsights` for that.\n */\nexport const useTaxLossOpportunities = (\n portfolioId: string | undefined,\n thresholds?: BraTaxLossThresholds\n) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: [...KEY.taxLossOpportunities(portfolioId ?? ''), thresholds],\n enabled: Boolean(portfolioId),\n queryFn: async () => {\n const result = await braQuery<{ braTaxLossOpportunities: BraTaxLossReport }>(\n `query BraTaxLossOpportunities($portfolioId: ID!, $thresholds: BraTaxLossThresholdInput) {\n braTaxLossOpportunities(portfolioId: $portfolioId, thresholds: $thresholds) {\n portfolioId workspaceId asOf\n thresholds { minLossAmount minLossPct }\n opportunities { ${TAX_LOSS_OPPORTUNITY_FIELDS} }\n }\n }`,\n { portfolioId, thresholds: thresholds ?? null },\n apiGatewayUrl\n );\n return result.braTaxLossOpportunities;\n },\n });\n};\n\n/**\n * Persists the currently-computed tax-loss opportunities as `BraInsight`\n * rows (type TAX_OPPORTUNITY, idempotent per symbol). Detection/flagging\n * only — never executes a trade.\n */\nexport const useHarvestTaxLossInsights = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async ({\n portfolioId,\n thresholds,\n }: {\n portfolioId: string;\n thresholds?: BraTaxLossThresholds;\n }) => {\n const result = await braMutate<{ braHarvestTaxLossInsights: BraInsight[] }>(\n `mutation BraHarvestTaxLossInsights($portfolioId: ID!, $thresholds: BraTaxLossThresholdInput) {\n braHarvestTaxLossInsights(portfolioId: $portfolioId, thresholds: $thresholds) { ${INSIGHT_FIELDS} }\n }`,\n { portfolioId, thresholds: thresholds ?? null },\n apiGatewayUrl\n );\n return result.braHarvestTaxLossInsights;\n },\n ...mutationFeedback<BraInsight[], { portfolioId: string; thresholds?: BraTaxLossThresholds }>({\n success: (data) => `${data.length} tax-loss insight${data.length === 1 ? '' : 's'} recorded`,\n onSuccess: (_data, vars) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.taxLossOpportunities(vars.portfolioId) });\n },\n }),\n });\n};\n\n// ============================================================================\n// Transactions\n// ============================================================================\n\nexport const useTransactions = (params: TransactionFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.transactions, params],\n queryFn: async () => {\n const result = await braQuery<{ braListTransactions: Connection<BraTransaction> }>(\n `query BraListTransactions($accountId: ID, $type: BraTransactionType, $pagination: PaginationInput) {\n braListTransactions(accountId: $accountId, type: $type, pagination: $pagination) {\n items { ${TRANSACTION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n accountId: params.accountId,\n type: params.type,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListTransactions;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\nexport const useRecordTransaction = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateTransactionInput) => {\n const result = await braMutate<{ braRecordTransaction: BraTransaction }>(\n `mutation BraRecordTransaction($input: BraCreateTransactionInput!) {\n braRecordTransaction(input: $input) { ${TRANSACTION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braRecordTransaction;\n },\n ...mutationFeedback<BraTransaction, BraCreateTransactionInput>({\n success: 'Transaction recorded',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.transactions });\n qc.invalidateQueries({ queryKey: KEY.account(data.accountId) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\n// ============================================================================\n// Rebalance proposals\n// ============================================================================\n\nexport const useRebalanceProposals = (params: RebalanceFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.rebalances, params],\n queryFn: async () => {\n const result = await braQuery<{\n braListRebalanceProposals: Connection<BraRebalanceProposal>;\n }>(\n `query BraListRebalanceProposals($householdId: ID, $portfolioId: ID, $status: BraRebalanceStatus) {\n braListRebalanceProposals(householdId: $householdId, portfolioId: $portfolioId, status: $status) {\n items { ${REBALANCE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n portfolioId: params.portfolioId,\n status: params.status,\n },\n apiGatewayUrl\n );\n return result.braListRebalanceProposals.items;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateRebalanceProposal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateRebalanceProposalInput) => {\n const result = await braMutate<{ braCreateRebalanceProposal: BraRebalanceProposal }>(\n `mutation BraCreateRebalanceProposal($input: BraCreateRebalanceProposalInput!) {\n braCreateRebalanceProposal(input: $input) { ${REBALANCE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateRebalanceProposal;\n },\n ...mutationFeedback<BraRebalanceProposal, BraCreateRebalanceProposalInput>({\n success: 'Rebalance proposal created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.rebalances }),\n }),\n });\n};\n\nexport const useTransitionRebalanceProposal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: BraRebalanceStatus }) => {\n const result = await braMutate<{ braTransitionRebalanceProposal: BraRebalanceProposal }>(\n `mutation BraTransitionRebalanceProposal($id: ID!, $status: BraRebalanceStatus!) {\n braTransitionRebalanceProposal(id: $id, status: $status) { ${REBALANCE_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braTransitionRebalanceProposal;\n },\n ...mutationFeedback<BraRebalanceProposal, { id: string; status: BraRebalanceStatus }>({\n success: (data) => `Rebalance ${data.status.toLowerCase()}`,\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.rebalances }),\n }),\n });\n};\n\n// ============================================================================\n// Pagination — \"load more\" for list pages + full-set pagers for aggregations\n// ============================================================================\n//\n// Every `braList*` connection returns `pageInfo { cursor hasMore }`. The gateway\n// is offset-based, so the FIRST page must OMIT `cursor` (explicit null → 500);\n// subsequent pages pass the previous page's `pageInfo.cursor`. Both helpers\n// below honor that rule.\n//\n// • `usePaged*` — incremental \"load more\" for interactive lists. Returns\n// a FLAT `items` array plus `hasMore` / `loadMore`,\n// pairs with the `<LoadMore/>` component.\n// • `fetchAll* / useAll*` — page through to `hasMore === false` so AGGREGATION\n// pages (Analytics net-cash-flow, Tax realized proceeds,\n// Reports ledger) compute over the FULL set, never a\n// truncated first 100.\n\nexport interface PagedListResult<T> {\n /** Flattened items across every fetched page. */\n items: T[];\n /** Another page exists. */\n hasMore: boolean;\n /** Fetch the next page (appends to `items`). */\n loadMore: () => void;\n /** First page in flight. */\n isLoading: boolean;\n /** A subsequent page in flight (drive the `<LoadMore/>` spinner off this). */\n isFetchingNextPage: boolean;\n isError: boolean;\n refetch: () => void;\n}\n\n/**\n * Generic cursor-accumulating list hook built on React-Query `useInfiniteQuery`.\n * Concrete `usePaged*` wrappers below supply the query + variables; page agents\n * consume those, not this directly.\n */\nfunction usePagedConnection<T>(config: {\n queryKey: readonly unknown[];\n query: string;\n buildVariables: (pagination: PaginationInput) => Record<string, unknown>;\n select: (data: unknown) => Connection<T>;\n enabled?: boolean;\n pageSize?: number;\n}): PagedListResult<T> {\n const { apiGatewayUrl } = useBrainyRich();\n const pageSize = config.pageSize ?? DEFAULT_PAGE.limit ?? 100;\n const infinite = useInfiniteQuery({\n queryKey: config.queryKey,\n enabled: config.enabled ?? true,\n initialPageParam: null as string | null,\n queryFn: async ({ pageParam }) => {\n const pagination: PaginationInput = pageParam\n ? { limit: pageSize, cursor: pageParam }\n : { limit: pageSize };\n const data = await braQuery<unknown>(\n config.query,\n config.buildVariables(pagination),\n apiGatewayUrl\n );\n return config.select(data);\n },\n getNextPageParam: (last) =>\n last.pageInfo.hasMore && last.pageInfo.cursor ? last.pageInfo.cursor : undefined,\n });\n\n return {\n items: (infinite.data?.pages ?? []).flatMap((page) => page.items),\n hasMore: Boolean(infinite.hasNextPage),\n loadMore: () => {\n void infinite.fetchNextPage();\n },\n isLoading: infinite.isLoading,\n isFetchingNextPage: infinite.isFetchingNextPage,\n isError: infinite.isError,\n refetch: () => {\n void infinite.refetch();\n },\n };\n}\n\nexport const usePagedAccounts = (params: AccountFilters = {}): PagedListResult<BraAccount> =>\n usePagedConnection<BraAccount>({\n queryKey: [...KEY.accounts, 'paged', params],\n query: `query BraListAccounts($householdId: ID, $status: BraAccountStatus, $pagination: PaginationInput) {\n braListAccounts(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${ACCOUNT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n householdId: params.householdId,\n status: params.status,\n pagination,\n }),\n select: (data) => (data as { braListAccounts: Connection<BraAccount> }).braListAccounts,\n });\n\nexport const usePagedPortfolios = (params: PortfolioFilters = {}): PagedListResult<BraPortfolio> =>\n usePagedConnection<BraPortfolio>({\n queryKey: [...KEY.portfolios, 'paged', params],\n query: `query BraListPortfolios($householdId: ID, $status: BraPortfolioStatus, $pagination: PaginationInput) {\n braListPortfolios(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${PORTFOLIO_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n householdId: params.householdId,\n status: params.status,\n pagination,\n }),\n select: (data) => (data as { braListPortfolios: Connection<BraPortfolio> }).braListPortfolios,\n });\n\nexport const usePagedGoals = (params: GoalFilters = {}): PagedListResult<BraGoal> =>\n usePagedConnection<BraGoal>({\n queryKey: [...KEY.goals, 'paged', params],\n query: `query BraListGoals($householdId: ID, $status: BraGoalStatus, $pagination: PaginationInput) {\n braListGoals(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${GOAL_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n householdId: params.householdId,\n status: params.status,\n pagination,\n }),\n select: (data) => (data as { braListGoals: Connection<BraGoal> }).braListGoals,\n });\n\nexport const usePagedHouseholds = (params: HouseholdFilters = {}): PagedListResult<BraHousehold> =>\n usePagedConnection<BraHousehold>({\n queryKey: [...KEY.households, 'paged', params],\n query: `query BraListHouseholds($status: BraHouseholdStatus, $pagination: PaginationInput) {\n braListHouseholds(status: $status, pagination: $pagination) {\n items { ${HOUSEHOLD_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({ status: params.status, pagination }),\n select: (data) => (data as { braListHouseholds: Connection<BraHousehold> }).braListHouseholds,\n });\n\nexport const usePagedInsights = (params: InsightFilters = {}): PagedListResult<BraInsight> =>\n usePagedConnection<BraInsight>({\n queryKey: [...KEY.insights, 'paged', params],\n query: `query BraListInsights($severity: BraInsightSeverity, $status: BraInsightStatus, $subjectId: ID, $subjectType: String, $pagination: PaginationInput) {\n braListInsights(severity: $severity, status: $status, subjectId: $subjectId, subjectType: $subjectType, pagination: $pagination) {\n items { ${INSIGHT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n severity: params.severity,\n status: params.status,\n subjectId: params.subjectId,\n subjectType: params.subjectType,\n pagination,\n }),\n select: (data) => (data as { braListInsights: Connection<BraInsight> }).braListInsights,\n });\n\nexport const usePagedTransactions = (\n params: TransactionFilters = {}\n): PagedListResult<BraTransaction> =>\n usePagedConnection<BraTransaction>({\n queryKey: [...KEY.transactions, 'paged', params],\n query: `query BraListTransactions($accountId: ID, $type: BraTransactionType, $pagination: PaginationInput) {\n braListTransactions(accountId: $accountId, type: $type, pagination: $pagination) {\n items { ${TRANSACTION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n accountId: params.accountId,\n type: params.type,\n pagination,\n }),\n select: (data) =>\n (data as { braListTransactions: Connection<BraTransaction> }).braListTransactions,\n });\n\n// ----------------------------------------------------------------------------\n// Full-set pagers (aggregation)\n// ----------------------------------------------------------------------------\n\n/** Page through a connection until `hasMore === false`, returning every item. */\nasync function fetchAllConnection<T>(\n fetchPage: (pagination: PaginationInput) => Promise<Connection<T>>,\n pageSize = 200,\n maxPages = 500\n): Promise<T[]> {\n const all: T[] = [];\n let cursor: string | null | undefined;\n for (let i = 0; i < maxPages; i++) {\n const pagination: PaginationInput = cursor ? { limit: pageSize, cursor } : { limit: pageSize };\n const connection = await fetchPage(pagination);\n all.push(...connection.items);\n if (!connection.pageInfo.hasMore || !connection.pageInfo.cursor) break;\n cursor = connection.pageInfo.cursor;\n }\n return all;\n}\n\n/** Fetch EVERY transaction matching `filters` (all pages). */\nexport async function fetchAllTransactions(\n apiGatewayUrl: string | undefined,\n filters: Omit<TransactionFilters, 'pagination'> = {},\n pageSize = 200\n): Promise<BraTransaction[]> {\n return fetchAllConnection<BraTransaction>(async (pagination) => {\n const data = await braQuery<{ braListTransactions: Connection<BraTransaction> }>(\n `query BraListTransactions($accountId: ID, $type: BraTransactionType, $pagination: PaginationInput) {\n braListTransactions(accountId: $accountId, type: $type, pagination: $pagination) {\n items { ${TRANSACTION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { accountId: filters.accountId, type: filters.type, pagination },\n apiGatewayUrl\n );\n return data.braListTransactions;\n }, pageSize);\n}\n\n/**\n * Fetch EVERY holding matching `filters` (all pages). `braListHoldings` is a\n * paginated `BraHoldingConnection` (default page size 50) like every other\n * `braList*` field, so a single un-paginated call silently truncates accounts\n * holding more than one page of positions — page through it fully here.\n */\nexport async function fetchAllHoldings(\n apiGatewayUrl: string | undefined,\n filters: HoldingFilters = {},\n pageSize = 200\n): Promise<BraHolding[]> {\n return fetchAllConnection<BraHolding>(async (pagination) => {\n const data = await braQuery<{ braListHoldings: Connection<BraHolding> }>(\n `query BraListHoldings($accountId: ID, $portfolioId: ID, $pagination: PaginationInput) {\n braListHoldings(accountId: $accountId, portfolioId: $portfolioId, pagination: $pagination) {\n items { ${HOLDING_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { accountId: filters.accountId, portfolioId: filters.portfolioId, pagination },\n apiGatewayUrl\n );\n return data.braListHoldings;\n }, pageSize);\n}\n\n/**\n * Aggregation-ready hook: ALL transactions matching `filters`. Use on Analytics\n * (net-cash-flow), Tax (realized proceeds) and Reports (ledger) so totals are\n * computed over the complete set rather than a truncated first page.\n */\nexport const useAllTransactions = (filters: Omit<TransactionFilters, 'pagination'> = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.transactions, 'all', filters],\n queryFn: () => fetchAllTransactions(apiGatewayUrl, filters),\n });\n return { ...query, data: query.data ?? [] };\n};\n\n/** Fetch EVERY account matching `filters` (all pages). */\nexport async function fetchAllAccounts(\n apiGatewayUrl: string | undefined,\n filters: Omit<AccountFilters, 'pagination'> = {},\n pageSize = 200\n): Promise<BraAccount[]> {\n return fetchAllConnection<BraAccount>(async (pagination) => {\n const data = await braQuery<{ braListAccounts: Connection<BraAccount> }>(\n `query BraListAccounts($householdId: ID, $status: BraAccountStatus, $pagination: PaginationInput) {\n braListAccounts(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${ACCOUNT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { householdId: filters.householdId, status: filters.status, pagination },\n apiGatewayUrl\n );\n return data.braListAccounts;\n }, pageSize);\n}\n\n/**\n * Aggregation-ready hook: ALL accounts matching `filters`. `braListHoldings`\n * IS paginated (`BraHoldingConnection`, default page size 50) like every\n * other `braList*` field — callers reading holdings per-account/portfolio via\n * `useHoldings`/`useAccount`/`usePortfolio` should page through it for\n * accounts that can hold more than one page of positions.\n */\nexport const useAllAccounts = (filters: Omit<AccountFilters, 'pagination'> = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.accounts, 'all', filters],\n queryFn: () => fetchAllAccounts(apiGatewayUrl, filters),\n });\n return { ...query, data: query.data ?? [] };\n};\n"],"mappings":";;;;;AAkFA,IAAM,WAAqC;CACzC,IAAM,IAAI;AAGV,CAFA,EAAE,6BAA6B,OAAO,EACtC,EAAE,gCAAgC,OAAO,EACzC,EAAE,4BAA4B,OAAO;GAGjC,IAAW,OACf,GACA,GACA,GACA,MACmB;CACnB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT;EACA;EACA;EACA,gBAAgB;EAOhB,0BAA0B,GAAM,uBAAuB;EACxD,CAAC;AAEF,KAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,yBAAyB;AAE1E,KAAI,CAAC,EAAS,KACZ,OAAU,MAAM,wCAAwC;AAE1D,QAAO,EAAS;GAQZ,IAAY,OAChB,GACA,GACA,MACmB;CACnB,IAAM,IAAO,MAAM,EAAgB,GAAO,GAAW,GAAS,EAAE,qBAAqB,IAAM,CAAC;AAE5F,QADA,IAAwB,EACjB;;AAoBT,SAAS,EAA+B,GAMtC;AACA,QAAO;EACL,YAAY,GAAM,MAAS;AAEzB,GADA,EAAK,YAAY,GAAM,EAAK,EACxB,EAAK,WACP,EAAO,QACL,OAAO,EAAK,WAAY,aAAa,EAAK,QAAQ,GAAM,EAAK,GAAG,EAAK,QACtE;;EAGL,UAAU,MAAU,EAAO,MAAM,EAAa,EAAM,CAAC;EACtD;;AAIH,IAAM,IAAM;CACV,UAAU,CAAC,cAAc,YAAY;CACrC,UAAU,CAAC,cAAc,WAAW;CACpC,UAAU,MAAe;EAAC;EAAc;EAAW;EAAG;CACtD,YAAY,CAAC,cAAc,aAAa;CACxC,YAAY,MAAe;EAAC;EAAc;EAAa;EAAG;CAC1D,UAAU,CAAC,cAAc,WAAW;CACpC,iBAAiB,CAAC,cAAc,mBAAmB;CACnD,iBAAiB,MAAe;EAAC;EAAc;EAAmB;EAAG;CACrE,OAAO,CAAC,cAAc,QAAQ;CAC9B,OAAO,MAAe;EAAC;EAAc;EAAQ;EAAG;CAChD,eAAe,MAAmB;EAAC;EAAc;EAAiB;EAAO;CACzE,YAAY,CAAC,cAAc,aAAa;CACxC,YAAY,MAAe;EAAC;EAAc;EAAa;EAAG;CAC1D,UAAU,CAAC,cAAc,WAAW;CACpC,UAAU,MAAe;EAAC;EAAc;EAAW;EAAG;CACtD,cAAc,MAAwB;EAAC;EAAc;EAAgB;EAAY;CACjF,cAAc,MAAwB;EAAC;EAAc;EAAgB;EAAY;CACjF,uBAAuB,MACrB;EAAC;EAAc;EAA0B;EAAY;CACvD,cAAc,CAAC,cAAc,eAAe;CAC5C,YAAY,CAAC,cAAc,sBAAsB;CACjD,QAAQ,CAAC,cAAc,SAAS;CACjC,EAGK,IAAgC,EAAE,OAAO,IAAI,EAM7C,IAAiB,mJAKjB,IAAqB,6IAKrB,IAAiB,0IAKjB,IAAmB,iKAKnB,IAA0B,kFAI1B,KAAyB,+FAIzB,IAAsB,uFAItB,IAAc,wKAKd,IAAmB,gJAKnB,IAAiB,mJAKjB,IAAmB,6IAKnB,KAAmB,uIAgFZ,MAAsB,MAAqB;CACtD,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,UAAU,KAAW,KAAK;EAC5C,SAAS,aACQ,MAAM,EACnB;oDAC4C,GAAiB;YAE7D,EAAE,YAAS,EACX,EACD,EACa;EAEjB,CAAC;GAOS,MAAe,IAAyB,EAAE,KAAK;CAC1D,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,CAAC,GAAG,EAAI,UAAU,EAAO;EACnC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAe;;;YAI7B;GACE,aAAa,EAAO;GACpB,QAAQ,EAAO;GACf,YAAY,EAAO,cAAc;GAClC,EACD,EACD,EACa;EAEjB,CAAC;AACF,QAAO;EACL,GAAG;EACH,MAAM,EAAM,MAAM,SAAS,EAAE;EAC7B,UAAU,EAAM,MAAM;EACvB;GASU,KAAc,MAA2B;CACpD,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,EAAI,QAAQ,KAAM,GAAG;EAC/B,SAAS,EAAQ;EACjB,SAAS,YAAY;GACnB,IAAM,IAAS,MAAM,EACnB;;cAEM,EAAe;iCACI,EAAe;qCACX,EAAmB;;YAGhD,EAAE,OAAI,EACN,EACD;AACD,OAAI,CAAC,EAAO,WAAY,QAAO;GAC/B,IAAM,EAAE,aAAU,iBAAc,GAAG,MAAS,EAAO;AACnD,UAAO;IAAE,GAAG;IAAM,UAAU,EAAS;IAAO,cAAc,EAAa;IAAO;;EAEjF,CAAC;GAGS,UAAyB;CACpC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;8CACsC,EAAe;YAErD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAAoD;GACrD,SAAS;GACT,iBAAiB;AAEf,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;;GAEnD,CAAC;EACH,CAAC;GAGS,UAAyB;CACpC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;uDAC+C,EAAe;YAE9D,GACA,EACD,EACa;EAEhB,GAAG,EAA2E;GAC5E,SAAS;GACT,YAAY,MAAS;AAGnB,IAFA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,QAAQ,EAAK,GAAG,EAAE,CAAC,EACxD,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;;GAEnD,CAAC;EACH,CAAC;GAGS,UAA0B;CACrC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,uEACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAkC;GACnC,SAAS;GACT,iBAAiB;AAEf,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;;GAEnD,CAAC;EACH,CAAC;GAOS,KAAiB,IAA2B,EAAE,KAAK;CAC9D,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,CAAC,GAAG,EAAI,YAAY,EAAO;EACrC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAiB;;;YAI/B;GACE,aAAa,EAAO;GACpB,QAAQ,EAAO;GACf,YAAY,EAAO,cAAc;GAClC,EACD,EACD,EACa;EAEjB,CAAC;AACF,QAAO;EACL,GAAG;EACH,MAAM,EAAM,MAAM,SAAS,EAAE;EAC7B,UAAU,EAAM,MAAM;EACvB;GAMU,KAAgB,MAA2B;CACtD,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,EAAI,UAAU,KAAM,GAAG;EACjC,SAAS,EAAQ;EACjB,SAAS,YAAY;GACnB,IAAM,IAAS,MAAM,EACnB;;cAEM,EAAiB;iCACE,EAAe;;YAGxC,EAAE,OAAI,EACN,EACD;AACD,OAAI,CAAC,EAAO,aAAc,QAAO;GACjC,IAAM,EAAE,aAAU,GAAG,MAAS,EAAO;AACrC,UAAO;IAAE,GAAG;IAAM,UAAU,EAAS;IAAO;;EAE/C,CAAC;GAGS,UAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;gDACwC,EAAiB;YAEzD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAAwD;GACzD,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC;GACpE,CAAC;EACH,CAAC;GAGS,UAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;yDACiD,EAAiB;YAElE,GACA,EACD,EACa;EAEhB,GAAG,EAA+E;GAChF,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC,EAClD,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,EAAK,GAAG,EAAE,CAAC;;GAE7D,CAAC;EACH,CAAC;GAGS,UAA4B;CACvC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,2EACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAkC;GACnC,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC;GACpE,CAAC;EACH,CAAC;GAOS,KAAe,MAA2B;CACrD,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,CAAC,GAAG,EAAI,UAAU,EAAO;EACnC,SAAS,GAAQ,EAAO,aAAa,EAAO;EAC5C,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAe;;;YAI7B;GAAE,WAAW,EAAO;GAAW,aAAa,EAAO;GAAa,EAChE,EACD,EACa,gBAAgB;EAEjC,CAAC;AACF,QAAO;EAAE,GAAG;EAAO,MAAM,EAAM,QAAQ,EAAE;EAAE;GAGhC,UAAyB;CACpC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;8CACsC,EAAe;YAErD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAAoD;GACrD,SAAS;GACT,YAAY,MAAS;AAInB,IAHA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,QAAQ,EAAK,UAAU,EAAE,CAAC,EAC3D,EAAK,eAAa,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,EAAK,YAAY,EAAE,CAAC,EACzF,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;;GAEnD,CAAC;EACH,CAAC;GAGS,UAAyB;CACpC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;uDAC+C,EAAe;YAE9D,GACA,EACD,EACa;EAEhB,GAAG,EAA2E;GAC5E,SAAS;GACT,YAAY,MAAS;AAInB,IAHA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,QAAQ,EAAK,UAAU,EAAE,CAAC,EAC3D,EAAK,eAAa,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,EAAK,YAAY,EAAE,CAAC,EACzF,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;;GAEnD,CAAC;EACH,CAAC;GAGS,UAAyB;CACpC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,qEACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAkC;GACnC,SAAS;GACT,iBAAiB;AAIf,IAHA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC,EAClD,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;;GAEnD,CAAC;EACH,CAAC;GAkBE,IAA4B;IAC9B,GAAuB;0BACD,EAAwB;GAG5C,KAAyB,OAAiD;CAC9E,GAAG;CACH,aAAa,EAAE,YAAY;CAC5B,GAEY,UAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,EAAI;EACd,SAAS,aACQ,MAAM,EAGnB;;sBAEc,EAA0B;;;YAIxC,EAAE,EACF,EACD,EACa,uBAAuB,MAAM,IAAI,EAAsB;EAExE,CAAC;AACF,QAAO;EAAE,GAAG;EAAO,MAAM,EAAM,QAAQ,EAAE;EAAE;GAGhC,KAAqB,MAA2B;CAC3D,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,EAAI,eAAe,KAAM,GAAG;EACtC,SAAS,EAAQ;EACjB,SAAS,YAAY;GACnB,IAAM,IAAS,MAAM,EACnB;;cAEM,EAA0B;;YAGhC,EAAE,OAAI,EACN,EACD;AACD,UAAO,EAAO,oBAAoB,EAAsB,EAAO,kBAAkB,GAAG;;EAEvF,CAAC;GAGS,UAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,MAUV,GATQ,MAAM,EACnB;;cAEM,EAA0B;;YAGhC,EAAE,UAAO,EACT,EACD,EACmC,wBAAwB;EAE9D,GAAG,EAAkE;GACnE,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,iBAAiB,CAAC;GACzE,CAAC;EACH,CAAC;GAOS,KAAY,IAAsB,EAAE,KAAK;CACpD,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,CAAC,GAAG,EAAI,OAAO,EAAO;EAChC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAY;;;YAI1B;GACE,aAAa,EAAO;GACpB,QAAQ,EAAO;GACf,YAAY,EAAO,cAAc;GAClC,EACD,EACD,EACa;EAEjB,CAAC;AACF,QAAO;EACL,GAAG;EACH,MAAM,EAAM,MAAM,SAAS,EAAE;EAC7B,UAAU,EAAM,MAAM;EACvB;GAMU,KAAW,MAA2B;CACjD,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,EAAI,KAAK,KAAM,GAAG;EAC5B,SAAS,EAAQ;EACjB,SAAS,YAAY;GACnB,IAAM,IAAS,MAAM,EACnB;;cAEM,EAAY;iCACO,EAAoB;;YAG7C,EAAE,OAAI,EACN,EACD;AACD,OAAI,CAAC,EAAO,QAAS,QAAO;GAC5B,IAAM,EAAE,aAAU,GAAG,MAAS,EAAO;AACrC,UAAO;IAAE,GAAG;IAAM,UAAU,EAAS;IAAO;;EAE/C,CAAC;GAGS,KAAmB,MAA+B;CAC7D,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,EAAI,aAAa,KAAU,GAAG;EACxC,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAoB;;;YAIlC,EAAE,WAAQ,EACV,EACD,EACa,oBAAoB;EAErC,CAAC;AACF,QAAO;EAAE,GAAG;EAAO,MAAM,EAAM,QAAQ,EAAE;EAAE;GAGhC,UAAsB;CACjC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;2CACmC,EAAY;YAE/C,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAA8C;GAC/C,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,CAAC;GAC/D,CAAC;EACH,CAAC;GAGS,UAAsB;CACjC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;oDAC4C,EAAY;YAExD,GACA,EACD,EACa;EAEhB,GAAG,EAAqE;GACtE,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,CAAC,EAC7C,EAAG,kBAAkB,EAAE,UAAU,EAAI,KAAK,EAAK,GAAG,EAAE,CAAC;;GAExD,CAAC;EACH,CAAC;GAGS,UAAuB;CAClC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,iEACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAkC;GACnC,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,CAAC;GAC/D,CAAC;EACH,CAAC;GAGS,UAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;4EACoE,EAAY;YAEhF,GACA,EACD,EACa;EAEhB,GAAG,EAAgE;GACjE,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,CAAC,EAC7C,EAAG,kBAAkB,EAAE,UAAU,EAAI,KAAK,EAAK,GAAG,EAAE,CAAC;;GAExD,CAAC;EACH,CAAC;GAGS,UAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;gDACwC,EAAoB;YAE5D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAA0D;GAC3D,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,aAAa,EAAK,OAAO,EAAE,CAAC,EACjE,EAAG,kBAAkB,EAAE,UAAU,EAAI,KAAK,EAAK,OAAO,EAAE,CAAC;;GAE5D,CAAC;EACH,CAAC;GAGS,UAA6B;CACxC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,6EACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAkC;GACnC,SAAS;GACT,iBAAiB;AAIf,IAHA,EAAG,kBAAkB,EAAE,UAAU,EAAI,OAAO,CAAC,EAC7C,EAAG,kBAAkB,EAAE,UAAU,CAAC,GAAG,EAAI,MAAM,EAAE,CAAC,EAClD,EAAG,kBAAkB,EAAE,UAAU,CAAC,cAAc,gBAAgB,EAAE,CAAC,EACnE,EAAG,kBAAkB,EAAE,UAAU,CAAC,cAAc,OAAO,EAAE,CAAC;;GAE7D,CAAC;EACH,CAAC;GAOS,MAAiB,IAA2B,EAAE,KAAK;CAC9D,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,CAAC,GAAG,EAAI,YAAY,EAAO;EACrC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAiB;;;YAI/B;GAAE,QAAQ,EAAO;GAAQ,YAAY,EAAO,cAAc;GAAc,EACxE,EACD,EACa;EAEjB,CAAC;AACF,QAAO;EACL,GAAG;EACH,MAAM,EAAM,MAAM,SAAS,EAAE;EAC7B,UAAU,EAAM,MAAM;EACvB;GAGU,MAAgB,MAA2B;CACtD,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,EAAI,UAAU,KAAM,GAAG;EACjC,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;oCAC4B,EAAiB;YAE7C,EAAE,OAAI,EACN,EACD,EACa;EAEjB,CAAC;GAGS,WAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;gDACwC,EAAiB;YAEzD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAAwD;GACzD,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC;GACpE,CAAC;EACH,CAAC;GAGS,WAA2B;CACtC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;yDACiD,EAAiB;YAElE,GACA,EACD,EACa;EAEhB,GAAG,EAA+E;GAChF,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC,EAClD,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,EAAK,GAAG,EAAE,CAAC;;GAE7D,CAAC;EACH,CAAC;GAGS,WAA4B;CACvC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB,2EACA,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAkC;GACnC,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC;GACpE,CAAC;EACH,CAAC;GAOS,MAAe,IAAyB,EAAE,KAAK;CAC1D,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,CAAC,GAAG,EAAI,UAAU,EAAO;EACnC,SAAS,aACQ,MAAM,EACnB;;sBAEc,EAAe;;;YAI7B;GACE,UAAU,EAAO;GACjB,QAAQ,EAAO;GACf,WAAW,EAAO;GAClB,aAAa,EAAO;GACpB,YAAY,EAAO,cAAc;GAClC,EACD,EACD,EACa;EAEjB,CAAC;AACF,QAAO;EACL,GAAG;EACH,MAAM,EAAM,MAAM,SAAS,EAAE;EAC7B,UAAU,EAAM,MAAM;EACvB;GAqBU,WAAyB;CACpC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;8CACsC,EAAe;YAErD,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAAoD;GACrD,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;GAClE,CAAC;EACH,CAAC;GAGS,WAA8B;CACzC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;6CACqC,EAAe;YAEpD,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAqC;GACtC,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,QAAQ,EAAK,GAAG,EAAE,CAAC;;GAE3D,CAAC;EACH,CAAC;GAGS,WAA0B;CACrC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;yCACiC,EAAe;YAEhD,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAqC;GACtC,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,QAAQ,EAAK,GAAG,EAAE,CAAC;;GAE3D,CAAC;EACH,CAAC;GAGS,WAA0B;CACrC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;yCACiC,EAAe;YAEhD,EAAE,OAAI,EACN,EACD,EACa;EAEhB,GAAG,EAAqC;GACtC,SAAS;GACT,YAAY,MAAS;AAEnB,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,QAAQ,EAAK,GAAG,EAAE,CAAC;;GAE3D,CAAC;EACH,CAAC;GAOE,KAAqB,kDAQd,MAA2B,MAAoC;CAC1E,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,EAAI,YAAY,KAAe,GAAG;EAC5C,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;;;wBAGgB,GAAmB;;YAGnC,EAAE,gBAAa,EACf,EACD,EACa;EAEjB,CAAC;GAQS,WAAgC;CAC3C,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;iEACyD,EAAe;YAExE,EAAE,gBAAa,EACf,EACD,EACa;EAEhB,GAAG,EAAuC;GACxC,UAAU,MAAS,GAAG,EAAK,OAAO,eAAe,EAAK,WAAW,IAAI,KAAK,IAAI;GAC9E,YAAY,GAAO,MAAgB;AAEjC,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,EAAY,EAAE,CAAC;;GAEnE,CAAC;EACH,CAAC;GAUS,MAA2B,MAAoC;CAC1E,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,EAAI,YAAY,KAAe,GAAG;EAC5C,SAAS;EACT,SAAS,aACQ,MAAM,EACnB,+MAKA,EAAE,gBAAa,EACf,EACD,EACa;EAEjB,CAAC;GASE,KAA8B,+GAOvB,MACX,GACA,MACG;CACH,IAAM,EAAE,qBAAkB,GAAe;AACzC,QAAO,EAAS;EACd,UAAU,CAAC,GAAG,EAAI,qBAAqB,KAAe,GAAG,EAAE,EAAW;EACtE,SAAS,EAAQ;EACjB,SAAS,aACQ,MAAM,EACnB;;;;8BAIsB,GAA4B;;YAGlD;GAAE;GAAa,YAAY,KAAc;GAAM,EAC/C,EACD,EACa;EAEjB,CAAC;GAQS,WAAkC;CAC7C,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,EACjB,gBACA,qBAKe,MAAM,EACnB;4FACoF,EAAe;YAEnG;GAAE;GAAa,YAAY,KAAc;GAAM,EAC/C,EACD,EACa;EAEhB,GAAG,EAA2F;GAC5F,UAAU,MAAS,GAAG,EAAK,OAAO,mBAAmB,EAAK,WAAW,IAAI,KAAK,IAAI;GAClF,YAAY,GAAO,MAAS;AAE1B,IADA,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC,EAChD,EAAG,kBAAkB,EAAE,UAAU,EAAI,qBAAqB,EAAK,YAAY,EAAE,CAAC;;GAEjF,CAAC;EACH,CAAC;GAoCS,WAA6B;CACxC,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;kDAC0C,EAAmB;YAE7D,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAA4D;GAC7D,SAAS;GACT,YAAY,MAAS;AAGnB,IAFA,EAAG,kBAAkB,EAAE,UAAU,EAAI,cAAc,CAAC,EACpD,EAAG,kBAAkB,EAAE,UAAU,EAAI,QAAQ,EAAK,UAAU,EAAE,CAAC,EAC/D,EAAG,kBAAkB,EAAE,UAAU,EAAI,UAAU,CAAC;;GAEnD,CAAC;EACH,CAAC;GAOS,MAAyB,IAA2B,EAAE,KAAK;CACtE,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU,CAAC,GAAG,EAAI,YAAY,EAAO;EACrC,SAAS,aACQ,MAAM,EAGnB;;sBAEc,EAAiB;;;YAI/B;GACE,aAAa,EAAO;GACpB,aAAa,EAAO;GACpB,QAAQ,EAAO;GAChB,EACD,EACD,EACa,0BAA0B;EAE3C,CAAC;AACF,QAAO;EAAE,GAAG;EAAO,MAAM,EAAM,QAAQ,EAAE;EAAE;GAGhC,WAAmC;CAC9C,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;wDACgD,EAAiB;YAEjE,EAAE,UAAO,EACT,EACD,EACa;EAEhB,GAAG,EAAwE;GACzE,SAAS;GACT,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC;GACpE,CAAC;EACH,CAAC;GAGS,WAAuC;CAClD,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAK,GAAgB;AAC3B,QAAO,EAAY;EACjB,YAAY,OAAO,OACF,MAAM,EACnB;uEAC+D,EAAiB;YAEhF,GACA,EACD,EACa;EAEhB,GAAG,EAAmF;GACpF,UAAU,MAAS,aAAa,EAAK,OAAO,aAAa;GACzD,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAI,YAAY,CAAC;GACpE,CAAC;EACH,CAAC;;AAwCJ,SAAS,EAAsB,GAOR;CACrB,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAW,EAAO,YAAY,EAAa,SAAS,KACpD,IAAW,EAAiB;EAChC,UAAU,EAAO;EACjB,SAAS,EAAO,WAAW;EAC3B,kBAAkB;EAClB,SAAS,OAAO,EAAE,mBAAgB;GAChC,IAAM,IAA8B,IAChC;IAAE,OAAO;IAAU,QAAQ;IAAW,GACtC,EAAE,OAAO,GAAU,EACjB,IAAO,MAAM,EACjB,EAAO,OACP,EAAO,eAAe,EAAW,EACjC,EACD;AACD,UAAO,EAAO,OAAO,EAAK;;EAE5B,mBAAmB,MACjB,EAAK,SAAS,WAAW,EAAK,SAAS,SAAS,EAAK,SAAS,SAAS,KAAA;EAC1E,CAAC;AAEF,QAAO;EACL,QAAQ,EAAS,MAAM,SAAS,EAAE,EAAE,SAAS,MAAS,EAAK,MAAM;EACjE,SAAS,EAAQ,EAAS;EAC1B,gBAAgB;AACT,KAAS,eAAe;;EAE/B,WAAW,EAAS;EACpB,oBAAoB,EAAS;EAC7B,SAAS,EAAS;EAClB,eAAe;AACR,KAAS,SAAS;;EAE1B;;AAGH,IAAa,MAAoB,IAAyB,EAAE,KAC1D,EAA+B;CAC7B,UAAU;EAAC,GAAG,EAAI;EAAU;EAAS;EAAO;CAC5C,OAAO;;kBAEO,EAAe;;;;CAI7B,iBAAiB,OAAgB;EAC/B,aAAa,EAAO;EACpB,QAAQ,EAAO;EACf;EACD;CACD,SAAS,MAAU,EAAqD;CACzE,CAAC,EAES,MAAsB,IAA2B,EAAE,KAC9D,EAAiC;CAC/B,UAAU;EAAC,GAAG,EAAI;EAAY;EAAS;EAAO;CAC9C,OAAO;;kBAEO,EAAiB;;;;CAI/B,iBAAiB,OAAgB;EAC/B,aAAa,EAAO;EACpB,QAAQ,EAAO;EACf;EACD;CACD,SAAS,MAAU,EAAyD;CAC7E,CAAC,EAES,MAAiB,IAAsB,EAAE,KACpD,EAA4B;CAC1B,UAAU;EAAC,GAAG,EAAI;EAAO;EAAS;EAAO;CACzC,OAAO;;kBAEO,EAAY;;;;CAI1B,iBAAiB,OAAgB;EAC/B,aAAa,EAAO;EACpB,QAAQ,EAAO;EACf;EACD;CACD,SAAS,MAAU,EAA+C;CACnE,CAAC,EAES,MAAsB,IAA2B,EAAE,KAC9D,EAAiC;CAC/B,UAAU;EAAC,GAAG,EAAI;EAAY;EAAS;EAAO;CAC9C,OAAO;;kBAEO,EAAiB;;;;CAI/B,iBAAiB,OAAgB;EAAE,QAAQ,EAAO;EAAQ;EAAY;CACtE,SAAS,MAAU,EAAyD;CAC7E,CAAC,EAES,KAAoB,IAAyB,EAAE,KAC1D,EAA+B;CAC7B,UAAU;EAAC,GAAG,EAAI;EAAU;EAAS;EAAO;CAC5C,OAAO;;kBAEO,EAAe;;;;CAI7B,iBAAiB,OAAgB;EAC/B,UAAU,EAAO;EACjB,QAAQ,EAAO;EACf,WAAW,EAAO;EAClB,aAAa,EAAO;EACpB;EACD;CACD,SAAS,MAAU,EAAqD;CACzE,CAAC,EAES,MACX,IAA6B,EAAE,KAE/B,EAAmC;CACjC,UAAU;EAAC,GAAG,EAAI;EAAc;EAAS;EAAO;CAChD,OAAO;;kBAEO,EAAmB;;;;CAIjC,iBAAiB,OAAgB;EAC/B,WAAW,EAAO;EAClB,MAAM,EAAO;EACb;EACD;CACD,SAAS,MACN,EAA6D;CACjE,CAAC;AAOJ,eAAe,EACb,GACA,IAAW,KACX,IAAW,KACG;CACd,IAAM,IAAW,EAAE,EACf;AACJ,MAAK,IAAI,IAAI,GAAG,IAAI,GAAU,KAAK;EAEjC,IAAM,IAAa,MAAM,EADW,IAAS;GAAE,OAAO;GAAU;GAAQ,GAAG,EAAE,OAAO,GAAU,CAChD;AAE9C,MADA,EAAI,KAAK,GAAG,EAAW,MAAM,EACzB,CAAC,EAAW,SAAS,WAAW,CAAC,EAAW,SAAS,OAAQ;AACjE,MAAS,EAAW,SAAS;;AAE/B,QAAO;;AAIT,eAAsB,GACpB,GACA,IAAkD,EAAE,EACpD,IAAW,KACgB;AAC3B,QAAO,EAAmC,OAAO,OAClC,MAAM,EACjB;;oBAEc,EAAmB;;;UAIjC;EAAE,WAAW,EAAQ;EAAW,MAAM,EAAQ;EAAM;EAAY,EAChE,EACD,EACW,qBACX,EAAS;;AASd,eAAsB,GACpB,GACA,IAA0B,EAAE,EAC5B,IAAW,KACY;AACvB,QAAO,EAA+B,OAAO,OAC9B,MAAM,EACjB;;oBAEc,EAAe;;;UAI7B;EAAE,WAAW,EAAQ;EAAW,aAAa,EAAQ;EAAa;EAAY,EAC9E,EACD,EACW,iBACX,EAAS;;AAQd,IAAa,MAAsB,IAAkD,EAAE,KAAK;CAC1F,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU;GAAC,GAAG,EAAI;GAAc;GAAO;GAAQ;EAC/C,eAAe,GAAqB,GAAe,EAAQ;EAC5D,CAAC;AACF,QAAO;EAAE,GAAG;EAAO,MAAM,EAAM,QAAQ,EAAE;EAAE;;AAI7C,eAAsB,EACpB,GACA,IAA8C,EAAE,EAChD,IAAW,KACY;AACvB,QAAO,EAA+B,OAAO,OAC9B,MAAM,EACjB;;oBAEc,EAAe;;;UAI7B;EAAE,aAAa,EAAQ;EAAa,QAAQ,EAAQ;EAAQ;EAAY,EACxE,EACD,EACW,iBACX,EAAS;;AAUd,IAAa,MAAkB,IAA8C,EAAE,KAAK;CAClF,IAAM,EAAE,qBAAkB,GAAe,EACnC,IAAQ,EAAS;EACrB,UAAU;GAAC,GAAG,EAAI;GAAU;GAAO;GAAQ;EAC3C,eAAe,EAAiB,GAAe,EAAQ;EACxD,CAAC;AACF,QAAO;EAAE,GAAG;EAAO,MAAM,EAAM,QAAQ,EAAE;EAAE"}
|
|
1
|
+
{"version":3,"file":"useBrainyRichApi.js","names":[],"sources":["../../../src/brainyrich/hooks/useBrainyRichApi.ts"],"sourcesContent":["/**\n * BrainyRich API hooks\n * @module brainyrich/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-brainyrich-svc`\n * federated GraphQL contract (the `bra*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL (via `BrainyRichRootProps.apiGatewayUrl`,\n * threaded from `useBrainyRich()`) + a workspace-scoped token.\n */\n\nimport { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useBrainyRich } from '../providers/BrainyRichProvider';\nimport { notify, errorMessage } from '../components/notify';\nimport type {\n Connection,\n BraNetWorthSummary,\n BraAccount,\n BraAccountStatus,\n BraPortfolio,\n BraPortfolioStatus,\n BraHolding,\n BraModelPortfolio,\n BraModelAllocation,\n BraGoal,\n BraGoalStatus,\n BraGoalFunding,\n BraHousehold,\n BraHouseholdStatus,\n BraInsight,\n BraInsightSeverity,\n BraInsightStatus,\n BraTransaction,\n BraTransactionType,\n BraRebalanceProposal,\n BraRebalanceStatus,\n BraPortfolioRiskReport,\n BraRiskSummary,\n BraTaxLossReport,\n BraTaxLossThresholds,\n BraAdvisor,\n BraAdvisorRole,\n BraFirmReport,\n BraAdvisorBranding,\n BraUpsertAdvisorBrandingInput,\n BraClientPortalSummary,\n BraScheduledReport,\n BraReportRun,\n BraCreateScheduledReportInput,\n BraGenerateReportNowInput,\n BraMarketQuote,\n BraHoldingPriceRefreshResult,\n BraTradeInstruction,\n BraTradeInstructionStatus,\n BraCreateTradeInstructionInput,\n BraCreateAccountInput,\n BraUpdateAccountInput,\n BraCreatePortfolioInput,\n BraUpdatePortfolioInput,\n BraCreateHoldingInput,\n BraUpdateHoldingInput,\n BraCreateModelPortfolioInput,\n BraCreateGoalInput,\n BraUpdateGoalInput,\n BraLinkGoalFundingInput,\n BraCreateHouseholdInput,\n BraUpdateHouseholdInput,\n BraCreateInsightInput,\n BraCreateTransactionInput,\n BraCreateRebalanceProposalInput,\n PaginationInput,\n} from '../types/bra';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in an in-memory cache keyed\n * by operationName+variables for ~15s (mutations are never cached). A read issued\n * right after a write (e.g. the React-Query refetch our `invalidateQueries`\n * triggers) would otherwise return the PRE-mutation response until the TTL\n * expires — making just-created/updated rows invisible until a full reload.\n * fe-libs' documented remedy is that write-performing callers clear those caches;\n * we do exactly that after every bra mutation so every follow-up read is fresh.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\nconst braQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string,\n opts?: { suppressGlobalError?: boolean }\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n // When suppressed, fe-libs does NOT dispatch the global BACKEND_ERROR_EVENT\n // (which the host app-shell auto-toasts). Mutations suppress it so their\n // centralized `onError` (mutationFeedback) is the SINGLE toast source — no\n // double-toast against the shell listener. Reads leave it un-suppressed so a\n // failed read still drives the shell's connection indicator / error toast in\n // addition to the page's own ErrorState.\n suppressGlobalErrorEvent: opts?.suppressGlobalError ?? false,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n return response.data;\n};\n\n/**\n * Mutation transport — identical to `braQuery` but (a) suppresses the global\n * error event so mutation feedback is owned solely by the hooks' `onError`, and\n * (b) clears read caches after so follow-up reads are fresh.\n */\nconst braMutate = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const data = await braQuery<TData>(query, variables, baseUrl, { suppressGlobalError: true });\n clearGraphqlReadCaches();\n return data;\n};\n\n// ============================================================================\n// Centralized mutation feedback (fixes the silent-mutation-failure defect)\n// ============================================================================\n\n/**\n * Compose success/error toast feedback onto a React-Query mutation WITHOUT\n * discarding the hook's existing `onSuccess` side-effects (cache invalidation).\n *\n * - `onError` always fires `notify.error(<friendly message>)` — this is the one\n * place mutation failures surface, for every hook, so pages need no per-call\n * error handling.\n * - `onSuccess` runs the caller's invalidation first, then `notify.success`.\n *\n * Call-site handlers passed to `mutate(vars, { onSuccess, onError })` STILL run\n * (React-Query invokes both the hook-level and call-level callbacks), so pages\n * keep closing dialogs etc. on success.\n */\nfunction mutationFeedback<TData, TVars>(opts: {\n success?: string | ((data: TData, vars: TVars) => string);\n onSuccess?: (data: TData, vars: TVars) => void;\n}): {\n onSuccess: (data: TData, vars: TVars) => void;\n onError: (error: unknown) => void;\n} {\n return {\n onSuccess: (data, vars) => {\n opts.onSuccess?.(data, vars);\n if (opts.success) {\n notify.success(\n typeof opts.success === 'function' ? opts.success(data, vars) : opts.success\n );\n }\n },\n onError: (error) => notify.error(errorMessage(error)),\n };\n}\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n netWorth: ['brainyrich', 'net-worth'] as const,\n accounts: ['brainyrich', 'accounts'] as const,\n account: (id: string) => ['brainyrich', 'account', id] as const,\n portfolios: ['brainyrich', 'portfolios'] as const,\n portfolio: (id: string) => ['brainyrich', 'portfolio', id] as const,\n holdings: ['brainyrich', 'holdings'] as const,\n modelPortfolios: ['brainyrich', 'model-portfolios'] as const,\n modelPortfolio: (id: string) => ['brainyrich', 'model-portfolio', id] as const,\n goals: ['brainyrich', 'goals'] as const,\n goal: (id: string) => ['brainyrich', 'goal', id] as const,\n goalFundings: (goalId: string) => ['brainyrich', 'goal-fundings', goalId] as const,\n households: ['brainyrich', 'households'] as const,\n household: (id: string) => ['brainyrich', 'household', id] as const,\n insights: ['brainyrich', 'insights'] as const,\n insight: (id: string) => ['brainyrich', 'insight', id] as const,\n riskSignals: (portfolioId: string) => ['brainyrich', 'risk-signals', portfolioId] as const,\n riskSummary: (portfolioId: string) => ['brainyrich', 'risk-summary', portfolioId] as const,\n taxLossOpportunities: (portfolioId: string) =>\n ['brainyrich', 'tax-loss-opportunities', portfolioId] as const,\n transactions: ['brainyrich', 'transactions'] as const,\n rebalances: ['brainyrich', 'rebalance-proposals'] as const,\n health: ['brainyrich', 'health'] as const,\n myAdvisorProfile: ['brainyrich', 'my-advisor-profile'] as const,\n advisors: ['brainyrich', 'advisors'] as const,\n firmReport: ['brainyrich', 'firm-report'] as const,\n myAdvisorBranding: ['brainyrich', 'my-advisor-branding'] as const,\n clientPortalSummary: ['brainyrich', 'client-portal-summary'] as const,\n scheduledReports: ['brainyrich', 'scheduled-reports'] as const,\n reportRuns: (scheduledReportId?: string) =>\n ['brainyrich', 'report-runs', scheduledReportId ?? 'all'] as const,\n marketQuote: (symbol: string) => ['brainyrich', 'market-quote', symbol] as const,\n tradeInstructions: (portfolioId?: string, status?: BraTradeInstructionStatus) =>\n ['brainyrich', 'trade-instructions', portfolioId ?? 'all', status ?? 'all'] as const,\n};\n\n/** Gateway is offset-based; OMIT `cursor` on the first page. */\nconst DEFAULT_PAGE: PaginationInput = { limit: 50 };\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness — mirror bra.ts)\n// ============================================================================\n\nconst HOLDING_FIELDS = `\n id workspaceId accountId portfolioId symbol name assetClass quantity lastPrice\n costBasis marketValue currency asOf createdAt updatedAt\n`;\n\nconst TRANSACTION_FIELDS = `\n id workspaceId accountId holdingId type symbol quantity price amount fee currency\n tradeDate settleDate notes createdAt updatedAt\n`;\n\nconst ACCOUNT_FIELDS = `\n id workspaceId ownerId householdId name type status institution accountMask\n cashBalance currency isManual createdAt updatedAt\n`;\n\nconst PORTFOLIO_FIELDS = `\n id workspaceId ownerId householdId name description status baseCurrency\n modelPortfolioId driftThresholdPct targetAllocation tags createdAt updatedAt\n`;\n\nconst MODEL_ALLOCATION_FIELDS = `\n id workspaceId modelPortfolioId assetClass targetPct createdAt updatedAt\n`;\n\nconst MODEL_PORTFOLIO_FIELDS = `\n id workspaceId name description riskProfile baseCurrency isActive createdAt updatedAt\n`;\n\nconst GOAL_FUNDING_FIELDS = `\n id workspaceId goalId accountId allocationPct fixedAmount createdAt updatedAt\n`;\n\nconst GOAL_FIELDS = `\n id workspaceId ownerId householdId name type status projection targetAmount\n targetDate monthlyContribution priority currency notes tags createdAt updatedAt\n`;\n\nconst HOUSEHOLD_FIELDS = `\n id workspaceId name status riskProfile advisorId aum currency primaryContactName\n primaryContactEmail notes tags createdAt updatedAt\n`;\n\nconst INSIGHT_FIELDS = `\n id workspaceId ownerId type severity status title detail metrics subjectId\n subjectType acknowledgedById resolvedAt createdAt updatedAt\n`;\n\nconst REBALANCE_FIELDS = `\n id workspaceId portfolioId householdId status driftPct rationale trades\n proposedById approvedById executedAt createdAt updatedAt\n`;\n\nconst NET_WORTH_FIELDS = `\n workspaceId ownerId totalNetWorth totalMarketValue totalCash accountCount currency\n byAssetClass { assetClass marketValue }\n`;\n\n// ============================================================================\n// Filter param shapes (exported so page agents can type their call sites)\n// ============================================================================\n\nexport interface AccountFilters {\n householdId?: string;\n status?: BraAccountStatus;\n pagination?: PaginationInput;\n}\n\nexport interface PortfolioFilters {\n householdId?: string;\n status?: BraPortfolioStatus;\n pagination?: PaginationInput;\n}\n\nexport interface HoldingFilters {\n accountId?: string;\n portfolioId?: string;\n}\n\nexport interface GoalFilters {\n householdId?: string;\n status?: BraGoalStatus;\n pagination?: PaginationInput;\n}\n\nexport interface HouseholdFilters {\n status?: BraHouseholdStatus;\n pagination?: PaginationInput;\n}\n\nexport interface InsightFilters {\n severity?: BraInsightSeverity;\n status?: BraInsightStatus;\n subjectId?: string;\n subjectType?: string;\n pagination?: PaginationInput;\n}\n\nexport interface TransactionFilters {\n accountId?: string;\n type?: BraTransactionType;\n pagination?: PaginationInput;\n}\n\nexport interface RebalanceFilters {\n householdId?: string;\n portfolioId?: string;\n status?: BraRebalanceStatus;\n}\n\n// ============================================================================\n// Health\n// ============================================================================\n\nexport const useBraHealth = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.health,\n queryFn: async () => {\n const result = await braQuery<{ braHealth: string }>(\n `query BraHealth { braHealth }`,\n {},\n apiGatewayUrl\n );\n return result.braHealth;\n },\n });\n};\n\n// ============================================================================\n// Net worth (Overview)\n// ============================================================================\n\nexport const useNetWorthSummary = (ownerId?: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: [...KEY.netWorth, ownerId ?? 'me'],\n queryFn: async () => {\n const result = await braQuery<{ braNetWorthSummary: BraNetWorthSummary }>(\n `query BraNetWorthSummary($ownerId: ID) {\n braNetWorthSummary(ownerId: $ownerId) { ${NET_WORTH_FIELDS} }\n }`,\n { ownerId },\n apiGatewayUrl\n );\n return result.braNetWorthSummary;\n },\n });\n};\n\n// ============================================================================\n// Accounts\n// ============================================================================\n\nexport const useAccounts = (params: AccountFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.accounts, params],\n queryFn: async () => {\n const result = await braQuery<{ braListAccounts: Connection<BraAccount> }>(\n `query BraListAccounts($householdId: ID, $status: BraAccountStatus, $pagination: PaginationInput) {\n braListAccounts(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${ACCOUNT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n status: params.status,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListAccounts;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\n/** Raw wire shape for `braAccount`: nested `holdings`/`transactions` are Connections. */\ntype BraAccountWire = Omit<BraAccount, 'holdings' | 'transactions'> & {\n holdings: Connection<BraHolding>;\n transactions: Connection<BraTransaction>;\n};\n\nexport const useAccount = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.account(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braAccount: BraAccountWire | null }>(\n `query BraAccount($id: ID!) {\n braAccount(id: $id) {\n ${ACCOUNT_FIELDS}\n holdings { items { ${HOLDING_FIELDS} } pageInfo { cursor hasMore } }\n transactions { items { ${TRANSACTION_FIELDS} } pageInfo { cursor hasMore } }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n if (!result.braAccount) return null;\n const { holdings, transactions, ...rest } = result.braAccount;\n return { ...rest, holdings: holdings.items, transactions: transactions.items } as BraAccount;\n },\n });\n};\n\nexport const useCreateAccount = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateAccountInput) => {\n const result = await braMutate<{ braCreateAccount: BraAccount }>(\n `mutation BraCreateAccount($input: BraCreateAccountInput!) {\n braCreateAccount(input: $input) { ${ACCOUNT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateAccount;\n },\n ...mutationFeedback<BraAccount, BraCreateAccountInput>({\n success: 'Account created',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useUpdateAccount = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateAccountInput }) => {\n const result = await braMutate<{ braUpdateAccount: BraAccount }>(\n `mutation BraUpdateAccount($id: ID!, $input: BraUpdateAccountInput!) {\n braUpdateAccount(id: $id, input: $input) { ${ACCOUNT_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateAccount;\n },\n ...mutationFeedback<BraAccount, { id: string; input: BraUpdateAccountInput }>({\n success: 'Account updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.account(data.id) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useArchiveAccount = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchiveAccount: boolean }>(\n `mutation BraArchiveAccount($id: ID!) { braArchiveAccount(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchiveAccount;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Account archived',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\n// ============================================================================\n// Portfolios\n// ============================================================================\n\nexport const usePortfolios = (params: PortfolioFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.portfolios, params],\n queryFn: async () => {\n const result = await braQuery<{ braListPortfolios: Connection<BraPortfolio> }>(\n `query BraListPortfolios($householdId: ID, $status: BraPortfolioStatus, $pagination: PaginationInput) {\n braListPortfolios(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${PORTFOLIO_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n status: params.status,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListPortfolios;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\n/** Raw wire shape for `braPortfolio`: nested `holdings` is a Connection. */\ntype BraPortfolioWire = Omit<BraPortfolio, 'holdings'> & { holdings: Connection<BraHolding> };\n\nexport const usePortfolio = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.portfolio(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braPortfolio: BraPortfolioWire | null }>(\n `query BraPortfolio($id: ID!) {\n braPortfolio(id: $id) {\n ${PORTFOLIO_FIELDS}\n holdings { items { ${HOLDING_FIELDS} } pageInfo { cursor hasMore } }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n if (!result.braPortfolio) return null;\n const { holdings, ...rest } = result.braPortfolio;\n return { ...rest, holdings: holdings.items } as BraPortfolio;\n },\n });\n};\n\nexport const useCreatePortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreatePortfolioInput) => {\n const result = await braMutate<{ braCreatePortfolio: BraPortfolio }>(\n `mutation BraCreatePortfolio($input: BraCreatePortfolioInput!) {\n braCreatePortfolio(input: $input) { ${PORTFOLIO_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreatePortfolio;\n },\n ...mutationFeedback<BraPortfolio, BraCreatePortfolioInput>({\n success: 'Portfolio created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.portfolios }),\n }),\n });\n};\n\nexport const useUpdatePortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdatePortfolioInput }) => {\n const result = await braMutate<{ braUpdatePortfolio: BraPortfolio }>(\n `mutation BraUpdatePortfolio($id: ID!, $input: BraUpdatePortfolioInput!) {\n braUpdatePortfolio(id: $id, input: $input) { ${PORTFOLIO_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdatePortfolio;\n },\n ...mutationFeedback<BraPortfolio, { id: string; input: BraUpdatePortfolioInput }>({\n success: 'Portfolio updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.portfolios });\n qc.invalidateQueries({ queryKey: KEY.portfolio(data.id) });\n },\n }),\n });\n};\n\nexport const useArchivePortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchivePortfolio: boolean }>(\n `mutation BraArchivePortfolio($id: ID!) { braArchivePortfolio(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchivePortfolio;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Portfolio archived',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.portfolios }),\n }),\n });\n};\n\n// ============================================================================\n// Holdings\n// ============================================================================\n\nexport const useHoldings = (params: HoldingFilters) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.holdings, params],\n enabled: Boolean(params.accountId || params.portfolioId),\n queryFn: async () => {\n const result = await braQuery<{ braListHoldings: Connection<BraHolding> }>(\n `query BraListHoldings($accountId: ID, $portfolioId: ID) {\n braListHoldings(accountId: $accountId, portfolioId: $portfolioId) {\n items { ${HOLDING_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { accountId: params.accountId, portfolioId: params.portfolioId },\n apiGatewayUrl\n );\n return result.braListHoldings.items;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateHolding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateHoldingInput) => {\n const result = await braMutate<{ braCreateHolding: BraHolding }>(\n `mutation BraCreateHolding($input: BraCreateHoldingInput!) {\n braCreateHolding(input: $input) { ${HOLDING_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateHolding;\n },\n ...mutationFeedback<BraHolding, BraCreateHoldingInput>({\n success: 'Holding added',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.holdings });\n qc.invalidateQueries({ queryKey: KEY.account(data.accountId) });\n if (data.portfolioId) qc.invalidateQueries({ queryKey: KEY.portfolio(data.portfolioId) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useUpdateHolding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateHoldingInput }) => {\n const result = await braMutate<{ braUpdateHolding: BraHolding }>(\n `mutation BraUpdateHolding($id: ID!, $input: BraUpdateHoldingInput!) {\n braUpdateHolding(id: $id, input: $input) { ${HOLDING_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateHolding;\n },\n ...mutationFeedback<BraHolding, { id: string; input: BraUpdateHoldingInput }>({\n success: 'Holding updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.holdings });\n qc.invalidateQueries({ queryKey: KEY.account(data.accountId) });\n if (data.portfolioId) qc.invalidateQueries({ queryKey: KEY.portfolio(data.portfolioId) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\nexport const useDeleteHolding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braDeleteHolding: boolean }>(\n `mutation BraDeleteHolding($id: ID!) { braDeleteHolding(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braDeleteHolding;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Holding removed',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.holdings });\n qc.invalidateQueries({ queryKey: KEY.accounts });\n qc.invalidateQueries({ queryKey: KEY.portfolios });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\n// ============================================================================\n// Model portfolios\n// ============================================================================\n\n/**\n * Raw wire shape for `BraModelPortfolio`: nested `allocations` is a Connection\n * (`BraModelAllocationConnection`), same as `braListModelPortfolios` itself\n * (`BraModelPortfolioConnection`) — both need an `items`/`pageInfo` selection,\n * flattened to a plain array at the hook boundary so pages keep working with\n * `BraModelPortfolio[]` / `BraModelAllocation[]`.\n */\ntype BraModelPortfolioWire = Omit<BraModelPortfolio, 'allocations'> & {\n allocations: Connection<BraModelAllocation>;\n};\n\nconst MODEL_PORTFOLIO_SELECTION = `\n ${MODEL_PORTFOLIO_FIELDS}\n allocations { items { ${MODEL_ALLOCATION_FIELDS} } pageInfo { cursor hasMore } }\n`;\n\nconst flattenModelPortfolio = (m: BraModelPortfolioWire): BraModelPortfolio => ({\n ...m,\n allocations: m.allocations.items,\n});\n\nexport const useModelPortfolios = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.modelPortfolios,\n queryFn: async () => {\n const result = await braQuery<{\n braListModelPortfolios: Connection<BraModelPortfolioWire>;\n }>(\n `query BraListModelPortfolios {\n braListModelPortfolios {\n items { ${MODEL_PORTFOLIO_SELECTION} }\n pageInfo { cursor hasMore }\n }\n }`,\n {},\n apiGatewayUrl\n );\n return result.braListModelPortfolios.items.map(flattenModelPortfolio);\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useModelPortfolio = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.modelPortfolio(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braModelPortfolio: BraModelPortfolioWire | null }>(\n `query BraModelPortfolio($id: ID!) {\n braModelPortfolio(id: $id) {\n ${MODEL_PORTFOLIO_SELECTION}\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braModelPortfolio ? flattenModelPortfolio(result.braModelPortfolio) : null;\n },\n });\n};\n\nexport const useCreateModelPortfolio = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateModelPortfolioInput) => {\n const result = await braMutate<{ braCreateModelPortfolio: BraModelPortfolioWire }>(\n `mutation BraCreateModelPortfolio($input: BraCreateModelPortfolioInput!) {\n braCreateModelPortfolio(input: $input) {\n ${MODEL_PORTFOLIO_SELECTION}\n }\n }`,\n { input },\n apiGatewayUrl\n );\n return flattenModelPortfolio(result.braCreateModelPortfolio);\n },\n ...mutationFeedback<BraModelPortfolio, BraCreateModelPortfolioInput>({\n success: 'Model portfolio created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.modelPortfolios }),\n }),\n });\n};\n\n// ============================================================================\n// Goals\n// ============================================================================\n\nexport const useGoals = (params: GoalFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.goals, params],\n queryFn: async () => {\n const result = await braQuery<{ braListGoals: Connection<BraGoal> }>(\n `query BraListGoals($householdId: ID, $status: BraGoalStatus, $pagination: PaginationInput) {\n braListGoals(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${GOAL_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n status: params.status,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListGoals;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\n/** Raw wire shape for `braGoal`: nested `fundings` is a Connection. */\ntype BraGoalWire = Omit<BraGoal, 'fundings'> & { fundings: Connection<BraGoalFunding> };\n\nexport const useGoal = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.goal(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braGoal: BraGoalWire | null }>(\n `query BraGoal($id: ID!) {\n braGoal(id: $id) {\n ${GOAL_FIELDS}\n fundings { items { ${GOAL_FUNDING_FIELDS} } pageInfo { cursor hasMore } }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n if (!result.braGoal) return null;\n const { fundings, ...rest } = result.braGoal;\n return { ...rest, fundings: fundings.items } as BraGoal;\n },\n });\n};\n\nexport const useGoalFundings = (goalId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.goalFundings(goalId ?? ''),\n enabled: Boolean(goalId),\n queryFn: async () => {\n const result = await braQuery<{ braListGoalFundings: Connection<BraGoalFunding> }>(\n `query BraListGoalFundings($goalId: ID!) {\n braListGoalFundings(goalId: $goalId) {\n items { ${GOAL_FUNDING_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { goalId },\n apiGatewayUrl\n );\n return result.braListGoalFundings.items;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateGoal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateGoalInput) => {\n const result = await braMutate<{ braCreateGoal: BraGoal }>(\n `mutation BraCreateGoal($input: BraCreateGoalInput!) {\n braCreateGoal(input: $input) { ${GOAL_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateGoal;\n },\n ...mutationFeedback<BraGoal, BraCreateGoalInput>({\n success: 'Goal created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.goals }),\n }),\n });\n};\n\nexport const useUpdateGoal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateGoalInput }) => {\n const result = await braMutate<{ braUpdateGoal: BraGoal }>(\n `mutation BraUpdateGoal($id: ID!, $input: BraUpdateGoalInput!) {\n braUpdateGoal(id: $id, input: $input) { ${GOAL_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateGoal;\n },\n ...mutationFeedback<BraGoal, { id: string; input: BraUpdateGoalInput }>({\n success: 'Goal updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.goals });\n qc.invalidateQueries({ queryKey: KEY.goal(data.id) });\n },\n }),\n });\n};\n\nexport const useArchiveGoal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchiveGoal: boolean }>(\n `mutation BraArchiveGoal($id: ID!) { braArchiveGoal(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchiveGoal;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Goal archived',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.goals }),\n }),\n });\n};\n\nexport const useRecalcGoalProjection = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; fundedAmount: number }) => {\n const result = await braMutate<{ braRecalcGoalProjection: BraGoal }>(\n `mutation BraRecalcGoalProjection($id: ID!, $fundedAmount: Float!) {\n braRecalcGoalProjection(id: $id, fundedAmount: $fundedAmount) { ${GOAL_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braRecalcGoalProjection;\n },\n ...mutationFeedback<BraGoal, { id: string; fundedAmount: number }>({\n success: 'Projection recalculated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.goals });\n qc.invalidateQueries({ queryKey: KEY.goal(data.id) });\n },\n }),\n });\n};\n\nexport const useLinkGoalFunding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraLinkGoalFundingInput) => {\n const result = await braMutate<{ braLinkGoalFunding: BraGoalFunding }>(\n `mutation BraLinkGoalFunding($input: BraLinkGoalFundingInput!) {\n braLinkGoalFunding(input: $input) { ${GOAL_FUNDING_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braLinkGoalFunding;\n },\n ...mutationFeedback<BraGoalFunding, BraLinkGoalFundingInput>({\n success: 'Funding linked',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.goalFundings(data.goalId) });\n qc.invalidateQueries({ queryKey: KEY.goal(data.goalId) });\n },\n }),\n });\n};\n\nexport const useUnlinkGoalFunding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braUnlinkGoalFunding: boolean }>(\n `mutation BraUnlinkGoalFunding($id: ID!) { braUnlinkGoalFunding(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braUnlinkGoalFunding;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Funding unlinked',\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.goals });\n qc.invalidateQueries({ queryKey: [...KEY.goals] });\n qc.invalidateQueries({ queryKey: ['brainyrich', 'goal-fundings'] });\n qc.invalidateQueries({ queryKey: ['brainyrich', 'goal'] });\n },\n }),\n });\n};\n\n// ============================================================================\n// Households\n// ============================================================================\n\nexport const useHouseholds = (params: HouseholdFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.households, params],\n queryFn: async () => {\n const result = await braQuery<{ braListHouseholds: Connection<BraHousehold> }>(\n `query BraListHouseholds($status: BraHouseholdStatus, $pagination: PaginationInput) {\n braListHouseholds(status: $status, pagination: $pagination) {\n items { ${HOUSEHOLD_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status: params.status, pagination: params.pagination ?? DEFAULT_PAGE },\n apiGatewayUrl\n );\n return result.braListHouseholds;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\nexport const useHousehold = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.household(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braHousehold: BraHousehold | null }>(\n `query BraHousehold($id: ID!) {\n braHousehold(id: $id) { ${HOUSEHOLD_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braHousehold;\n },\n });\n};\n\nexport const useCreateHousehold = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateHouseholdInput) => {\n const result = await braMutate<{ braCreateHousehold: BraHousehold }>(\n `mutation BraCreateHousehold($input: BraCreateHouseholdInput!) {\n braCreateHousehold(input: $input) { ${HOUSEHOLD_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateHousehold;\n },\n ...mutationFeedback<BraHousehold, BraCreateHouseholdInput>({\n success: 'Household created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.households }),\n }),\n });\n};\n\nexport const useUpdateHousehold = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; input: BraUpdateHouseholdInput }) => {\n const result = await braMutate<{ braUpdateHousehold: BraHousehold }>(\n `mutation BraUpdateHousehold($id: ID!, $input: BraUpdateHouseholdInput!) {\n braUpdateHousehold(id: $id, input: $input) { ${HOUSEHOLD_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braUpdateHousehold;\n },\n ...mutationFeedback<BraHousehold, { id: string; input: BraUpdateHouseholdInput }>({\n success: 'Household updated',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.households });\n qc.invalidateQueries({ queryKey: KEY.household(data.id) });\n },\n }),\n });\n};\n\nexport const useArchiveHousehold = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braArchiveHousehold: boolean }>(\n `mutation BraArchiveHousehold($id: ID!) { braArchiveHousehold(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.braArchiveHousehold;\n },\n ...mutationFeedback<boolean, string>({\n success: 'Household archived',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.households }),\n }),\n });\n};\n\n// ============================================================================\n// Insights\n// ============================================================================\n\nexport const useInsights = (params: InsightFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.insights, params],\n queryFn: async () => {\n const result = await braQuery<{ braListInsights: Connection<BraInsight> }>(\n `query BraListInsights($severity: BraInsightSeverity, $status: BraInsightStatus, $subjectId: ID, $subjectType: String, $pagination: PaginationInput) {\n braListInsights(severity: $severity, status: $status, subjectId: $subjectId, subjectType: $subjectType, pagination: $pagination) {\n items { ${INSIGHT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n severity: params.severity,\n status: params.status,\n subjectId: params.subjectId,\n subjectType: params.subjectType,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListInsights;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\nexport const useInsight = (id: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.insight(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await braQuery<{ braInsight: BraInsight | null }>(\n `query BraInsight($id: ID!) {\n braInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braInsight;\n },\n });\n};\n\nexport const useCreateInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateInsightInput) => {\n const result = await braMutate<{ braCreateInsight: BraInsight }>(\n `mutation BraCreateInsight($input: BraCreateInsightInput!) {\n braCreateInsight(input: $input) { ${INSIGHT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateInsight;\n },\n ...mutationFeedback<BraInsight, BraCreateInsightInput>({\n success: 'Insight created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.insights }),\n }),\n });\n};\n\nexport const useAcknowledgeInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braAcknowledgeInsight: BraInsight }>(\n `mutation BraAcknowledgeInsight($id: ID!) {\n braAcknowledgeInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braAcknowledgeInsight;\n },\n ...mutationFeedback<BraInsight, string>({\n success: 'Insight acknowledged',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.insight(data.id) });\n },\n }),\n });\n};\n\nexport const useDismissInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braDismissInsight: BraInsight }>(\n `mutation BraDismissInsight($id: ID!) {\n braDismissInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braDismissInsight;\n },\n ...mutationFeedback<BraInsight, string>({\n success: 'Insight dismissed',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.insight(data.id) });\n },\n }),\n });\n};\n\nexport const useResolveInsight = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await braMutate<{ braResolveInsight: BraInsight }>(\n `mutation BraResolveInsight($id: ID!) {\n braResolveInsight(id: $id) { ${INSIGHT_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.braResolveInsight;\n },\n ...mutationFeedback<BraInsight, string>({\n success: 'Insight resolved',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.insight(data.id) });\n },\n }),\n });\n};\n\n// ============================================================================\n// Risk signals (BOFF-4236) — deterministic engine + optional AI summary\n// ============================================================================\n\nconst RISK_SIGNAL_FIELDS = `kind insightType severity title detail metrics`;\n\n/**\n * Real, explainable risk signals computed live from the portfolio's own\n * holdings/allocation data — every signal carries its formula/threshold under\n * `metrics`. Read-only; nothing is persisted until `useGenerateRiskInsights`\n * is called. Disabled until a portfolio is selected.\n */\nexport const usePortfolioRiskSignals = (portfolioId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.riskSignals(portfolioId ?? ''),\n enabled: Boolean(portfolioId),\n queryFn: async () => {\n const result = await braQuery<{ braPortfolioRiskSignals: BraPortfolioRiskReport }>(\n `query BraPortfolioRiskSignals($portfolioId: ID!) {\n braPortfolioRiskSignals(portfolioId: $portfolioId) {\n portfolioId workspaceId asOf totalValue holdingsConsidered\n signals { ${RISK_SIGNAL_FIELDS} }\n }\n }`,\n { portfolioId },\n apiGatewayUrl\n );\n return result.braPortfolioRiskSignals;\n },\n });\n};\n\n/**\n * Persists the currently-computed signals as `BraInsight` rows (idempotent —\n * re-running updates the existing OPEN insight of the same kind). Refreshes\n * both the signals report and the shared insights list on success.\n */\nexport const useGenerateRiskInsights = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (portfolioId: string) => {\n const result = await braMutate<{ braGenerateRiskInsights: BraInsight[] }>(\n `mutation BraGenerateRiskInsights($portfolioId: ID!) {\n braGenerateRiskInsights(portfolioId: $portfolioId) { ${INSIGHT_FIELDS} }\n }`,\n { portfolioId },\n apiGatewayUrl\n );\n return result.braGenerateRiskInsights;\n },\n ...mutationFeedback<BraInsight[], string>({\n success: (data) => `${data.length} risk insight${data.length === 1 ? '' : 's'} recorded`,\n onSuccess: (_data, portfolioId) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.riskSignals(portfolioId) });\n },\n }),\n });\n};\n\n/**\n * OPTIONAL LLM-generated plain-language restatement of the already-computed\n * signals — never the source of the numbers itself. `generated: false` +\n * `reason` when no provider key is configured; the deterministic signals\n * above always work regardless. Fetched on-demand (`refetch`), not on mount,\n * since it invokes an LLM call.\n */\nexport const usePortfolioRiskSummary = (portfolioId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.riskSummary(portfolioId ?? ''),\n enabled: false,\n queryFn: async () => {\n const result = await braQuery<{ braPortfolioRiskSummary: BraRiskSummary }>(\n `query BraPortfolioRiskSummary($portfolioId: ID!) {\n braPortfolioRiskSummary(portfolioId: $portfolioId) {\n generated summary provider reason signalsConsidered\n }\n }`,\n { portfolioId },\n apiGatewayUrl\n );\n return result.braPortfolioRiskSummary;\n },\n });\n};\n\n// ============================================================================\n// Tax-loss-harvesting opportunities (BOFF-4237) — configurable thresholds +\n// wash-sale caution flag, distinct from the generic TAX_LOSS_HARVEST signal\n// inside the risk engine above.\n// ============================================================================\n\nconst TAX_LOSS_OPPORTUNITY_FIELDS = `symbol marketValue costBasis unrealizedLoss lossPctOfPortfolio severity washSaleRisk washSaleReason metrics`;\n\n/**\n * Preview-only: real tax-loss-harvesting opportunities for one portfolio,\n * computed live with the given (or documented default) thresholds. Never\n * persists anything — see `useHarvestTaxLossInsights` for that.\n */\nexport const useTaxLossOpportunities = (\n portfolioId: string | undefined,\n thresholds?: BraTaxLossThresholds\n) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: [...KEY.taxLossOpportunities(portfolioId ?? ''), thresholds],\n enabled: Boolean(portfolioId),\n queryFn: async () => {\n const result = await braQuery<{ braTaxLossOpportunities: BraTaxLossReport }>(\n `query BraTaxLossOpportunities($portfolioId: ID!, $thresholds: BraTaxLossThresholdInput) {\n braTaxLossOpportunities(portfolioId: $portfolioId, thresholds: $thresholds) {\n portfolioId workspaceId asOf\n thresholds { minLossAmount minLossPct }\n opportunities { ${TAX_LOSS_OPPORTUNITY_FIELDS} }\n }\n }`,\n { portfolioId, thresholds: thresholds ?? null },\n apiGatewayUrl\n );\n return result.braTaxLossOpportunities;\n },\n });\n};\n\n/**\n * Persists the currently-computed tax-loss opportunities as `BraInsight`\n * rows (type TAX_OPPORTUNITY, idempotent per symbol). Detection/flagging\n * only — never executes a trade.\n */\nexport const useHarvestTaxLossInsights = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async ({\n portfolioId,\n thresholds,\n }: {\n portfolioId: string;\n thresholds?: BraTaxLossThresholds;\n }) => {\n const result = await braMutate<{ braHarvestTaxLossInsights: BraInsight[] }>(\n `mutation BraHarvestTaxLossInsights($portfolioId: ID!, $thresholds: BraTaxLossThresholdInput) {\n braHarvestTaxLossInsights(portfolioId: $portfolioId, thresholds: $thresholds) { ${INSIGHT_FIELDS} }\n }`,\n { portfolioId, thresholds: thresholds ?? null },\n apiGatewayUrl\n );\n return result.braHarvestTaxLossInsights;\n },\n ...mutationFeedback<BraInsight[], { portfolioId: string; thresholds?: BraTaxLossThresholds }>({\n success: (data) => `${data.length} tax-loss insight${data.length === 1 ? '' : 's'} recorded`,\n onSuccess: (_data, vars) => {\n qc.invalidateQueries({ queryKey: KEY.insights });\n qc.invalidateQueries({ queryKey: KEY.taxLossOpportunities(vars.portfolioId) });\n },\n }),\n });\n};\n\n// ============================================================================\n// Transactions\n// ============================================================================\n\nexport const useTransactions = (params: TransactionFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.transactions, params],\n queryFn: async () => {\n const result = await braQuery<{ braListTransactions: Connection<BraTransaction> }>(\n `query BraListTransactions($accountId: ID, $type: BraTransactionType, $pagination: PaginationInput) {\n braListTransactions(accountId: $accountId, type: $type, pagination: $pagination) {\n items { ${TRANSACTION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n accountId: params.accountId,\n type: params.type,\n pagination: params.pagination ?? DEFAULT_PAGE,\n },\n apiGatewayUrl\n );\n return result.braListTransactions;\n },\n });\n return {\n ...query,\n data: query.data?.items ?? [],\n pageInfo: query.data?.pageInfo,\n };\n};\n\nexport const useRecordTransaction = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateTransactionInput) => {\n const result = await braMutate<{ braRecordTransaction: BraTransaction }>(\n `mutation BraRecordTransaction($input: BraCreateTransactionInput!) {\n braRecordTransaction(input: $input) { ${TRANSACTION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braRecordTransaction;\n },\n ...mutationFeedback<BraTransaction, BraCreateTransactionInput>({\n success: 'Transaction recorded',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.transactions });\n qc.invalidateQueries({ queryKey: KEY.account(data.accountId) });\n qc.invalidateQueries({ queryKey: KEY.netWorth });\n },\n }),\n });\n};\n\n// ============================================================================\n// Rebalance proposals\n// ============================================================================\n\nexport const useRebalanceProposals = (params: RebalanceFilters = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.rebalances, params],\n queryFn: async () => {\n const result = await braQuery<{\n braListRebalanceProposals: Connection<BraRebalanceProposal>;\n }>(\n `query BraListRebalanceProposals($householdId: ID, $portfolioId: ID, $status: BraRebalanceStatus) {\n braListRebalanceProposals(householdId: $householdId, portfolioId: $portfolioId, status: $status) {\n items { ${REBALANCE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n householdId: params.householdId,\n portfolioId: params.portfolioId,\n status: params.status,\n },\n apiGatewayUrl\n );\n return result.braListRebalanceProposals.items;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateRebalanceProposal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateRebalanceProposalInput) => {\n const result = await braMutate<{ braCreateRebalanceProposal: BraRebalanceProposal }>(\n `mutation BraCreateRebalanceProposal($input: BraCreateRebalanceProposalInput!) {\n braCreateRebalanceProposal(input: $input) { ${REBALANCE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateRebalanceProposal;\n },\n ...mutationFeedback<BraRebalanceProposal, BraCreateRebalanceProposalInput>({\n success: 'Rebalance proposal created',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.rebalances }),\n }),\n });\n};\n\nexport const useTransitionRebalanceProposal = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; status: BraRebalanceStatus }) => {\n const result = await braMutate<{ braTransitionRebalanceProposal: BraRebalanceProposal }>(\n `mutation BraTransitionRebalanceProposal($id: ID!, $status: BraRebalanceStatus!) {\n braTransitionRebalanceProposal(id: $id, status: $status) { ${REBALANCE_FIELDS} }\n }`,\n vars,\n apiGatewayUrl\n );\n return result.braTransitionRebalanceProposal;\n },\n ...mutationFeedback<BraRebalanceProposal, { id: string; status: BraRebalanceStatus }>({\n success: (data) => `Rebalance ${data.status.toLowerCase()}`,\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.rebalances }),\n }),\n });\n};\n\n// ============================================================================\n// Pagination — \"load more\" for list pages + full-set pagers for aggregations\n// ============================================================================\n//\n// Every `braList*` connection returns `pageInfo { cursor hasMore }`. The gateway\n// is offset-based, so the FIRST page must OMIT `cursor` (explicit null → 500);\n// subsequent pages pass the previous page's `pageInfo.cursor`. Both helpers\n// below honor that rule.\n//\n// • `usePaged*` — incremental \"load more\" for interactive lists. Returns\n// a FLAT `items` array plus `hasMore` / `loadMore`,\n// pairs with the `<LoadMore/>` component.\n// • `fetchAll* / useAll*` — page through to `hasMore === false` so AGGREGATION\n// pages (Analytics net-cash-flow, Tax realized proceeds,\n// Reports ledger) compute over the FULL set, never a\n// truncated first 100.\n\nexport interface PagedListResult<T> {\n /** Flattened items across every fetched page. */\n items: T[];\n /** Another page exists. */\n hasMore: boolean;\n /** Fetch the next page (appends to `items`). */\n loadMore: () => void;\n /** First page in flight. */\n isLoading: boolean;\n /** A subsequent page in flight (drive the `<LoadMore/>` spinner off this). */\n isFetchingNextPage: boolean;\n isError: boolean;\n refetch: () => void;\n}\n\n/**\n * Generic cursor-accumulating list hook built on React-Query `useInfiniteQuery`.\n * Concrete `usePaged*` wrappers below supply the query + variables; page agents\n * consume those, not this directly.\n */\nfunction usePagedConnection<T>(config: {\n queryKey: readonly unknown[];\n query: string;\n buildVariables: (pagination: PaginationInput) => Record<string, unknown>;\n select: (data: unknown) => Connection<T>;\n enabled?: boolean;\n pageSize?: number;\n}): PagedListResult<T> {\n const { apiGatewayUrl } = useBrainyRich();\n const pageSize = config.pageSize ?? DEFAULT_PAGE.limit ?? 100;\n const infinite = useInfiniteQuery({\n queryKey: config.queryKey,\n enabled: config.enabled ?? true,\n initialPageParam: null as string | null,\n queryFn: async ({ pageParam }) => {\n const pagination: PaginationInput = pageParam\n ? { limit: pageSize, cursor: pageParam }\n : { limit: pageSize };\n const data = await braQuery<unknown>(\n config.query,\n config.buildVariables(pagination),\n apiGatewayUrl\n );\n return config.select(data);\n },\n getNextPageParam: (last) =>\n last.pageInfo.hasMore && last.pageInfo.cursor ? last.pageInfo.cursor : undefined,\n });\n\n return {\n items: (infinite.data?.pages ?? []).flatMap((page) => page.items),\n hasMore: Boolean(infinite.hasNextPage),\n loadMore: () => {\n void infinite.fetchNextPage();\n },\n isLoading: infinite.isLoading,\n isFetchingNextPage: infinite.isFetchingNextPage,\n isError: infinite.isError,\n refetch: () => {\n void infinite.refetch();\n },\n };\n}\n\nexport const usePagedAccounts = (params: AccountFilters = {}): PagedListResult<BraAccount> =>\n usePagedConnection<BraAccount>({\n queryKey: [...KEY.accounts, 'paged', params],\n query: `query BraListAccounts($householdId: ID, $status: BraAccountStatus, $pagination: PaginationInput) {\n braListAccounts(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${ACCOUNT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n householdId: params.householdId,\n status: params.status,\n pagination,\n }),\n select: (data) => (data as { braListAccounts: Connection<BraAccount> }).braListAccounts,\n });\n\nexport const usePagedPortfolios = (params: PortfolioFilters = {}): PagedListResult<BraPortfolio> =>\n usePagedConnection<BraPortfolio>({\n queryKey: [...KEY.portfolios, 'paged', params],\n query: `query BraListPortfolios($householdId: ID, $status: BraPortfolioStatus, $pagination: PaginationInput) {\n braListPortfolios(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${PORTFOLIO_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n householdId: params.householdId,\n status: params.status,\n pagination,\n }),\n select: (data) => (data as { braListPortfolios: Connection<BraPortfolio> }).braListPortfolios,\n });\n\nexport const usePagedGoals = (params: GoalFilters = {}): PagedListResult<BraGoal> =>\n usePagedConnection<BraGoal>({\n queryKey: [...KEY.goals, 'paged', params],\n query: `query BraListGoals($householdId: ID, $status: BraGoalStatus, $pagination: PaginationInput) {\n braListGoals(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${GOAL_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n householdId: params.householdId,\n status: params.status,\n pagination,\n }),\n select: (data) => (data as { braListGoals: Connection<BraGoal> }).braListGoals,\n });\n\nexport const usePagedHouseholds = (params: HouseholdFilters = {}): PagedListResult<BraHousehold> =>\n usePagedConnection<BraHousehold>({\n queryKey: [...KEY.households, 'paged', params],\n query: `query BraListHouseholds($status: BraHouseholdStatus, $pagination: PaginationInput) {\n braListHouseholds(status: $status, pagination: $pagination) {\n items { ${HOUSEHOLD_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({ status: params.status, pagination }),\n select: (data) => (data as { braListHouseholds: Connection<BraHousehold> }).braListHouseholds,\n });\n\nexport const usePagedInsights = (params: InsightFilters = {}): PagedListResult<BraInsight> =>\n usePagedConnection<BraInsight>({\n queryKey: [...KEY.insights, 'paged', params],\n query: `query BraListInsights($severity: BraInsightSeverity, $status: BraInsightStatus, $subjectId: ID, $subjectType: String, $pagination: PaginationInput) {\n braListInsights(severity: $severity, status: $status, subjectId: $subjectId, subjectType: $subjectType, pagination: $pagination) {\n items { ${INSIGHT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n severity: params.severity,\n status: params.status,\n subjectId: params.subjectId,\n subjectType: params.subjectType,\n pagination,\n }),\n select: (data) => (data as { braListInsights: Connection<BraInsight> }).braListInsights,\n });\n\nexport const usePagedTransactions = (\n params: TransactionFilters = {}\n): PagedListResult<BraTransaction> =>\n usePagedConnection<BraTransaction>({\n queryKey: [...KEY.transactions, 'paged', params],\n query: `query BraListTransactions($accountId: ID, $type: BraTransactionType, $pagination: PaginationInput) {\n braListTransactions(accountId: $accountId, type: $type, pagination: $pagination) {\n items { ${TRANSACTION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n buildVariables: (pagination) => ({\n accountId: params.accountId,\n type: params.type,\n pagination,\n }),\n select: (data) =>\n (data as { braListTransactions: Connection<BraTransaction> }).braListTransactions,\n });\n\n// ----------------------------------------------------------------------------\n// Full-set pagers (aggregation)\n// ----------------------------------------------------------------------------\n\n/** Page through a connection until `hasMore === false`, returning every item. */\nasync function fetchAllConnection<T>(\n fetchPage: (pagination: PaginationInput) => Promise<Connection<T>>,\n pageSize = 200,\n maxPages = 500\n): Promise<T[]> {\n const all: T[] = [];\n let cursor: string | null | undefined;\n for (let i = 0; i < maxPages; i++) {\n const pagination: PaginationInput = cursor ? { limit: pageSize, cursor } : { limit: pageSize };\n const connection = await fetchPage(pagination);\n all.push(...connection.items);\n if (!connection.pageInfo.hasMore || !connection.pageInfo.cursor) break;\n cursor = connection.pageInfo.cursor;\n }\n return all;\n}\n\n/** Fetch EVERY transaction matching `filters` (all pages). */\nexport async function fetchAllTransactions(\n apiGatewayUrl: string | undefined,\n filters: Omit<TransactionFilters, 'pagination'> = {},\n pageSize = 200\n): Promise<BraTransaction[]> {\n return fetchAllConnection<BraTransaction>(async (pagination) => {\n const data = await braQuery<{ braListTransactions: Connection<BraTransaction> }>(\n `query BraListTransactions($accountId: ID, $type: BraTransactionType, $pagination: PaginationInput) {\n braListTransactions(accountId: $accountId, type: $type, pagination: $pagination) {\n items { ${TRANSACTION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { accountId: filters.accountId, type: filters.type, pagination },\n apiGatewayUrl\n );\n return data.braListTransactions;\n }, pageSize);\n}\n\n/**\n * Fetch EVERY holding matching `filters` (all pages). `braListHoldings` is a\n * paginated `BraHoldingConnection` (default page size 50) like every other\n * `braList*` field, so a single un-paginated call silently truncates accounts\n * holding more than one page of positions — page through it fully here.\n */\nexport async function fetchAllHoldings(\n apiGatewayUrl: string | undefined,\n filters: HoldingFilters = {},\n pageSize = 200\n): Promise<BraHolding[]> {\n return fetchAllConnection<BraHolding>(async (pagination) => {\n const data = await braQuery<{ braListHoldings: Connection<BraHolding> }>(\n `query BraListHoldings($accountId: ID, $portfolioId: ID, $pagination: PaginationInput) {\n braListHoldings(accountId: $accountId, portfolioId: $portfolioId, pagination: $pagination) {\n items { ${HOLDING_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { accountId: filters.accountId, portfolioId: filters.portfolioId, pagination },\n apiGatewayUrl\n );\n return data.braListHoldings;\n }, pageSize);\n}\n\n/**\n * Aggregation-ready hook: ALL transactions matching `filters`. Use on Analytics\n * (net-cash-flow), Tax (realized proceeds) and Reports (ledger) so totals are\n * computed over the complete set rather than a truncated first page.\n */\nexport const useAllTransactions = (filters: Omit<TransactionFilters, 'pagination'> = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.transactions, 'all', filters],\n queryFn: () => fetchAllTransactions(apiGatewayUrl, filters),\n });\n return { ...query, data: query.data ?? [] };\n};\n\n/** Fetch EVERY account matching `filters` (all pages). */\nexport async function fetchAllAccounts(\n apiGatewayUrl: string | undefined,\n filters: Omit<AccountFilters, 'pagination'> = {},\n pageSize = 200\n): Promise<BraAccount[]> {\n return fetchAllConnection<BraAccount>(async (pagination) => {\n const data = await braQuery<{ braListAccounts: Connection<BraAccount> }>(\n `query BraListAccounts($householdId: ID, $status: BraAccountStatus, $pagination: PaginationInput) {\n braListAccounts(householdId: $householdId, status: $status, pagination: $pagination) {\n items { ${ACCOUNT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { householdId: filters.householdId, status: filters.status, pagination },\n apiGatewayUrl\n );\n return data.braListAccounts;\n }, pageSize);\n}\n\n/**\n * Aggregation-ready hook: ALL accounts matching `filters`. `braListHoldings`\n * IS paginated (`BraHoldingConnection`, default page size 50) like every\n * other `braList*` field — callers reading holdings per-account/portfolio via\n * `useHoldings`/`useAccount`/`usePortfolio` should page through it for\n * accounts that can hold more than one page of positions.\n */\nexport const useAllAccounts = (filters: Omit<AccountFilters, 'pagination'> = {}) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: [...KEY.accounts, 'all', filters],\n queryFn: () => fetchAllAccounts(apiGatewayUrl, filters),\n });\n return { ...query, data: query.data ?? [] };\n};\n\n// ============================================================================\n// BOFF-4247 — Firm roster + firm-wide reporting\n// ============================================================================\n\nconst ADVISOR_FIELDS = `\n id workspaceId userId role status displayName email invitedById createdAt updatedAt\n`;\n\n/** The calling actor's own firm-roster row, or null if they haven't registered yet. */\nexport const useMyAdvisorProfile = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.myAdvisorProfile,\n queryFn: async () => {\n const result = await braQuery<{ braMyAdvisorProfile: BraAdvisor | null }>(\n `query BraMyAdvisorProfile { braMyAdvisorProfile { ${ADVISOR_FIELDS} } }`,\n {},\n apiGatewayUrl\n );\n return result.braMyAdvisorProfile;\n },\n });\n};\n\nexport interface BraEnsureAdvisorInput {\n userId?: string;\n role?: BraAdvisorRole;\n displayName?: string;\n email?: string;\n}\n\n/** Registers/updates the calling actor's own roster row. First row in a workspace self-registers as FIRM_ADMIN. */\nexport const useEnsureAdvisorProfile = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraEnsureAdvisorInput) => {\n const result = await braMutate<{ braEnsureAdvisorProfile: BraAdvisor }>(\n `mutation BraEnsureAdvisorProfile($input: BraEnsureAdvisorInput!) {\n braEnsureAdvisorProfile(input: $input) { ${ADVISOR_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braEnsureAdvisorProfile;\n },\n ...mutationFeedback<BraAdvisor, BraEnsureAdvisorInput>({\n success: (data) => `${data.displayName ?? data.userId} is on the firm roster as ${data.role}`,\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.myAdvisorProfile });\n qc.invalidateQueries({ queryKey: KEY.advisors });\n },\n }),\n });\n};\n\n/** Full firm roster. FIRM_ADMIN only — server enforces via domain data, not a separate RBAC role. */\nexport const useAdvisors = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.advisors,\n queryFn: async () => {\n const result = await braQuery<{ braListAdvisors: BraAdvisor[] }>(\n `query BraListAdvisors { braListAdvisors { ${ADVISOR_FIELDS} } }`,\n {},\n apiGatewayUrl\n );\n return result.braListAdvisors;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useSetAdvisorRole = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async ({ userId, role }: { userId: string; role: BraAdvisorRole }) => {\n const result = await braMutate<{ braSetAdvisorRole: BraAdvisor }>(\n `mutation BraSetAdvisorRole($userId: ID!, $role: BraAdvisorRole!) {\n braSetAdvisorRole(userId: $userId, role: $role) { ${ADVISOR_FIELDS} }\n }`,\n { userId, role },\n apiGatewayUrl\n );\n return result.braSetAdvisorRole;\n },\n ...mutationFeedback<BraAdvisor, { userId: string; role: BraAdvisorRole }>({\n success: (data) => `Role updated to ${data.role}`,\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.advisors }),\n }),\n });\n};\n\n/** Firm-wide aggregate AUM + per-advisor breakdown. FIRM_ADMIN only. */\nexport const useFirmReport = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.firmReport,\n queryFn: async () => {\n const result = await braQuery<{ braFirmReport: BraFirmReport }>(\n `query BraFirmReport {\n braFirmReport {\n workspaceId asOf totalAdvisors totalHouseholds totalAum currency\n byAdvisor { advisorId displayName email role householdCount aum }\n }\n }`,\n {},\n apiGatewayUrl\n );\n return result.braFirmReport;\n },\n // Not every workspace member is a FIRM_ADMIN — a 403 here is an expected,\n // non-retryable outcome for plain advisors/investors, not a transient fault.\n retry: false,\n });\n};\n\n// ============================================================================\n// BOFF-4244 — Advisor branding + branded client portal + scheduled reporting\n// ============================================================================\n\nconst ADVISOR_BRANDING_FIELDS = `\n id workspaceId advisorId firmName logoFileId primaryColor secondaryColor\n contactEmail disclaimer createdAt updatedAt\n`;\n\n/** The calling advisor's own client-portal branding, or null if not yet configured. */\nexport const useMyAdvisorBranding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.myAdvisorBranding,\n queryFn: async () => {\n const result = await braQuery<{ braMyAdvisorBranding: BraAdvisorBranding | null }>(\n `query BraMyAdvisorBranding { braMyAdvisorBranding { ${ADVISOR_BRANDING_FIELDS} } }`,\n {},\n apiGatewayUrl\n );\n return result.braMyAdvisorBranding;\n },\n });\n};\n\nexport const useUpsertMyAdvisorBranding = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraUpsertAdvisorBrandingInput) => {\n const result = await braMutate<{ braUpsertMyAdvisorBranding: BraAdvisorBranding }>(\n `mutation BraUpsertMyAdvisorBranding($input: BraUpsertAdvisorBrandingInput!) {\n braUpsertMyAdvisorBranding(input: $input) { ${ADVISOR_BRANDING_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braUpsertMyAdvisorBranding;\n },\n ...mutationFeedback<BraAdvisorBranding, BraUpsertAdvisorBrandingInput>({\n success: 'Client-portal branding saved',\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.myAdvisorBranding }),\n }),\n });\n};\n\n/** The calling client's own portfolio summary, branded with their advisor's client-portal branding. */\nexport const useClientPortalSummary = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.clientPortalSummary,\n queryFn: async () => {\n const result = await braQuery<{ braClientPortalSummary: BraClientPortalSummary }>(\n `query BraClientPortalSummary {\n braClientPortalSummary {\n ownerId asOf totalNetWorth totalCash holdingsMarketValue currency advisorId\n branding { firmName logoFileId primaryColor secondaryColor contactEmail disclaimer }\n }\n }`,\n {},\n apiGatewayUrl\n );\n return result.braClientPortalSummary;\n },\n });\n};\n\nconst SCHEDULED_REPORT_FIELDS = `\n id workspaceId advisorId householdId name frequency status lastRunAt nextRunAt createdAt updatedAt\n`;\n\nconst REPORT_RUN_FIELDS = `\n id workspaceId scheduledReportId advisorId householdId status periodStart periodEnd\n errorMessage generatedAt notifiedAt createdAt\n`;\n\nexport const useScheduledReports = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.scheduledReports,\n queryFn: async () => {\n const result = await braQuery<{ braListScheduledReports: BraScheduledReport[] }>(\n `query BraListScheduledReports { braListScheduledReports { ${SCHEDULED_REPORT_FIELDS} } }`,\n {},\n apiGatewayUrl\n );\n return result.braListScheduledReports;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateScheduledReport = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateScheduledReportInput) => {\n const result = await braMutate<{ braCreateScheduledReport: BraScheduledReport }>(\n `mutation BraCreateScheduledReport($input: BraCreateScheduledReportInput!) {\n braCreateScheduledReport(input: $input) { ${SCHEDULED_REPORT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateScheduledReport;\n },\n ...mutationFeedback<BraScheduledReport, BraCreateScheduledReportInput>({\n success: (data) => `\"${data.name}\" scheduled (${data.frequency.toLowerCase()})`,\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.scheduledReports }),\n }),\n });\n};\n\nexport const useSetScheduledReportStatus = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async ({ id, pause }: { id: string; pause: boolean }) => {\n const op = pause ? 'BraPauseScheduledReport' : 'BraResumeScheduledReport';\n const field = pause ? 'braPauseScheduledReport' : 'braResumeScheduledReport';\n const result = await braMutate<Record<string, BraScheduledReport>>(\n `mutation ${op}($id: ID!) { ${field}(id: $id) { ${SCHEDULED_REPORT_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return result[field] as BraScheduledReport;\n },\n ...mutationFeedback<BraScheduledReport, { id: string; pause: boolean }>({\n success: (data) => (data.status === 'PAUSED' ? 'Schedule paused' : 'Schedule resumed'),\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.scheduledReports }),\n }),\n });\n};\n\nexport const useReportRuns = (scheduledReportId?: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.reportRuns(scheduledReportId),\n queryFn: async () => {\n const result = await braQuery<{ braListReportRuns: BraReportRun[] }>(\n `query BraListReportRuns($scheduledReportId: ID) {\n braListReportRuns(scheduledReportId: $scheduledReportId) { ${REPORT_RUN_FIELDS} }\n }`,\n { scheduledReportId: scheduledReportId ?? null },\n apiGatewayUrl\n );\n return result.braListReportRuns;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\n/** Generates a report run now (same real render path a due schedule uses) and dispatches an in-app \"report ready\" notification. */\nexport const useGenerateReportNow = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraGenerateReportNowInput) => {\n const result = await braMutate<{ braGenerateReportNow: BraReportRun }>(\n `mutation BraGenerateReportNow($input: BraGenerateReportNowInput!) {\n braGenerateReportNow(input: $input) { ${REPORT_RUN_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braGenerateReportNow;\n },\n ...mutationFeedback<BraReportRun, BraGenerateReportNowInput>({\n success: 'Report is generating — a \"report ready\" notification will follow',\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.reportRuns(data.scheduledReportId ?? undefined) });\n qc.invalidateQueries({ queryKey: KEY.reportRuns(undefined) });\n qc.invalidateQueries({ queryKey: KEY.scheduledReports });\n },\n }),\n });\n};\n\n/** Real, regenerated-on-demand PDF for one report run, base64-encoded. Fetched on demand (not a cached query) — triggers a download. */\nexport async function downloadReportRunPdf(\n apiGatewayUrl: string | undefined,\n runId: string,\n filename: string\n): Promise<void> {\n const result = await braQuery<{ braReportRunPdf: string }>(\n `query BraReportRunPdf($id: ID!) { braReportRunPdf(id: $id) }`,\n { id: runId },\n apiGatewayUrl\n );\n const base64 = result.braReportRunPdf;\n const byteChars = atob(base64);\n const bytes = new Uint8Array(byteChars.length);\n for (let i = 0; i < byteChars.length; i += 1) {\n bytes[i] = byteChars.charCodeAt(i);\n }\n const blob = new Blob([bytes], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n}\n\nexport const useDownloadReportRunPdf = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useMutation({\n mutationFn: async (run: BraReportRun) =>\n downloadReportRunPdf(apiGatewayUrl, run.id, `brainyrich-report-${run.id}.pdf`),\n ...mutationFeedback<void, BraReportRun>({ success: 'PDF downloaded' }),\n });\n};\n\n// ============================================================================\n// BOFF-4257 — Real market-data feed + trade instructions (recommendation only)\n// ============================================================================\n\n/** A real, live current quote for one symbol from a public market-data feed. Manual/on-demand — not auto-polled. */\nexport const useMarketQuote = (symbol: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: KEY.marketQuote(symbol ?? ''),\n enabled: false,\n queryFn: async () => {\n const result = await braQuery<{ braMarketQuote: BraMarketQuote }>(\n `query BraMarketQuote($symbol: String!) {\n braMarketQuote(symbol: $symbol) { symbol price currency asOf source }\n }`,\n { symbol },\n apiGatewayUrl\n );\n return result.braMarketQuote;\n },\n });\n};\n\n/** Refreshes every holding's lastPrice in one account from real live quotes. */\nexport const useRefreshHoldingPrices = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (accountId: string) => {\n const result = await braMutate<{ braRefreshHoldingPrices: BraHoldingPriceRefreshResult }>(\n `mutation BraRefreshHoldingPrices($accountId: ID!) {\n braRefreshHoldingPrices(accountId: $accountId) {\n accountId\n updated { holdingId symbol previousPrice newPrice }\n failed { symbol reason }\n }\n }`,\n { accountId },\n apiGatewayUrl\n );\n return result.braRefreshHoldingPrices;\n },\n ...mutationFeedback<BraHoldingPriceRefreshResult, string>({\n success: (data) =>\n data.failed.length > 0\n ? `${data.updated.length} price(s) refreshed, ${data.failed.length} failed`\n : `${data.updated.length} price(s) refreshed`,\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: KEY.holdings });\n qc.invalidateQueries({ queryKey: KEY.accounts });\n },\n }),\n });\n};\n\nconst TRADE_INSTRUCTION_FIELDS = `\n id workspaceId portfolioId accountId symbol action quantity referencePrice priceSource\n priceAsOf status source rationale reviewedById reviewedAt createdAt updatedAt\n`;\n\n/** BUY/SELL recommendations for a human advisor to review — never an execution record. */\nexport const useTradeInstructions = (portfolioId?: string, status?: BraTradeInstructionStatus) => {\n const { apiGatewayUrl } = useBrainyRich();\n const query = useQuery({\n queryKey: KEY.tradeInstructions(portfolioId, status),\n queryFn: async () => {\n const result = await braQuery<{ braListTradeInstructions: BraTradeInstruction[] }>(\n `query BraListTradeInstructions($portfolioId: ID, $status: BraTradeInstructionStatus) {\n braListTradeInstructions(portfolioId: $portfolioId, status: $status) { ${TRADE_INSTRUCTION_FIELDS} }\n }`,\n { portfolioId: portfolioId ?? null, status: status ?? null },\n apiGatewayUrl\n );\n return result.braListTradeInstructions;\n },\n });\n return { ...query, data: query.data ?? [] };\n};\n\nexport const useCreateTradeInstruction = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BraCreateTradeInstructionInput) => {\n const result = await braMutate<{ braCreateTradeInstruction: BraTradeInstruction }>(\n `mutation BraCreateTradeInstruction($input: BraCreateTradeInstructionInput!) {\n braCreateTradeInstruction(input: $input) { ${TRADE_INSTRUCTION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.braCreateTradeInstruction;\n },\n ...mutationFeedback<BraTradeInstruction, BraCreateTradeInstructionInput>({\n success: (data) => `${data.action} ${data.quantity} ${data.symbol} instruction created`,\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.tradeInstructions(data.portfolioId) });\n qc.invalidateQueries({ queryKey: KEY.tradeInstructions(undefined) });\n },\n }),\n });\n};\n\n/** A human advisor marking an instruction reviewed. status must be ACKNOWLEDGED or DISMISSED — no execute transition exists. */\nexport const useReviewTradeInstruction = () => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async ({\n id,\n status,\n }: {\n id: string;\n status: Extract<BraTradeInstructionStatus, 'ACKNOWLEDGED' | 'DISMISSED'>;\n }) => {\n const result = await braMutate<{ braReviewTradeInstruction: BraTradeInstruction }>(\n `mutation BraReviewTradeInstruction($id: ID!, $status: BraTradeInstructionStatus!) {\n braReviewTradeInstruction(id: $id, status: $status) { ${TRADE_INSTRUCTION_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.braReviewTradeInstruction;\n },\n ...mutationFeedback<\n BraTradeInstruction,\n { id: string; status: Extract<BraTradeInstructionStatus, 'ACKNOWLEDGED' | 'DISMISSED'> }\n >({\n success: (data) => `Instruction marked ${data.status.toLowerCase()}`,\n onSuccess: (data) => {\n qc.invalidateQueries({ queryKey: KEY.tradeInstructions(data.portfolioId) });\n qc.invalidateQueries({ queryKey: KEY.tradeInstructions(undefined) });\n },\n }),\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FirmPage.d.ts","sourceRoot":"","sources":["../../../src/brainyrich/pages/FirmPage.tsx"],"names":[],"mappings":"AA8DA,wBAAgB,QAAQ,4CAiIvB"}
|