fix(hooks): follow-up exhaustive-deps fixes + useSipConnection duplicate body - #590
Conversation
…ken exposto Documenta procedimento de rotação de: token MCP Supabase (crítico), service_role key, anon key, JWT secret, Evolution API key, Portainer token e GitHub PAT. Inclui inventário de consumidores e tabela de acompanhamento pós-incidente. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Instala gitleaks v8.21.2, usa .gitleaks.toml existente; PR → delta apenas, push → histórico completo. Saída SARIF enviada para Code Scanning do GitHub. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Claude, Copilot, Lovable e dependabot devem chegar via PR. O workflow detecta commits AI-autored fora de PR merges e falha o pipeline com mensagem clara. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
… staging E11: documento de avaliação de impacto LGPD com linha do tempo, dados afetados, riscos e checklist ANPD (72h). E12: .env.staging template + STAGING-ENVIRONMENT.md com topologia, setup Supabase/Vercel e fluxo de deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
E17: branch-protection-sentinel agora verifica via API do GitHub (cron diário) se force pushes, dismiss_stale e required_checks continuam configurados. E18: BRANCH-PROTECTION-CONFIG.md documenta os 5 status checks a adicionar manualmente via GitHub Settings (ci/lockfile, quality, test, build, quality-gate). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Roda a suíte completa 3x sem retry toda noite (seg-sex, 03h UTC) para medir estabilidade real. Falhas em 1-2/3 passadas = flakiness; 3/3 = falha real. Resultados arquivados por 14 dias. continue-on-error=true para não bloquear main. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
8 timestamps duplicados detectados (16 arquivos). Migrations já em main/produção não podem ser renomeadas sem UPDATE em schema_migrations — documenta o procedimento seguro e o motivo pelo qual a renomeação cega causaria re-aplicação. CI gate já previne novos duplicados (migration-uniqueness.yml desde commit a79b011). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
E22: Replace xlsx CDN tarball URL with npm registry version 0.18.5 to eliminate supply chain attack vector via untrusted CDN source. E23: Remove jsdom (vitest uses happy-dom), @vitejs/plugin-react (project uses -swc variant), @storybook/addon-essentials and @storybook/addon-interactions (no v10 on npm; consolidated into individual addons already listed in devDependencies). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
… plan E27: Document 945-migration squash strategy with partial baseline freeze at 20260700000000 cutpoint — covers pg_dump procedure, schema_migrations UPDATE, staging validation criteria, and risk matrix. E28: Document unification of 11 infra/migrations/ files into supabase/migrations/ with idempotency review and schema_migrations INSERT procedure so new environments (staging, preview) apply them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…tes, realtime inventory E30: Add clean-build.yml - weekly Saturday CI run without bun cache to verify reproducible build from zero (frozen-lockfile + full test + build). E31: Upgrade schema-drift.yml from manual-only to include static-drift PR gate that blocks DDL outside supabase/migrations/ without needing DB access. Live-drift job preserved for manual/workflow_dispatch with DATABASE_URL. E32: Create .gitattributes with merge=ours for types.ts and bun.lock to prevent merge conflicts on auto-generated files; binary file declarations. E33: Document all 34 realtime channel subscriptions with publication status, source files, and smoke test SQL queries. Identifies 4 channels needing verification (email_revalidation_jobs, provider_message_log, security_audit_logs, team_conversations). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
350+ tables with RLS enabled, zero with DISABLE, documented patterns for zapp/evo/financeiro/vendas. Includes production verification SQL to identify tables missing policies. References existing RLS docs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…nstraint - Create zapp.is_public_url(url TEXT) IMMUTABLE SECURITY INVOKER function - Add chk_profile_pic_url_public constraint to evo.evolution_contacts - Add chk_contatos_profile_pic_url_public constraint to zapp.contatos - Idempotent backfill replaces remaining internal URLs with production host - DO blocks with IF EXISTS guards make migration safe to re-run Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Callers that did supabase.storage.from(bucket).getPublicUrl(path) directly bypassed sanitizeMediaUrl(), leaving a gap in the kong:8000 defense. resolvePublicStorageUrl(bucket, path) builds the URL via resolveMediaUrl() and passes it through sanitizeMediaUrl() in one call, matching the ADR-001 rule that URL construction must happen exclusively in mediaUrl.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
… proxies zapp.profiles and zapp.user_roles are the physical tables. public.profiles / public.user_roles are VIEW proxies and never emit CDC events, so the subscriptions were silent no-ops — profile/role changes never triggered live refresh in the browser. Fixes: - schema: 'public' → schema: 'zapp' for both channels - profiles filter: id=eq. → user_id=eq. (profiles.user_id is the auth UID; profiles.id is a surrogate key, per the 2026-07-17 DB audit) - Migration 20260726000200 adds both tables to supabase_realtime publication Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Composes CORS preflight, Sentry init, request-ID injection, timing header
(x-response-time), and structured 500 JSON error into a single decorator.
Before: each function duplicated handleCors + initSentry + try/catch + baseHeaders.
After: Deno.serve(withEdgeHandler('fn-name', async (req, ctx) => { ... }))
ctx.requestId and ctx.startedAt available in every handler.
Sentry captureException fires on unhandled errors before the 500 response.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…irectory useEmailManagement.ts had 5 independent hooks (useEmail, useEmailDraft, useEmailSearch, useEmailSLA, useEmailSignature) with no internal coupling. This commit extracts useEmailSignature (the most self-contained hook) to src/hooks/email/useEmailSignature.ts and re-exports it from the barrel. All import paths in consumers are unchanged (@/hooks/useEmailManagement). Pattern for next split: useEmailSLA → email/useEmailSLA.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
The previous let _discardedEventCount = 0 was a module-level mutable global that: (1) persisted across HMR reloads without resetting, (2) aggregated counts across all mounted instances of the hook, (3) could never be garbage-collected. Fix: discardedCountRef = useRef(0) scoped to each hook instance. Hook now returns getDiscardedCount() accessor for metrics consumers. getRealtimeDiscardedCount() deprecated and returns 0 (no consumers found). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Zero imports found for src/assets/emojis/*.png in any .ts/.tsx file. The custom-emojis bucket in remote Supabase storage serves production emoji rendering — these local PNGs were never referenced at runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Adds conservative floors (lines 40%, functions 35%, branches 25%, statements 40%) to vitest.config.ts thresholds and a matching CI step that reads coverage-summary.json and prints a human-readable failure message. Also switches to json-summary reporter so the gate has data. Raise thresholds in vitest.config.ts as the suite improves — never lower. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Template was committed as base64 binary instead of plaintext markdown, making it unreadable in GitHub review UI. Decoded to proper UTF-8 and: - Fixed typo: OBRIGATÑRIO → OBRIGATÓRIO - Added coverage regression checkbox under fix: section pointing to vitest.config.ts thresholds (pairs with E44 ratchet) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Replaces every remaining supabase.storage.from(bucket).getPublicUrl(path) call with resolvePublicStorageUrl(bucket, path) from @/lib/mediaUrl. Eliminates the final vector through which kong:8000 internal URLs could leak into the database or be served to clients. 17 files covered. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…y Lockfile
fix(schema): remove .schema('evo') from regular SELECT queries in useRealtimeMessages
- ci.yml: `git show origin/main:package.json` returns base64-encoded content
in this repo; add jq-validity check and base64 decode fallback so the
Verify Lockfile step no longer fails with "Invalid numeric literal" (jq exit 5)
- useRealtimeMessages.ts: evolution_contacts and evolution_messages SELECT
queries must go through the default zapp schema (security_invoker VIEW proxy)
not `.schema('evo')` directly — fixes SUP-004 violation that blocked
quality-gate CI step via check-schema-usage.mjs
Realtime subscription lines keep `schema: 'evo'` (correct per CLAUDE.md rule 4)
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…th package.json
- useRealtimeMessages.ts: restore .schema('evo') on evolution_contacts queries
(simulate-schema-access.mjs requires it; SUP-004 only prohibits evolution_messages/conversations)
- bun.lock workspace: remove @storybook/addon-essentials, @storybook/addon-interactions,
@vitejs/plugin-react, jsdom (deleted from package.json); update xlsx to 0.18.5 (npm)
- bun.lock packages: update xlsx entry from CDN (0.20.3) to npm registry (0.18.5)
with correct deps and sha512 integrity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
The .gitignore file was stored as base64-encoded content, causing git to read the raw base64 string as patterns (no valid patterns matched). This left node_modules/ untracked and all other gitignore rules inactive. Decoded the file to proper plaintext; node_modules is now correctly excluded at line 71 via the `node_modules` pattern (without trailing slash, which covers directories, symlinks, and files per audit note in the file). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Six TypeScript source files and one SQL migration were stored as single-line base64 blobs in git, causing unit test failures, TypeScript import errors, and Vercel build failures. Decoded files: - src/features/inbox/hooks/realtime/messageSender.ts (351 lines) - src/features/inbox/hooks/useRealtimeMessages.ts (692 lines) - src/hooks/useExternalApiManagement.ts (1136 lines) - src/lib/env.ts (71 lines) - src/lib/types/branded.ts (101 lines) - src/lib/useMediaUrl.ts (337 lines) - supabase/migrations/MIGRATION_TEMPLATE.sql (63 lines) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…ion API The quality gate rejects bare `: any` without ignore-audit annotation. The reactions array shape comes from the Evolution API response and has no TypeScript type definition — ignore-audit is the correct suppressant. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
- vitest.config.ts: add 6 Deno-only test files (https://deno.land/ imports) and contactsDB.test.ts (requires external Supabase env vars) to the exclude list so the vitest/Node.js suite no longer errors on ERR_UNSUPPORTED_ESM_URL_SCHEME - src/lib/useMediaUrl.ts: replace startsWith() URL prefix check with new URL(sanitized).hostname comparison (CWE-184 — incomplete URL substring sanitization, CodeQL HIGH) to prevent domain-confusion bypass Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
The CI Quality diagnostics job was failing at step "Schema gate final (bloqueante)" because types.ts only declared __InternalSupabase and public as top-level Database keys, while check-types-schemas.mjs requires both zapp and evo to be present. Added minimal stub declarations for both schemas using the standard [_ in never]: never pattern for empty Tables/Views/Functions/Enums/ CompositeTypes sub-keys. These stubs satisfy the extractTopLevelKeys() parser in the gate script without breaking any existing type inference (tsc --noEmit --skipLibCheck: 0 errors). Root cause: types.ts is auto-generated from Supabase postgres-meta and the CI auto-repair step (step 8) failed all 3 retries with HTTP 401 (META_TOKEN secret unavailable in PRs). The stubs act as a safe placeholder until a proper type regeneration is run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Batch 1 — core hooks and shared schemas: - silentErrorPrevention: consolidate 5 inline `any` to 1 named AnyFn alias - useRetryAndErrorPrevention: import AnyFn, remove inline suppression - useDebounce: import AnyFn, remove inline suppression - criticalPayloadSchemas: import z directly, remove ZodLike=any param - useNewConversation: update caller (drop z arg) - use-toast: [key:string]:any → unknown - useEmail: row:any → Record<string,unknown> - emailMappers: Raw=Record<string,any> → unknown - useNotificationManagement: useRef<any> → useRef<RealtimeChannel|null> Batch 2 — service factory layer: - types.ts: FilterParams [key:string]:any → unknown - queryFactory: TData=any→unknown, readonly any[]→unknown[] (10 suppressions) - mutationFactory: TVariables=any→unknown, readonly any[]→unknown[] (6 suppressions) - genericService: <T=any>→unknown, Record<string,any>→unknown (2 of 3; dynamic from() retained) TypeScript: zero errors (npx tsc --noEmit --skipLibCheck) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…, useQueueManagement, useAutomationSuggestions
- useAutomations: typed sort/findIndex callbacks with ExternalMsg interface; typed
last message as ExternalMsg|undefined; replaced client.rpc('name' as any) with
typedClient.rpc('name') for rpc_get_contact, rpc_upsert_contact, rpc_insert_message;
replaced rawContact/c:any with typed inline extraction for tags field
- useQueueManagement: removed SupabaseClient<any> rpcClient cast entirely; imported
safeClient and replaced both rpcClient.rpc() calls with safeClient.rpc()
- useAutomationSuggestions: consolidated suppression from rpc name cast to client cast
(SupabaseClient<any>), consistent with external-client pattern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…oss 21 files - ConnectionsView: maskSensitiveData/maskValue → Record<string,unknown> with proper casts - InstanceSettingsDialog: ReconnectionLog interface replaces any[] auditLogs state - OAuthConsent: OAuthData interface replaces 4 any suppressions in OAuthNs type - Connections (admin): SystemConnection/SystemConnectionPayload interfaces replace 9 suppressions - chart.tsx: LegendProps['payload'] from Recharts lib for payload prop type - GmailWebhookMonitor: Array.isArray guard + Record<string,unknown> map callback - ChatPanel: MessageQueueController import replaces messageQueue?: any - TeamFiles: onError: Error instead of any - useAutomationFailureAlerts: Record<string,unknown> + downstream ctx.stage casts - ConversationItem: ConversationLike/ConversationContact interfaces replace 5 any props - useVoiceManagement, useIntegrationManagement, useSpeechToText.test: targeted fixes - connectionsRepository, settingsRepository: typed return/param fixes - safeClient, safe-queries, safeClient.test: SafeQueryBuilder/typed helpers - datasource/db: DynamicTableClient + DynamicRpcClient patterns - supabaseHelpers: ReturnType<typeof supabase.from> in DynamicClient - test/typing: AnyFn import from silentErrorPrevention Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
…uppressions - TeamFiles.tsx: remove redundant `(file: any)` annotation; `WhisperFile` already inferred from `filteredFiles: WhisperFile[]` - useExternalEvolution.ts: define `ContactEnrichmentData` interface (tags, company, ai_sentiment, name, push_name) replacing `data: any` in the enrichment cache Map and `queryExternalProxy<any>` generic arg Remaining 11 suppressions are all legitimate: - 4× `SupabaseClient<any>` for external DB (no schema types available) - 1× `query: any` for dynamic Supabase query builder chaining - 2× `from(t): any` in generic table/RPC client helpers - 1× `SafeQueryBuilder = any` type alias for complex Supabase chain type - 1× canonical `AnyFn` definition in silentErrorPrevention.ts - 1× `ComponentType<any>` in lazy view map (React constraint) - 1× same in useAutomationSuggestions external client tsc --noEmit --skipLibCheck: 0 errors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NfRcF5T1usyyc1WVF3BJE
Merged origin/main (0bc0bc7) into claude/zapp-web-v3-audit-74uxvx. Conflict resolution strategy: - Config files (package.json, vitest.config.ts): take main's newer dep versions - .gitignore: merged both additions (.mcp.json entries + artifact patterns) - .github/workflows/schema-drift.yml: take main's (adds supabase/ci filter) - All 26 TypeScript source files: kept react-hooks/exhaustive-deps fixes from this branch (removes eslint-disable suppressions with proper dep arrays), incorporated non-deps-related changes from main where needed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jZX3jD8iLBNBqvgPVLBnE
…(fixes 1-9)
- useSipConnection: remove duplicate connect() body from merge conflict that
caused esbuild failure ("Expected ) but found catch")
- useAudioRecorder: add cleanupRecordingResources to unmount useEffect deps;
add setBlobUrl to cancelRecording and restoreRecording deps
- useAudioManagement: add setBlobUrl to startRecording, cancelRecording, and
restoreRecording deps (setBlobUrl is a stable useCallback with [] deps)
- useChatMediaSending: remove contactPhone from handleSendSticker,
handleSendCustomEmoji, and handleSendAudioMeme deps — callbacks consume
contactPhone only through getSafePhone which already captures it
All 9 fixes verified: tsc 0 errors, ESLint 0 exhaustive-deps errors, vite build clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jZX3jD8iLBNBqvgPVLBnE
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughA PR reconstrói workflows de CI, ajusta dependências de hooks React, reduz usos de ChangesGovernança e validação
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
All four workflow files were unparseable as YAML:
- ci-gate.yml: entire file was stored as base64 text; fixed checkout@v7→v4
- ts-nocheck-ratchet.yml: two corrupted base64 chunks; rewrote from scratch
- fix-schema-refs.yml: duplicate 'if:' key + --body text at col 0 breaking
block scalar; split summary steps + use ANSI-C $'...' quoting for body
- pr-size-gate.yml: single-line base64; JS template literals crossing col 0
inside script: | block; replaced with .join('\n') array form
All four now pass YAML validation. CI Status Gate (required check) was
already passing; these fixes restore the informational workflow checks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jZX3jD8iLBNBqvgPVLBnE
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
- bun.lock: version bumps (@sentry/react 10.66→10.68, web-vitals 5.3→6.0, @commitlint 19→21, @testing-library/jest-dom 6.9→7.0) - src/components/ui/registry.json: component registry restructuring (pre-existing uncommitted state found in working tree) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jZX3jD8iLBNBqvgPVLBnE
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
There was a problem hiding this comment.
Actionable comments posted: 20
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (16)
src/components/monitoring/MonitoringWebhookPanel.tsx (1)
48-63: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winValide o retorno antes de chamar
setSecretStatus(...).data as SecretStatusnão faz validação em runtime; se a Edge Function devolver um payload fora do contrato, a UI pode ficar inconsistente ou quebrar ao lercheckedAt,lengthouhashPrefix.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/monitoring/MonitoringWebhookPanel.tsx` around lines 48 - 63, Validate the payload returned by supabase.functions.invoke in loadSecretStatus before calling setSecretStatus, ensuring it matches the SecretStatus shape and safely includes checkedAt, length, and hashPrefix. Treat invalid data as an error through the existing catch/toast flow, and remove the unchecked cast.Source: Path instructions
src/components/effects/EasterEggs.tsx (1)
228-255: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winCancele a instalação assíncrona do listener. Se
navigator.permissions.queryresolver depois que o efeito desmontar, o cleanup já passou edevicemotionpode ficar registrado sem remoção. Adicione um flag de descarte antes de chamaraddEventListener.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/effects/EasterEggs.tsx` around lines 228 - 255, Update the effect containing setupListener and its cleanup to track a disposed/cancelled flag, set it during cleanup, and check it after the asynchronous permission query resolves before calling addEventListener. Ensure listenerAdded is only set when the listener is actually registered, preventing late registration after unmount.src/features/admin/hooks/useAdminManagement.ts (1)
817-840: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick winEvite a recarga em loop no diálogo de roles.
roleUsers ?? []cria um array novo enquantoroleUsersainda está indefinido; comshowAddRoleDialogaberto, isso troca a identidade defetchAvailableRoleUsersa cada render e ouseEffectdispara novas consultas até a query preencher. Use um fallback estável (EMPTY_ROLE_USERS/useMemo) e removaroleUsersListdas dependências do efeito se ele só serve para o filtro interno.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/admin/hooks/useAdminManagement.ts` around lines 817 - 840, Estabilize o fallback usado por roleUsersList quando roleUsers estiver indefinido, usando EMPTY_ROLE_USERS ou useMemo, para que fetchAvailableRoleUsers não seja recriada a cada render. Como roleUsersList é utilizado apenas no filtro interno de fetchAvailableRoleUsers, remova-o das dependências de useEffect e mantenha o efeito dependente somente de showAddRoleDialog e da callback estável.src/hooks/useAutomationSuggestions.ts (1)
144-148: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winSó grave
applied_tagsdepois de checar o retorno da RPC.rpc_upsert_contactpode falhar sem interromper esse fluxo; hoje a função ainda persiste a tag local e mostra sucesso mesmo com erro externo ou semexternalClient, deixando a auditoria inconsistente com o contato.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useAutomationSuggestions.ts` around lines 144 - 148, In the automation suggestion flow around rpc_upsert_contact, only persist applied_tags and show success after confirming externalClient exists and the RPC returns successfully. Handle RPC errors or a missing client by stopping the local update and success notification, keeping the audit consistent with the external contact.src/components/connections/IntegrationsPanel.tsx (1)
50-92: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winO cleanup não aborta as requisições em andamento.
Ao fechar o diálogo, apenas
cancelledmuda. OAbortControllersó é abortado nofinally, que roda depois dePromise.allSettled; logo, as seis requisições continuam consumindo rede. Crie o controller no efeito e aborte-o diretamente no cleanup.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/connections/IntegrationsPanel.tsx` around lines 50 - 92, Move AbortController ownership from loadAll into the useEffect: create the controller there, pass its signal through loadAll to each getter, and call abort() in the effect cleanup alongside setting cancelled. Remove the delayed finally-based abort so closing the dialog immediately cancels all in-flight requests.src/components/dashboard/FloatingParticles.tsx (1)
19-30: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winA redução de movimento ainda mantém animações infinitas ativas.
Quando
prefersReducedMotioné verdadeiro, apenas as partículas são removidas; os quatro orbes abaixo continuam animando comrepeat: Infinity. Condicione também essesanimate/transitionà preferência reduzida.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/dashboard/FloatingParticles.tsx` around lines 19 - 30, Atualize as animações dos quatro orbes no componente FloatingParticles para respeitarem prefersReducedMotion, desativando os valores animate e as transições com repeat: Infinity quando essa preferência estiver ativa. Preserve as animações atuais quando prefersReducedMotion for falso.src/components/reports/AbandonmentRate.tsx (1)
20-48: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winTratem rejeições e sempre encerrem o loading.
Esses loaders disparam Promises sem recuperação. Uma falha de rede ou exceção deixa o componente em skeleton/loading e pode gerar rejeição não tratada. Adicionem
try/catch/finallydentro de cada loader; nocatch, preservem um estado consistente e exibam/registram a falha.
src/components/reports/AbandonmentRate.tsx#L20-L48: envolverfetchAbandonmentRateMessagescomtry/catch/finally.src/components/reports/ConversationHeatmap.tsx#L28-L56: envolverfetchContactMessagesForHeatmapcomtry/catch/finally.src/components/reports/DemandForecast.tsx#L29-L82: garantirsetLoading(false)nofinally.src/components/reports/PeriodComparison.tsx#L31-L82: tratar falhas de ambas as consultas e finalizar o loading.src/features/inbox/components/LeadRiskScorePanel.tsx#L42-L63: tratar falhas da consulta e marcar o painel como carregado nofinally.As per path instructions, “Promises sem await ou .catch()” devem ser verificadas.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/reports/AbandonmentRate.tsx` around lines 20 - 48, Ensure all listed loaders handle rejected requests and always clear loading state: in src/components/reports/AbandonmentRate.tsx lines 20-48, wrap loadData’s fetchAbandonmentRateMessages flow in try/catch/finally, preserving consistent state and logging or displaying errors; apply the same to fetchContactMessagesForHeatmap in src/components/reports/ConversationHeatmap.tsx lines 28-56; guarantee setLoading(false) in finally for DemandForecast.tsx lines 29-82; handle both queries and finalize loading in PeriodComparison.tsx lines 31-82; and handle the query failure while marking the panel loaded in finally in LeadRiskScorePanel.tsx lines 42-63. Verify each effect invocation does not leave an unhandled promise rejection.Source: Path instructions
src/hooks/useEmail.ts (1)
55-62: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winNormalize
message_countantes doMath.max
rowestá tipado comoRecord<string, unknown>, entãorow.message_count ?? 1continua sem narrowing e não entra emMath.max. Converta esse campo para número antes de calcularunread_count(como já feito emuseEmailManagement.ts).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useEmail.ts` around lines 55 - 62, Normalize row.message_count to a numeric value before passing it to Math.max in mapBaseThreadRow, matching the existing conversion used in useEmailManagement.ts. Preserve the current fallback to 1 and unread_count behavior for read threads.Source: Path instructions
src/features/inbox/components/ConversationHistory.tsx (1)
82-172: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winEvite sobrescrita por respostas antigas
- Uma requisição anterior pode concluir depois da atual e sobrescrever
conversations/isLoadingcom dados do contexto errado. UserequestId,AbortControllerou uma flag de cancelamento antes de chamarsetConversations/setIsLoading.contactPhonenão é usado na query; tire-o das dependências para evitar refetch desnecessário.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/components/ConversationHistory.tsx` around lines 82 - 172, The fetchConversationHistory callback must ignore stale requests before updating conversations or isLoading; add request cancellation or a request ID/active flag and guard every relevant state update, including early returns and finally, so only the latest invocation affects state. Remove unused contactPhone from the callback dependency array since it is not used by the query.src/hooks/useAutomations.ts (1)
99-116: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftUse a RPC tipada aqui, não
SupabaseClient<any>Hoje o código só garante que
msgsé um array, mas ainda assumemessage_timestamp,from_meecontentsem validação. Se a RPC devolver uma linha fora do contrato, a ordenação pode virarNaNe as automações tomar decisões erradas. Use o helper tipado da RPC ou valide cada item antes de processar.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useAutomations.ts` around lines 99 - 116, Update the RPC call in the automation flow around typedClient and rpc('rpc_list_messages') to use the project’s typed RPC helper and its declared message-row contract instead of SupabaseClient<any>. Ensure returned rows are validated for message_timestamp, from_me, and content before sorting or selecting last, rejecting or excluding invalid rows so sorting never receives invalid timestamps.Source: Path instructions
src/features/inbox/components/ConversationSummary.tsx (1)
115-120: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winNão use
hasGeneratedcomo gatilho direto desse reset.Após gerar o resumo,
setHasGenerated(true)executa este efeito, que imediatamente limpasummarye volta o estado parafalse. O resumo recém-gerado desaparece. Detecte a mudança dos filtros com umuseRefou outra comparação anterior, mantendohasGeneratedapenas como condição.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/components/ConversationSummary.tsx` around lines 115 - 120, Atualize o useEffect associado a analysisPeriod, customDateFrom e customDateTo para detectar mudanças reais nos filtros usando useRef ou comparação com os valores anteriores, sem usar hasGenerated como gatilho. Mantenha hasGenerated apenas como condição antes de limpar summary e redefini-lo, garantindo que setHasGenerated(true) após a geração não apague o resumo recém-criado.src/hooks/useVoiceManagement.ts (1)
39-46: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winInterrompa o
SpeechRecognitionno unmount.
O cleanup só marcamountedRefcomo falso; a instância pode continuar ativa após o componente desmontar, mantendo o microfone e recursos do navegador ocupados. Chamestop()no cleanup e limperecognitionRef.current.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useVoiceManagement.ts` around lines 39 - 46, Atualize o cleanup do useEffect em useVoiceManagement para interromper a instância ativa de SpeechRecognition antes de desmontar. Chame stop() quando recognitionRef.current existir e, em seguida, defina recognitionRef.current como null, preservando também a atualização de mountedRef.current para false.src/hooks/connections/useHubTabNavigation.ts (1)
9-42: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winLógica de validação/sincronização de aba duplicada entre dois hooks.
useHubTabNavigationeuseHubTabNavigationManagementimplementam exatamente a mesma validação deHubTabe os mesmos dois efeitos de sincronização comsearchParams— esta própria PR precisou aplicar o mesmo fix deuseCallback/deps duas vezes.
src/hooks/connections/useHubTabNavigation.ts#L9-L42: manter como implementação canônica desta lógica.src/hooks/connections/useConnectionsManagement.ts#L39-L80: substituiruseHubTabNavigationManagementpor uma chamada auseHubTabNavigation(isDev)(ou extrair ambos para um hook compartilhado), eliminando a duplicação devalidateTabe dos doisuseEffect.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/connections/useHubTabNavigation.ts` around lines 9 - 42, The tab validation and URL synchronization logic is duplicated across two hooks. Keep useHubTabNavigation in src/hooks/connections/useHubTabNavigation.ts:9-42 as the canonical implementation; in src/hooks/connections/useConnectionsManagement.ts:39-80, replace useHubTabNavigationManagement with a call to useHubTabNavigation(isDev), removing its duplicate validateTab and synchronization effects.src/hooks/useAudioRecorder.ts (2)
24-43: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy liftDuas implementações completas de
useAudioRecordermantidas em paralelo.src/hooks/useAudioRecorder.tsesrc/hooks/useAudioManagement.tsexportam cada um sua própria versão deuseAudioRecorder, com a mesma lógica de MediaRecorder/AudioContext/SpeechRecognition/stopRecordingRef. Esta PR precisou replicar o mesmo fix (stopRecordingRef, deps desetBlobUrl) nos dois arquivos, confirmando o risco de divergência futura.
src/hooks/useAudioRecorder.ts#L24-L43: candidata a implementação canônica (após corrigir o TDZ decleanupRecordingResourcesapontado no arquivo).src/hooks/useAudioManagement.ts#L781-L781: avaliar remoção douseAudioRecorderlocal em favor de importar a implementação desrc/hooks/useAudioRecorder.ts, confirmando antes quais consumidores usam qual versão.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useAudioRecorder.ts` around lines 24 - 43, Use src/hooks/useAudioRecorder.ts:24-43 as the canonical useAudioRecorder implementation, moving cleanupRecordingResources before the useEffect that references it to eliminate the temporal dead zone. In src/hooks/useAudioManagement.ts:781-781, inspect consumers and remove the local useAudioRecorder implementation where compatible, importing the canonical hook instead; preserve any version-specific behavior only if consumers require it.
24-43: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick winTDZ em
cleanupRecordingResourcesquebra a montagem do hooksrc/hooks/useAudioRecorder.ts:25-43— o array de dependências deuseEffectavaliacleanupRecordingResourcesantes doconstser inicializado, disparandoReferenceErrorem runtime. MovacleanupRecordingResourcespara antes do efeito.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useAudioRecorder.ts` around lines 24 - 43, Move the cleanupRecordingResources useCallback definition before the useEffect that references it in its dependency array. Preserve its existing cleanup behavior and keep the mountedRef lifecycle effect unchanged aside from resolving this initialization order.src/features/inbox/components/useAudioRecorderUI.ts (1)
159-163: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick winEfeito de auto-start reinicia a gravação a cada render.
onRecordingCompleteé uma closure inline aqui, entãostartRecordingmuda em todo render;cancelRecordingtambém muda quandoisRecording/isPaused/transcriptionatualizam. Com essas deps, ouseEffectfaz cleanup + setup de novo em cada re-render, cancelando e reiniciando o microfone repetidamente. Mantenha esse efeito estável para rodar só no mount.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/components/useAudioRecorderUI.ts` around lines 159 - 163, Estabilize o efeito de auto-start em useAudioRecorderUI para executar apenas na montagem, evitando que as mudanças de startRecording ou cancelRecording causem cleanup e reinício da gravação a cada render. Preserve o cancelamento no unmount e ajuste as dependências conforme necessário para manter esse comportamento.
🟡 Minor comments (16)
src/pages/admin/email/useEmailHealthStatus.ts-66-83 (1)
66-83: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winValide o payload da Edge Function antes de consumi-lo.
Response.json()entra como dado não confiável e os campos aninhados são acessados sem narrowing. Uma resposta 2xx malformada pode gravarfailuresDatainválido e quebrar consumidores posteriores. Valide o shape antes de atualizar o estado.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/admin/email/useEmailHealthStatus.ts` around lines 66 - 83, Validate the parsed payload from fetchResponse.json() before using it in the health and failures state updates. Add a type/shape guard for the expected status, source, validation timestamp, failure count, and failuresResult.items/total fields, and reject malformed 2xx responses before setHealth or setFailuresData; preserve the existing error handling for non-OK responses.Source: Path instructions
src/pages/admin/AdminDevDiagnosticsPage.tsx-28-40 (1)
28-40: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winTrate o
{ error }do insert da auditoria. Oawaitjá existe; o problema é ignorar o retorno desafeClient.from(...), então a falha pode passar em silêncio e o acesso ficar sem registro.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/admin/AdminDevDiagnosticsPage.tsx` around lines 28 - 40, Atualize a função logAccess para capturar o retorno de safeClient.from(...) no insert de dev_diagnostic_logs e verificar sua propriedade error. Quando houver falha, trate-a explicitamente conforme o padrão de tratamento de erros já usado no módulo, sem ignorar o resultado da auditoria..github/workflows/pr-size-gate.yml-137-143 (1)
137-143: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winBusca de comentário existente não pagina — pode duplicar em PRs com muitos comentários.
listCommentsretorna só a primeira página (padrão 30 itens). Em PRs bem discutidos, o comentário com o marcador<!-- pr-size-gate -->pode estar fora dessa página, e o bot cria um comentário duplicado em vez de atualizar o existente.♻️ Fix sugerido (usar paginate)
- const { data: comments } = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number - }); + const comments = await github.paginate(github.rest.issues.listComments, { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/pr-size-gate.yml around lines 137 - 143, Atualize a busca em torno de `github.rest.issues.listComments` e `comments.find` para usar a API paginada (`github.paginate` ou equivalente), garantindo que todos os comentários da issue sejam carregados antes de procurar pelo `MARKER`; preserve a lógica existente de localizar o comentário e atualizar ou criar conforme o resultado.src/services/api/genericService.ts-63-65 (1)
63-65: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFaça narrowing real de
minemaxantes de montar a faixa.
as Record<string, unknown>e'min' in rangeValsó garantem a chave;gte/lteainda pode receber objeto/array e gerar filtro inválido em runtime. Validemin/maxcomo escalares antes de aplicar o range.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/services/api/genericService.ts` around lines 63 - 65, Update the range handling around rangeVal so min and max are narrowed to valid scalar values before calling query.gte and query.lte. Do not rely solely on the Record cast or key existence checks; reject objects and arrays, and apply each bound only when its value passes scalar validation.Source: Path instructions
src/components/monitoring/MonitoringWebhookPanel.tsx-278-279 (1)
278-279: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winTrate as rejeições dessas Promises
src/components/monitoring/MonitoringWebhookPanel.tsx#L69-L70e#L278-L279:navigator.clipboard.writeText()pode rejeitar; o handler hoje ignora essa falha.src/components/monitoring/RetryMetricsPanel.tsx#L206-L207,#L284-L290e#L417-L418: mesmo problema emcopy()erefetch().Use
async/awaitcomtry/catchouvoid ...catch(...)nesses handlers.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/monitoring/MonitoringWebhookPanel.tsx` around lines 278 - 279, Trate explicitamente as rejeições das Promises nos handlers de cópia e atualização: em src/components/monitoring/MonitoringWebhookPanel.tsx, nos trechos 69-70 e 278-279, capture a rejeição de navigator.clipboard.writeText(); em src/components/monitoring/RetryMetricsPanel.tsx, nos trechos 206-207 e 417-418, trate a Promise de copy(), e no trecho 284-290, trate a Promise de refetch(). Use async/await com try/catch ou void com catch() em cada handler, sem deixar essas rejeições serem ignoradas.Source: Path instructions
src/components/ai/AutoTicketClassifier.tsx-127-134 (1)
127-134: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winRestaurar
isMountedRefantes de carregar os tickets. No cleanup,isMountedRef.currentvirafalse; na segunda execução do efeito em Strict Mode,loadClassifiedTickets()roda com o ref desativado eloading/estado não atualizam, deixando a tela presa no carregamento. DefinaisMountedRef.current = trueno início do efeito.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ai/AutoTicketClassifier.tsx` around lines 127 - 134, Atualize o efeito que chama loadClassifiedTickets para definir isMountedRef.current como true antes do carregamento. Preserve o cleanup que o redefine para false, garantindo que execuções subsequentes do efeito em Strict Mode possam atualizar loading e os demais estados.src/components/effects/EasterEggs.tsx-64-69 (1)
64-69: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRemova
rainbow-modeedisco-modeno unmount.
O cleanup atual só cancela os timers; se o provider desmontar antes do timeout, as classes ficam emdocument.bodye o efeito vaza para o resto da app.Correção sugerida
useEffect( () => () => { effectTimers.current.forEach(clearTimeout); + document.body.classList.remove('rainbow-mode', 'disco-mode'); }, [] );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/effects/EasterEggs.tsx` around lines 64 - 69, Atualize o cleanup de desmontagem do componente em EasterEggs para remover explicitamente as classes `rainbow-mode` e `disco-mode` de `document.body`, além de cancelar os timers existentes. Garanta que ambos os efeitos sejam limpos mesmo quando o provider desmontar antes dos timeouts.src/features/admin/components/GmailWebhookMonitor.tsx-35-37 (1)
35-37: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winValide cada conta antes do cast para
EmailAccount.
Array.isArraynão valida os elementos. O cast final aceita itens nulos, primitivos ou objetos semid/email_address, produzindo dados inválidos na lista. Filtre com um type guard/schema que confirme os campos obrigatórios antes domap.As per path instructions, “any/unknown sem narrowing posterior” deve ser verificado.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/admin/components/GmailWebhookMonitor.tsx` around lines 35 - 37, Valide cada elemento de emailAccounts antes do cast final em EmailAccount: filtre apenas objetos não nulos que contenham os campos obrigatórios id e email_address, usando um type guard ou schema com narrowing explícito de unknown. Aplique o map que define history_id como null somente após essa filtragem e remova a dependência de um cast que aceite dados inválidos.Source: Path instructions
src/components/settings/theme/useThemePreset.ts-181-205 (1)
181-205: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winValide o payload antes de aplicar o tema.
JSON.parse(text)deixaconfigsem forma garantida; umborderRadiusnão numérico pode virarNaNrememapplyBorderRadius, epreset/themefora do tipo esperado ainda chegam aos callbacks. Faça o parse comounknowne aplique narrowing antes de chamarapplyPresetById,applyBorderRadiuseonThemeChange.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/settings/theme/useThemePreset.ts` around lines 181 - 205, Validate the imported payload in importTheme before applying any values: parse it as unknown, narrow it to an object, require preset and theme to be strings, and ensure borderRadius is a finite number before invoking applyPresetById, applyBorderRadius, setBorderRadius, or onThemeChange. Keep invalid payloads routed to the existing error toast.Source: Path instructions
src/features/auth/components/mfa/MFAEnroll.tsx-64-71 (1)
64-71: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winNão atualize a ref durante o render. Em React concorrente,
handleVerifyRef.current = handleVerifypode expor a closure de um render descartado; mova essa sincronização para umuseEffectdependente dehandleVerify, antes do efeito que reage acode.Correção sugerida
const handleVerifyRef = useRef(handleVerify); - handleVerifyRef.current = handleVerify; + useEffect(() => { + handleVerifyRef.current = handleVerify; + }, [handleVerify]); useEffect(() => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/auth/components/mfa/MFAEnroll.tsx` around lines 64 - 71, In MFAEnroll, stop assigning handleVerifyRef.current during render; synchronize the ref in a useEffect dependent on handleVerify, declared before the existing code-length verification effect. Keep the handleVerifyRef.current invocation in the code effect unchanged.Source: Linters/SAST tools
src/hooks/useRetryAndErrorPrevention.ts-260-274 (1)
260-274: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winO cancelamento não impede
onReject.A expressão da linha 266 é avaliada ao iniciar a Promise; se o componente desmontar depois, o callback já foi capturado e ainda será executado. Passe um wrapper que teste
cancelledno momento da rejeição.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useRetryAndErrorPrevention.ts` around lines 260 - 274, Corrija o callback onReject no useEffect de useRetryAndErrorPrevention para avaliar cancelled no momento da rejeição, não durante a criação da Promise. Passe um wrapper que verifique cancelled antes de invocar onRejectRef.current, mantendo o cancelamento efetivo após a desmontagem.src/components/settings/sla/SLARuleFormDialog.tsx-54-59 (1)
54-59: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winEvite escrever em
ref.currentdurante o render — isso deixa o componente impuro e pode expor valores de uma renderização abortada em React concorrente. Mova essa sincronização para umuseEffect/useLayoutEffect(ou um helperuseLatest).
src/components/settings/sla/SLARuleFormDialog.tsx#L54-L59src/hooks/useRetryAndErrorPrevention.ts#L152-L153src/hooks/useRetryAndErrorPrevention.ts#L187-L188src/hooks/useRetryAndErrorPrevention.ts#L233-L234src/hooks/useRetryAndErrorPrevention.ts#L260-L261src/hooks/useRetryAndErrorPrevention.ts#L302-L307src/hooks/useRetryAndErrorPrevention.ts#L394-L397src/hooks/useTeamChatDraft.ts#L29-L32🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/settings/sla/SLARuleFormDialog.tsx` around lines 54 - 59, Stop assigning to ref.current during render; synchronize each latest-value ref through useEffect/useLayoutEffect or the existing useLatest helper. Update SLARuleFormDialog.tsx lines 54-59, all listed ref assignments in useRetryAndErrorPrevention.ts at lines 152-153, 187-188, 233-234, 260-261, 302-307, and 394-397, and useTeamChatDraft.tsx lines 29-32, preserving the existing consumers and dependency behavior.Source: Linters/SAST tools
src/components/ui/registry.json-91-99 (1)
91-99: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRemova as variantes duplicadas do registry.
toggle.variant,badge.variant,input.variantecard.variantrepetem"hover"ou"visible". Comosrc/pages/DesignSystem.tsxrenderiza cada entrada diretamente, essas duplicatas aparecem como opções repetidas e poluem o catálogo visual. Mantenha cada variante uma única vez ou corrija o gerador do registry.Also applies to: 131-150, 204-221, 230-246
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ui/registry.json` around lines 91 - 99, Remova as entradas duplicadas nas listas de variantes de toggle, badge, input e card no registry, mantendo cada variante como "hover" ou "visible" apenas uma vez. Preserve a ordem e todas as variantes únicas para que DesignSystem.tsx continue renderizando o catálogo completo sem opções repetidas.src/hooks/useGmailOAuthFlow.ts-334-337 (1)
334-337: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winTrate a Promise retornada por
ensureWatch.O efeito chama uma função
asyncsemawaitnem.catch(). Uma rejeição inesperada pode gerarunhandled rejection; usevoid ensureWatch(acc.id).catch(...)ou agregue as chamadas comPromise.allSettled.As per path instructions: Promises sem
awaitou.catch().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useGmailOAuthFlow.ts` around lines 334 - 337, Atualize o efeito que percorre accountsRef.current para tratar a Promise retornada por ensureWatch: encadeie um catch com tratamento apropriado para cada chamada ou agregue as chamadas usando Promise.allSettled, evitando rejeições não tratadas.Source: Path instructions
src/features/inbox/components/RealtimeInboxView.tsx-129-160 (1)
129-160: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winExponha
useExternalDbno retorno do hook.RealtimeInboxViewlê(inbox as any).useExternalDb, masuseRealtimeInboxnão retorna esse campo; o valor ficaundefinede a decisão demarkAsReadpassa a depender de uma condição acidental. Passe o booleano tipado pelo hook ou mova essa lógica para dentro dele.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/components/RealtimeInboxView.tsx` around lines 129 - 160, Expose the typed useExternalDb boolean from useRealtimeInbox and include it in the hook’s returned value, then consume that returned field directly in RealtimeInboxView instead of casting inbox to any. Preserve the existing markAsRead condition and dependency tracking using the exposed value.Source: Path instructions
src/features/inbox/hooks/realtime/useAutomationFailureAlerts.ts-78-81 (1)
78-81: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFalta narrowing em
row.rule_snapshot?.name.Com
rule_snapshotagora tipado comoRecord<string, unknown> | null,row.rule_snapshot?.nameresolve paraunknowne não recebe cast, ao contrário depayload.rule_name(linha 80) e dectx.stage(linhas 81/99), que já usam cast explícito. Senamenão for string, o toast pode exibir[object Object]sem aviso do compilador.🔧 Sugestão de correção
- const ruleName = - row.rule_snapshot?.name ?? (payload.rule_name as string | undefined) ?? 'Regra sem nome'; + const ruleName = + (row.rule_snapshot?.name as string | undefined) ?? + (payload.rule_name as string | undefined) ?? + 'Regra sem nome';As per path instructions, "any/unknown sem narrowing posterior" deve ser verificado em código TypeScript/JavaScript.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/hooks/realtime/useAutomationFailureAlerts.ts` around lines 78 - 81, Faça o narrowing de row.rule_snapshot?.name no cálculo de ruleName, validando ou convertendo explicitamente o valor unknown para string antes de usá-lo como nome. Preserve o fallback existente para payload.rule_name e “Regra sem nome”, garantindo que valores não-string não cheguem ao toast como [object Object].Source: Path instructions
🧹 Nitpick comments (7)
.github/workflows/ts-nocheck-ratchet.yml (1)
19-19: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winCheckout sem
persist-credentials: false— job é somente leitura.Esse job só faz
grep/wcemsrc/, não precisa de push nem chamadasgh. Ao contrário do workflowfix-schema-refs.yml(que precisa do token para push), aqui não há justificativa para manter credenciais persistidas no runner.🔒 Fix sugerido
- uses: actions/checkout@v4 + with: + persist-credentials: false🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/ts-nocheck-ratchet.yml at line 19, Update the actions/checkout@v4 step in the ts-nocheck-ratchet workflow to disable persisted credentials with persist-credentials: false, keeping the rest of the read-only job unchanged.Source: Linters/SAST tools
.github/workflows/ci-gate.yml (1)
61-63: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winTemplate injection: interpolar
github.base_refdireto no shell.O zizmor sinalizou linhas 62-63:
${{ github.base_ref }}é expandido textualmente antes do shell rodar. Hoje o trigger restringe amain/develop, então o risco prático é baixo, mas é um padrão frágil — se o gatilho mudar no futuro (ou herdar depull_request_target), vira injeção de comando real. Passe o valor viaenvem vez de interpolar direto.🛡️ Fix sugerido
- name: Verify bun.lock is in sync with package.json + env: + BASE_REF: ${{ github.base_ref }} run: | if [ "${{ github.event_name }}" = "pull_request" ]; then - git fetch origin ${{ github.base_ref }} - BASE="origin/${{ github.base_ref }}" + git fetch origin "$BASE_REF" + BASE="origin/$BASE_REF"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/ci-gate.yml around lines 61 - 63, Atualize o bloco condicional do workflow que usa `github.event_name` para receber `github.base_ref` por meio de uma variável `env`, removendo as interpolações diretas `${{ github.base_ref }}` nos comandos `git fetch` e na atribuição de `BASE`; preserve o comportamento de buscar e referenciar a branch base da pull request.Source: Linters/SAST tools
src/utils/emailMappers.ts (1)
16-16: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winValide o payload antes dos casts.
Trocar
anyporunknownnão torna o mapper seguro enquanto todos os campos continuam usandoas string,as booleanetc. Payloads inválidos ainda entram nos modelos tipados e podem quebrar consumidores depois. Use um schema Zod ou type guard antes do mapeamento.As per path instructions: verificar
any/unknownsem narrowing posterior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/emailMappers.ts` at line 16, Valide o payload Raw antes do mapeamento, substituindo os casts diretos para string, boolean e demais tipos por um schema Zod ou type guard que faça o narrowing dos campos. Faça o mapper prosseguir apenas com dados validados e rejeite ou trate payloads inválidos antes de construir os modelos tipados.Source: Path instructions
src/components/monitoring/RetryMetricsPanel.tsx (1)
116-124: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winEstabilize
filtersantes de passá-lo ao hook.Esse objeto é recriado em cada render e é enviado diretamente a
useRetryMetrics. Caso o hook use o objeto emqueryKeyou dependências de efeitos, isso pode causar churn ou refetches desnecessários.As per coding guidelines: valores derivados usados em
queryKeyou dependências de hooks devem ser estabilizados comuseMemoou estado apropriado.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/monitoring/RetryMetricsPanel.tsx` around lines 116 - 124, Estabilize o objeto filters antes de passá-lo a useRetryMetrics, usando useMemo com hours, actionFilter e statusFilter como dependências. Preserve os valores atuais de action e status, mantendo null para o filtro all, e continue usando o objeto memoizado na chamada do hook.Source: Coding guidelines
src/features/inbox/components/ConversationHistory.tsx (1)
172-176: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winRemova
contactPhonedas dependências.
fetchConversationHistorynão lêcontactPhone; mantê-lo no callback e no efeito provoca refetches desnecessários quando o telefone é formatado ou atualizado.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/components/ConversationHistory.tsx` around lines 172 - 176, Remove contactPhone from the dependency array of the useEffect that invokes fetchConversationHistory in ConversationHistory. Keep contactId, periodFilter, and fetchConversationHistory as dependencies, and leave the callback dependencies unchanged unless required by this removal.src/features/auth/components/mfa/MFAVerify.tsx (1)
56-59: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winRefs são mutadas durante o render em dois hooks.
Sincronize ambas após o commit para evitar que renders concorrentes descartados contaminem efeitos posteriores.
src/features/auth/components/mfa/MFAVerify.tsx#L56-L59: mover as atribuições para um efeito pós-commit.src/features/inbox/components/chat/useChatInputLogic.ts#L46-L47: sincronizarinputValueRefem efeito ou usar o valor comprometido do textarea.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/auth/components/mfa/MFAVerify.tsx` around lines 56 - 59, Move the current-value assignments for handleVerifyRef and verifyingRef in MFAVerify.tsx into a post-commit effect, preserving their latest committed values for subsequent effects. Also update inputValueRef synchronization in useChatInputLogic.ts at lines 46-47 to occur in an effect or otherwise use the textarea’s committed value; both sites require changes.src/features/inbox/hooks/useRealtimeInbox.ts (1)
201-201: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winNão dependa do objeto inteiro
messageQueuesem estabilizá-lo.
useMessageQueueretorna um novo objeto a cada renderização, então esta dependência faz o efeito executar novamente em toda renderização. Dependa diretamente do callback estávelreconcileWithDeliveryou memorize o controller retornado pelo hook.As per coding guidelines, valores derivados usados em dependências de hooks devem ser estabilizados com
useMemo/estado apropriado.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/hooks/useRealtimeInbox.ts` at line 201, Atualize as dependências do efeito associado a `selectedMessages`, `selectedContactId` e `messageQueue` para não depender do objeto instável `messageQueue`; use diretamente o callback estável `reconcileWithDelivery` ou memorize o controller retornado por `useMessageQueue`, garantindo que o efeito só seja reexecutado quando seus valores relevantes mudarem.Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7265195f-a918-4138-93f8-962fc678e3be
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock,!**/*.lock
📒 Files selected for processing (149)
.github/workflows/ci-gate.yml.github/workflows/fix-schema-refs.yml.github/workflows/pr-size-gate.yml.github/workflows/ts-nocheck-ratchet.yml.gitignoresrc/components/ai/AutoTicketClassifier.tsxsrc/components/catalog/ExternalProductCatalog.tsxsrc/components/catalog/ExternalProductManagement.tsxsrc/components/catalog/ProductDetailDialog.tsxsrc/components/catalog/SendProductDialog.tsxsrc/components/connections/ConnectionAuditDialog.tsxsrc/components/connections/ConnectionsView.tsxsrc/components/connections/InstanceSettingsDialog.tsxsrc/components/connections/IntegrationsPanel.tsxsrc/components/connections/NumberReputationMonitor.tsxsrc/components/contacts/AuditLogPanel.tsxsrc/components/contacts/ContactRecycleBin.tsxsrc/components/contacts/useContactDuplicateDetector.tssrc/components/dashboard/ConversationHeatmap.tsxsrc/components/dashboard/FloatingParticles.tsxsrc/components/diagnostics/ConnectionHealthPanel.tsxsrc/components/effects/EasterEggs.tsxsrc/components/gamification/GamificationProvider.tsxsrc/components/layout/SidebarNavGroup.tsxsrc/components/monitoring/MonitoringWebhookPanel.tsxsrc/components/monitoring/RetryMetricsPanel.tsxsrc/components/monitoring/useRetryMetricsPanelState.tssrc/components/queues/SLADashboard.tsxsrc/components/reports/AbandonmentRate.tsxsrc/components/reports/ConversationHeatmap.tsxsrc/components/reports/DemandForecast.tsxsrc/components/reports/PeriodComparison.tsxsrc/components/security/AuditLogDashboard.tsxsrc/components/security/IPWhitelistPanel.tsxsrc/components/security/RateLimitRealtimeAlerts.tsxsrc/components/security/SecurityOverview.tsxsrc/components/settings/sla/SLARuleFormDialog.tsxsrc/components/settings/theme/useThemePreset.tssrc/components/team-chat/TeamChatInputArea.tsxsrc/components/team-chat/TeamChatPanel.tsxsrc/components/team-chat/useTeamChatPanel.tssrc/components/transitions/TransitionProvider.tsxsrc/components/ui/chart.tsxsrc/components/ui/command-palette.tsxsrc/components/ui/registry.jsonsrc/components/voice/FloatingParticles.tsxsrc/features/admin/components/GmailWebhookMonitor.tsxsrc/features/admin/components/SicoobBridgeDashboard.tsxsrc/features/admin/components/TrainingMode.tsxsrc/features/admin/hooks/useAdminManagement.tssrc/features/auth/components/AuthProvider.tsxsrc/features/auth/components/mfa/MFAEnroll.tsxsrc/features/auth/components/mfa/MFAVerify.tsxsrc/features/auth/hooks/usePermissions.tssrc/features/inbox/components/CRMAutoSync.tsxsrc/features/inbox/components/ChatPanel.tsxsrc/features/inbox/components/ContactPurchasesPanel.tsxsrc/features/inbox/components/ConversationHistory.tsxsrc/features/inbox/components/ConversationListSidebar.tsxsrc/features/inbox/components/ConversationMemoryPanel.tsxsrc/features/inbox/components/ConversationSummary.tsxsrc/features/inbox/components/ConversationTasksPanel.tsxsrc/features/inbox/components/LeadRiskScorePanel.tsxsrc/features/inbox/components/NextBestActionEngine.tsxsrc/features/inbox/components/ObjectionDetector.tsxsrc/features/inbox/components/RealtimeInboxView.tsxsrc/features/inbox/components/RemindersPanel.tsxsrc/features/inbox/components/TeamFiles.tsxsrc/features/inbox/components/VoiceChanger.tsxsrc/features/inbox/components/chat/AIEnhanceButton.tsxsrc/features/inbox/components/chat/ChatInputArea.tsxsrc/features/inbox/components/chat/MessageStatusPanel.tsxsrc/features/inbox/components/chat/hooks/useInitialHighlight.tssrc/features/inbox/components/chat/useChatInputLogic.tssrc/features/inbox/components/chat/useChatPanelHandlers.tssrc/features/inbox/components/contact-details/EditContactDialog.tsxsrc/features/inbox/components/conversation-list/ConversationItem.tsxsrc/features/inbox/components/useAudioRecorderUI.tssrc/features/inbox/components/useFileUploadLogic.tssrc/features/inbox/components/useGlobalSearchData.tssrc/features/inbox/hooks/reactions/useBatchReactions.tssrc/features/inbox/hooks/realtime/useAutomationFailureAlerts.tssrc/features/inbox/hooks/sip/useSipConnection.tssrc/features/inbox/hooks/useChatMediaSending.tssrc/features/inbox/hooks/useChatSearch.tssrc/features/inbox/hooks/useMediaUrl.tssrc/features/inbox/hooks/useMessageQueue.tssrc/features/inbox/hooks/useMessageStatus.tssrc/features/inbox/hooks/useMessages.tssrc/features/inbox/hooks/useMessagesCursor.tssrc/features/inbox/hooks/useNewConversation.tssrc/features/inbox/hooks/useRealtimeInbox.tssrc/features/sla/hooks/useSLAAlertPreferences.tssrc/features/sla/hooks/useSLAAlerts.tssrc/features/sla/hooks/useSLACalculation.tssrc/hooks/__tests__/useSpeechToText.test.tssrc/hooks/connections/useConnectionsManagement.tssrc/hooks/connections/useHubTabNavigation.tssrc/hooks/use-toast.tssrc/hooks/useAudioManagement.tssrc/hooks/useAudioRecorder.tssrc/hooks/useAutomationSuggestions.tssrc/hooks/useAutomations.tssrc/hooks/useConversationManagement.tssrc/hooks/useDebounce.tssrc/hooks/useEmail.tssrc/hooks/useEmailManagement.tssrc/hooks/useEvolutionApiManagement.tssrc/hooks/useEvolutionAutoSync.tssrc/hooks/useExternalApiManagement.tssrc/hooks/useExternalEvolution.tssrc/hooks/useGmailOAuthFlow.tssrc/hooks/useImportData.tssrc/hooks/useIndexNavigation.tssrc/hooks/useIntegrationManagement.tssrc/hooks/useNotificationManagement.tssrc/hooks/useOnboarding.tssrc/hooks/useProviderPanel.tssrc/hooks/usePushNotifications.tssrc/hooks/useQueueManagement.tssrc/hooks/useRetryAndErrorPrevention.tssrc/hooks/useTeamChatDraft.tssrc/hooks/useTypingPresence.tssrc/hooks/useVoiceManagement.tssrc/integrations/datasource/db.tssrc/integrations/supabase/safe-queries.tssrc/integrations/supabase/safeClient.test.tssrc/integrations/supabase/safeClient.tssrc/lib/silentErrorPrevention.tssrc/lib/supabaseHelpers.tssrc/pages/OAuthConsent.tsxsrc/pages/admin-realtime-monitor/DispatchErrorsBlock.tsxsrc/pages/admin-realtime-monitor/EventsLiveBlock.tsxsrc/pages/admin-webhook-secret-status/useAdminWebhookStatus.tssrc/pages/admin-webhook-secret-status/useHmacAuditHistory.tssrc/pages/admin/AdminDevDiagnosticsPage.tsxsrc/pages/admin/AdminEmailAuditPage.tsxsrc/pages/admin/Connections.tsxsrc/pages/admin/email/useEmailHealthStatus.tssrc/pages/admin/operations/OpsTransfersTab.tsxsrc/services/api/genericService.tssrc/services/api/mutationFactory.tssrc/services/api/queryFactory.tssrc/services/api/types.tssrc/services/connections/connectionsRepository.tssrc/services/settings/settingsRepository.tssrc/shared/criticalPayloadSchemas.tssrc/test/typing.tssrc/utils/emailMappers.ts
💤 Files with no reviewable changes (11)
- src/features/admin/components/SicoobBridgeDashboard.tsx
- src/pages/admin-webhook-secret-status/useHmacAuditHistory.ts
- src/components/monitoring/useRetryMetricsPanelState.ts
- src/pages/admin-realtime-monitor/DispatchErrorsBlock.tsx
- src/pages/admin-realtime-monitor/EventsLiveBlock.tsx
- src/pages/admin/operations/OpsTransfersTab.tsx
- src/components/dashboard/ConversationHeatmap.tsx
- src/pages/admin-webhook-secret-status/useAdminWebhookStatus.ts
- src/hooks/usePushNotifications.ts
- src/components/transitions/TransitionProvider.tsx
- src/hooks/useExternalApiManagement.ts
| gh pr create \ | ||
| --title "fix: migrate realtime subscriptions from public to zapp schema" \ | ||
| --body "## Summary | ||
|
|
||
| Automated migration of Realtime subscriptions from \`schema: 'public'\` to \`schema: 'zapp'\`. | ||
|
|
||
| ## Why | ||
|
|
||
| The \`public\` schema contains proxy views, not physical tables. Only the \`zapp\` schema has physical tables that are published to Realtime. | ||
|
|
||
| ## Verification | ||
|
|
||
| - [ ] CI passes | ||
| - [ ] Realtime subscriptions work correctly | ||
| - [ ] 1 approval required before merge" \ | ||
| --body $'## Summary\n\nAutomated migration of Realtime subscriptions from `schema: \'public\'` to `schema: \'zapp\'`.\n\n## Why\n\nThe `public` schema contains proxy views, not physical tables. Only the `zapp` schema has physical tables that are published to Realtime.\n\n## Verification\n\n- [ ] CI passes\n- [ ] Realtime subscriptions work correctly\n- [ ] 1 approval required before merge' \ | ||
| --base main |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verifica se existem refs a schema public associadas a mensagens/conversas
rg -n "schema: 'public'" -g '*.ts' -g '*.tsx' -B3 -A3 src/ | rg -i 'evolution_messages|evolution_conversations'Repository: adm01-debug/zapp-web-v3
Length of output: 161
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow =="
git ls-files .github/workflows/fix-schema-refs.yml
wc -l .github/workflows/fix-schema-refs.yml
sed -n '1,140p' .github/workflows/fix-schema-refs.yml
echo
echo "== search schema refs =="
rg -n "schema: 'public'|schema: \"public\"|schema: 'zapp'|schema: \"zapp\"|evolution_messages|evolution_conversations" .
echo
echo "== candidate files mentioning evo tables =="
rg -n "evolution_messages|evolution_conversations" .Repository: adm01-debug/zapp-web-v3
Length of output: 50380
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== .github/workflows/fix-schema-refs.yml (trechos) =="
sed -n '1,140p' .github/workflows/fix-schema-refs.yml
echo
echo "== migração que cita public -> zapp no realtime =="
sed -n '1,120p' supabase/migrations/20260724000026_fix_missing_realtime_publications.sql
echo
echo "== migração de views zapp para evolution_* =="
sed -n '1,90p' supabase/migrations/20260725000012_create_zapp_views_edge_function_tables.sql
echo
echo "== guia do projeto sobre evo/zapp =="
sed -n '40,60p' CLAUDE.mdRepository: adm01-debug/zapp-web-v3
Length of output: 10091
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== ocorrências de schema: 'public' no src =="
rg -n -C 3 "schema: 'public'|schema: \"public\"" src/
echo
echo "== ocorrências de schema: 'public' no supabase/functions =="
rg -n -C 3 "schema: 'public'|schema: \"public\"" supabase/functions
echo
echo "== trechos do arquivo citado com public =="
sed -n '80,110p' src/features/inbox/components/useAudioMessagePlayer.tsRepository: adm01-debug/zapp-web-v3
Length of output: 2167
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== useAudioMessagePlayer.ts =="
sed -n '80,102p' src/features/inbox/components/useAudioMessagePlayer.ts
echo
echo "== useBridgeStatus.ts =="
sed -n '192,210p' src/pages/admin/useBridgeStatus.ts
echo
echo "== busca por voice_conversion_queue =="
rg -n -C 3 "voice_conversion_queue" .
echo
echo "== busca por system_health_incidents =="
rg -n -C 3 "system_health_incidents" .Repository: adm01-debug/zapp-web-v3
Length of output: 50379
Restringe o replace automático
O sed global vai trocar também public.voice_conversion_queue e public.system_health_incidents, que são tabelas físicas/publicadas de verdade. Isso quebra essas subscriptions ao apontá-las para zapp (onde há view proxy/no-op). Limite a migração aos alvos corretos com uma whitelist explícita.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fix-schema-refs.yml around lines 55 - 58, Restrict the
automatic schema replacement in the workflow’s migration step to an explicit
whitelist of intended Realtime subscription targets, excluding
public.voice_conversion_queue and public.system_health_incidents. Update the
sed/replacement logic while preserving the existing PR creation flow in gh pr
create.
| }, [search, categoryId, supplierId, onlyInStock, fetchProducts, buildFilters]); | ||
|
|
||
| // Page changes | ||
| useEffect(() => { | ||
| if (page > 0) fetchProducts(buildFilters()); | ||
| }, [page]); // eslint-disable-line react-hooks/exhaustive-deps | ||
| }, [page, fetchProducts, buildFilters]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
A mudança de página dispara o debounce de filtros e volta para a página 1.
buildFilters depende de page; portanto, ao avançar a paginação, ele muda e reexecuta o efeito de filtros. Após 300 ms, esse efeito executa setPage(0), impedindo permanecer em qualquer página posterior. Separe os filtros-base paginados com useMemo e deixe o debounce depender apenas dos filtros, não de page.
Conforme as coding guidelines, “Estabilizar valores derivados usados em queryKey, dependências de hooks ou paginação com useMemo/estado apropriado”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/catalog/ExternalProductManagement.tsx` around lines 89 - 94,
Impeça que a mudança de página reative o debounce de filtros em
ExternalProductManagement. Separe os filtros-base da paginação em um valor
estabilizado com useMemo, faça o efeito de filtros depender apenas desses
filtros e preserve page apenas no fluxo de busca paginada; ajuste buildFilters e
as dependências dos efeitos para que avançar a página não execute setPage(0).
Source: Coding guidelines
| const startWarmup = async (id: string) => { | ||
| await startReputationWarmup(id); | ||
| toast.success('Aquecimento iniciado'); | ||
| loadData(); | ||
| void loadData(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Não confirme o aquecimento quando o update falhar.
startReputationWarmup em src/hooks/useNumberReputation.ts ignora o { error } do Supabase e sempre resolve. Assim, esta chamada sempre exibe sucesso, mesmo sem atualizar a reputação. Faça o helper lançar/retornar o erro e mostre um toast destrutivo aqui.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/connections/NumberReputationMonitor.tsx` around lines 39 - 42,
Update startReputationWarmup in useNumberReputation to propagate the Supabase
update error instead of always resolving, then adjust startWarmup in
NumberReputationMonitor to show the success toast only after a successful update
and display a destructive toast when the helper fails.
| const fetchWhitelistedIPs = useCallback(async () => { | ||
| setLoading(true); | ||
| const data = await fetchIPWhitelist(); | ||
| if (!mountedRef.current) return; | ||
| setWhitelistedIPs(data); | ||
| setLoading(false); | ||
| }; | ||
| }, [mountedRef]); | ||
|
|
||
| useEffect(() => { | ||
| fetchWhitelistedIPs(); | ||
| }, [mountedRef]); | ||
| }, [fetchWhitelistedIPs]); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Trate falhas do carregamento.
Se fetchIPWhitelist() rejeitar, o efeito gera uma Promise não tratada e o spinner pode permanecer ativo. Capture o erro e mova setLoading(false) para um finally protegido por mountedRef.current; isso também cobre as chamadas dos handlers.
As per path instructions, “Promises sem await ou .catch().”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/security/IPWhitelistPanel.tsx` around lines 53 - 63, Handle
rejection in fetchWhitelistedIPs by wrapping fetchIPWhitelist and the state
update in try/finally, ensuring the returned Promise is caught by the useEffect
invocation and handler callers. Move setLoading(false) into a finally block
guarded by mountedRef.current, while preserving the existing mounted check
before updating whitelisted IPs.
Source: Path instructions
| const loadSessions = useCallback(async () => { | ||
| if (!profileId) return; | ||
| const { data } = await supabase | ||
| .from('training_sessions') | ||
| .select('*') | ||
| .eq('profile_id', profileId) | ||
| .order('created_at', { ascending: false }) | ||
| .limit(10); | ||
| if (data) setSessions(data); | ||
| }, [profileId]); | ||
|
|
||
| useEffect(() => { | ||
| if (profileId) loadSessions(); | ||
| }, [profileId]); // eslint-disable-line react-hooks/exhaustive-deps | ||
| }, [profileId, loadSessions]); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
Capture falhas de loadSessions.
A consulta pode rejeitar em falhas de rede, mas loadSessions não captura erros e o efeito a chama sem await nem .catch(). Trate o erro dentro de loadSessions ou use void loadSessions().catch(...); isso também protege a chamada posterior na conclusão do cenário.
Conforme as path instructions, verifique “Promises sem await ou .catch()”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/features/admin/components/TrainingMode.tsx` around lines 80 - 93, Capture
rejected promises from loadSessions by handling the Supabase query error inside
the callback or attaching a catch handler to every effect invocation, including
the later scenario-completion call. Ensure the effect does not leave
loadSessions unhandled while preserving the existing session-loading behavior.
Source: Path instructions
| const { operation = 'Async effect', cleanup, fallback, dependencies } = options ?? {}; | ||
|
|
||
| const effectRef = useRef(effect); | ||
| effectRef.current = effect; | ||
| const cleanupRef = useRef(cleanup); | ||
| cleanupRef.current = cleanup; | ||
| const fallbackRef = useRef(fallback); | ||
| fallbackRef.current = fallback; | ||
| const abortRef = useRef<AbortController | null>(null); | ||
|
|
||
| useEffect(() => { | ||
| abortRef.current = new AbortController(); | ||
|
|
||
| (async () => { | ||
| try { | ||
| await withErrorRecovery(effect, { | ||
| operation: options?.operation || 'Async effect', | ||
| await withErrorRecovery(effectRef.current, { | ||
| operation, | ||
| shouldThrow: false, | ||
| }); | ||
| } catch (error) { | ||
| log.error(`Async effect failed: ${options?.operation || 'Unknown'}`, error); | ||
| options?.fallback?.(); | ||
| log.error(`Async effect failed: ${operation}`, error); | ||
| fallbackRef.current?.(); | ||
| } | ||
| })(); | ||
|
|
||
| return () => { | ||
| abortRef.current?.abort(); | ||
| options?.cleanup?.(); | ||
| cleanupRef.current?.(); | ||
| }; | ||
| }, options?.dependencies); // eslint-disable-line react-hooks/exhaustive-deps | ||
| }, [operation]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n -C 3 --glob '*.{ts,tsx}' \
'useAsyncEffect\s*\(|dependencies\s*:' srcRepository: adm01-debug/zapp-web-v3
Length of output: 161
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Mapear o arquivo e localizar o hook/assinaturas relacionadas
ast-grep outline src/hooks/useRetryAndErrorPrevention.ts --view expanded || true
echo '---'
rg -n -C 4 --glob 'src/**/*.{ts,tsx}' \
'dependencies\s*:|useRetryAndErrorPrevention|useAsyncEffect|withErrorRecovery' srcRepository: adm01-debug/zapp-web-v3
Length of output: 9702
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '291,335p' src/hooks/useRetryAndErrorPrevention.tsRepository: adm01-debug/zapp-web-v3
Length of output: 1338
dependencies está sendo ignorado pelo hook. O useEffect só depende de operation, então mudanças passadas por quem usa useAsyncEffect não disparam nova execução; ou conecte dependencies ao efeito, ou remova essa opção da API.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/hooks/useRetryAndErrorPrevention.ts` around lines 300 - 329, Conecte a
opção dependencies ao array de dependências do useEffect no fluxo de
useAsyncEffect, preservando operation como dependência existente para que
alterações recebidas pelo consumidor disparem novamente o efeito. Não remova
dependencies da API; use o valor já desestruturado em options.
| type DynamicTableClient = { from(t: string): ReturnType<typeof supabase.from> }; | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| export function dbFrom(entity: LogicalEntity): any { | ||
| const mapping = requireMapping(entity); | ||
| validateEntityAccess(mapping.table, mapping.client); | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| return dbClient(entity).from(mapping.table as any); | ||
| return (dbClient(entity) as unknown as DynamicTableClient).from(mapping.table); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Não propague any pelo acesso dinâmico.
dbFrom é um ponto central e seu retorno any remove a validação de colunas, payloads e resultados de todas as consultas downstream. Retorne ReturnType<typeof supabase.from> — como já feito em src/lib/supabaseHelpers.ts — ou um builder explicitamente limitado.
Correção sugerida
-export function dbFrom(entity: LogicalEntity): any {
+export function dbFrom(entity: LogicalEntity): ReturnType<typeof supabase.from> {As per path instructions: **/*.{ts,tsx,js,jsx}: verificar any/unknown sem narrowing posterior.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| type DynamicTableClient = { from(t: string): ReturnType<typeof supabase.from> }; | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| export function dbFrom(entity: LogicalEntity): any { | |
| const mapping = requireMapping(entity); | |
| validateEntityAccess(mapping.table, mapping.client); | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| return dbClient(entity).from(mapping.table as any); | |
| return (dbClient(entity) as unknown as DynamicTableClient).from(mapping.table); | |
| type DynamicTableClient = { from(t: string): ReturnType<typeof supabase.from> }; | |
| // eslint-disable-next-line `@typescript-eslint/no-explicit-any` | |
| export function dbFrom(entity: LogicalEntity): ReturnType<typeof supabase.from> { | |
| const mapping = requireMapping(entity); | |
| validateEntityAccess(mapping.table, mapping.client); | |
| return (dbClient(entity) as unknown as DynamicTableClient).from(mapping.table); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/integrations/datasource/db.ts` around lines 63 - 69, Remova o retorno
explícito como any de dbFrom e faça a função retornar ReturnType<typeof
supabase.from>, reutilizando o tipo já empregado em supabaseHelpers.ts. Preserve
o fluxo de requireMapping, validateEntityAccess e dbClient, ajustando apenas a
tipagem do cliente dinâmico e do retorno para evitar propagar any sem narrowing
posterior.
Source: Path instructions
| // Accept clients bound to either schema (zapp is canonical, public via view proxy). | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| type AnySupabaseClient = SupabaseClient<Database, any, any, any, any>; | ||
| type AnySupabaseClient = SupabaseClient<Database, string>; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
npx tsc --noEmit --pretty false 2>&1 | rg 'src/integrations/supabase/safe-queries.ts|TS2344|SchemaName'Repository: adm01-debug/zapp-web-v3
Length of output: 161
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## safe-queries.ts\n'
cat -n src/integrations/supabase/safe-queries.ts | sed -n '1,120p'
printf '\n## supabase package version\n'
node - <<'JS'
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const ver = pkg.dependencies?.['`@supabase/supabase-js`'] || pkg.devDependencies?.['`@supabase/supabase-js`'] || '(not found)';
console.log(ver);
JS
printf '\n## SupabaseClient type signature in installed types (if present)\n'
rg -n "type SchemaName|class SupabaseClient|interface SupabaseClient" node_modules/@supabase -g '*.d.ts' -g '*.ts' | sed -n '1,120p'Repository: adm01-debug/zapp-web-v3
Length of output: 4957
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## relevant local type definitions for Database\n'
rg -n "export type Database|type Database" src/integrations/supabase -g '*.ts' -g '*.tsx' | sed -n '1,80p'
printf '\n## usages of AnySupabaseClient and schema()\n'
rg -n "AnySupabaseClient|schema\\('evo'\\)|schema\\('zapp'\\)" src/integrations/supabase src -g '*.ts' -g '*.tsx' | sed -n '1,160p'Repository: adm01-debug/zapp-web-v3
Length of output: 2106
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('src/integrations/supabase/safe-queries.ts')
text = p.read_text()
print(text)
PYRepository: adm01-debug/zapp-web-v3
Length of output: 7694
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## safe-queries.ts"
cat -n src/integrations/supabase/safe-queries.ts | sed -n '1,120p'
echo
echo "## Database type"
rg -n "export type Database|type Database" src/integrations/supabase -g '*.ts' -g '*.tsx' | sed -n '1,80p'
echo
echo "## SupabaseClient declaration"
if [ -d node_modules/@supabase ]; then
rg -n "class SupabaseClient|type SchemaName" node_modules/@supabase -g '*.d.ts' -g '*.ts' | sed -n '1,120p'
else
echo "node_modules/@supabase not present"
fiRepository: adm01-debug/zapp-web-v3
Length of output: 5152
🌐 Web query:
SupabaseClient generic schema parameter string keyof Database TS2344 @supabase/supabase-js 2.110.0
💡 Result:
The TS2344 error ("Type '...' does not satisfy the constraint '...'") related to the SupabaseClient generic schema parameter typically occurs when TypeScript fails to infer the correct SchemaName generic or when the provided schema does not match the expected constraints defined in the Database type [1][2]. In versions of @supabase/supabase-js, the SupabaseClient is defined with generic parameters that include SchemaName extends string & keyof Database [1]. This ensures that the schema you pass (or the default 'public') exists within your generated Database interface [1]. Common causes and solutions for this error include: 1. Incomplete or Mismatched Database Types: Ensure your generated Database type actually includes the schema you are trying to use. If your database types were generated without including specific schemas, they will not be present in keyof Database [1][3]. 2. Inference Limitations: When initializing the client with createClient<Database>(...), if you do not explicitly provide the second generic argument (SchemaName), TypeScript may default it to 'public' [4]. If 'public' is not part of your Database type (e.g., you are using a different schema structure), or if the inference is constrained by other options, a TS2344 error may occur [4][2]. 3. Workaround for Initialization: You can often resolve this by explicitly passing the schema name as the second generic parameter during client instantiation [4]: const supabase = createClient<Database, 'your_schema_name'>(URL, KEY); 4. Type Relaxation: If you are encountering this error specifically in the client options.db.schema configuration, recent updates in the library have aimed to relax these constraints [4]. Ensure you are using the latest version of the library (2.110.0 or later) [5][6], as maintainers frequently adjust these type definitions to improve compatibility with complex custom schemas [4]. If you are using @supabase/ssr, ensure your createClient wrappers are correctly passing the generic types through to the underlying SupabaseClient instance [7][2]. If the error persists after explicitly defining the schema, double-check that your generated types file (database.types.ts) includes the target schema and that your Database interface is correctly exported [3].
Citations:
- 1: https://github.com/supabase/supabase-js/blob/b8a5d7137de9985d09fb5820b444b1f7a8a580f3/src/SupabaseClient.ts
- 2: @supabase/supabase-js v2.50.4 breaks types supabase/supabase-js#1483
- 3: https://supabase.com/docs/reference/javascript/typescript-support
- 4: fix(supabase): relax db schema type constraints in createClient options supabase/supabase-js#2476
- 5: https://github.com/supabase/supabase-js/releases/tag/v2.110.0
- 6: https://github.com/supabase/supabase-js/blob/HEAD/CHANGELOG.md
- 7: fix(types): export type utils for ssr use supabase/supabase-js#1491
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## schema.ts"
cat -n src/integrations/supabase/schema.ts | sed -n '1,220p'
echo
echo "## top of types.ts around Database"
cat -n src/integrations/supabase/types.ts | sed -n '1,120p'Repository: adm01-debug/zapp-web-v3
Length of output: 6969
🏁 Script executed:
#!/bin/bash
set -euo pipefail
log=/tmp/coderabbit-shell-logs/shell-output-LtG4Cv
echo "## log head"
sed -n '1,220p' "$log"Repository: adm01-debug/zapp-web-v3
Length of output: 173
🌐 Web query:
@supabase/supabase-js v2.110.0 SupabaseClient class signature SchemaName extends string keyof Database source
💡 Result:
In @supabase/supabase-js v2.110.0, the SupabaseClient class is defined with three primary generic type parameters [1][2][3]. Its class signature is structured as follows [3]: export default class SupabaseClient< Database = any, SchemaNameOrClientOptions extends (string & keyof Omit<Database, 'InternalSupabase'>) | { PostgrestVersion: string } =..., SchemaName extends string & keyof Omit<Database, 'InternalSupabase'> =..., Schema extends... =..., ClientOptions extends { PostgrestVersion: string } =... > {... } Key aspects of the SchemaName type parameter: 1. Definition: The SchemaName parameter is constrained as SchemaName extends string & keyof Omit<Database, 'InternalSupabase'> [1][3]. It represents the specific database schema being targeted by the client instance [4][5]. 2. Purpose: It facilitates type-safe database queries by restricting access to tables and views within the specified schema [3][6]. 3. Default Behavior: By default, if not explicitly provided, the type system attempts to resolve the schema to 'public' if it exists within the provided Database definition; otherwise, it defaults to the available keys in the Database type [1][3]. 4. Relationship with SchemaNameOrClientOptions: In modern versions of the library (following changes introduced around v2.50.4), the second generic parameter, SchemaNameOrClientOptions, allows for specifying either the schema name or client configuration options (such as PostgrestVersion) [3][7]. The SchemaName parameter is then derived based on these inputs to ensure compatibility with both legacy patterns and newer requirements for SSR and version-specific PostgREST features [3][7]. For most users, the standard usage involves passing the Database type generated by the Supabase CLI, which then automatically populates these generic parameters correctly [6].
Citations:
- 1: https://jsr.io/@supabase/supabase-js/doc/all_symbols
- 2: https://jsr.io/@supabase/supabase-js/doc
- 3: https://github.com/supabase/supabase-js/blob/21e9d4b7/packages/core/supabase-js/src/SupabaseClient.ts
- 4: https://supabase.com/docs/reference/javascript/initializing
- 5: https://github.com/supabase/supabase-js/blob/21e9d4b7/packages/core/supabase-js/src/lib/types.ts
- 6: https://supabase.com/docs/reference/javascript/typescript-support
- 7: fix(types): export type utils for ssr use supabase/supabase-js#1491
Restrinja AnySupabaseClient a schemas válidos.
SupabaseClient<Database, string> viola a constraint do generic de schema. Use uma união explícita dos schemas suportados (public | zapp) — ou derive isso de keyof Omit<Database, '__InternalSupabase'> — para manter o helper tipado sem quebrar o build.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/integrations/supabase/safe-queries.ts` at line 14, Atualize o alias
AnySupabaseClient para restringir o parâmetro de schema à união válida "public"
| "zapp" (ou derivá-la de keyof Omit<Database, "__InternalSupabase">),
substituindo o string amplo em SupabaseClient<Database, ...> e preservando a
tipagem compatível com a constraint do generic.
| useEffect(() => { | ||
| if (isDev) { | ||
| void loadLogs(); | ||
| void logAccess(); | ||
| void logAccess(isDev); | ||
| } | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [isDev]); | ||
| }, [isDev, loadLogs]); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
Capture rejeições das operações disparadas com void.
loadLogs() e logAccess(isDev) podem rejeitar sem .catch(). Em especial, loadLogs não possui try/catch/finally, deixando loading ativo caso a consulta lance. Trate o erro dentro das funções ou capture as promessas nas chamadas.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/admin/AdminDevDiagnosticsPage.tsx` around lines 76 - 81, Handle
rejected promises from loadLogs and logAccess in the useEffect for
AdminDevDiagnosticsPage: add appropriate try/catch/finally handling inside those
functions, ensuring loadLogs always clears its loading state when the query
fails, or attach catches at both void call sites. Preserve the existing isDev
guard and dependency array.
Source: Path instructions
| (options?.onSuccess as ((d: unknown, v: unknown, c: unknown) => void) | undefined)?.( | ||
| data, | ||
| variables, | ||
| context | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
fd -i -e ts -e tsx -e json -e lock . \
| xargs -r rg -n "UseMutationOptions|MutationFunctionContext|`@tanstack/react-query`"Repository: adm01-debug/zapp-web-v3
Length of output: 30200
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '\n## mutationFactory.ts\n'
sed -n '1,280p' src/services/api/mutationFactory.ts | cat -n
printf '\n## queryFactory.ts\n'
sed -n '1,220p' src/services/api/queryFactory.ts | cat -n
printf '\n## package.json TanStack deps\n'
rg -n '"`@tanstack/react-query`"|`@tanstack/query-core`' package.json bun.lockRepository: adm01-debug/zapp-web-v3
Length of output: 17597
🌐 Web query:
TanStack Query v5 useMutation onSuccess onError signature async promise data variables context official docs
💡 Result:
In TanStack Query v5, the onSuccess and onError callback signatures in useMutation (and when passed to mutate) follow a specific structure involving the mutation result, variables, the optional context returned from onMutate, and the mutation function context [1][2][3]. As of v5.89.0, the signatures for these callbacks are [3]: onSuccess: (data: TData, variables: TVariables, onMutateResult: TOnMutateResult | undefined, context: MutationFunctionContext) => void onError: (err: TError, variables: TVariables, onMutateResult: TOnMutateResult | undefined, context: MutationFunctionContext) => void Key signature details: - data / err: The result (on success) or the error object (on error) [1][2]. - variables: The variables passed to the mutation function [1][2]. - onMutateResult: The value returned by your onMutate callback [4]. This will be undefined if no onMutate is defined or if onMutate does not return a value [3]. - context: The mutation function context [3]. Behavior of async and promises: - When defined within the useMutation hook options, returning a promise from onSuccess or onError will cause the hook to await that promise before proceeding to the next step in the mutation lifecycle (e.g., before executing onSettled) [1][2][5]. - When passed directly to the mutate function, onSuccess and onError are triggered for that specific call [4][6]. - You can use mutateAsync if you need to receive a promise that resolves on success or throws on error, which is useful for composing side effects [6]. Important note on updates: A recent change (introduced in v5.89.0) added a fourth parameter (mutation function context) to these callbacks [3]. If you are migrating code that previously relied on a specific number of positional arguments, ensure your callback signatures are updated to accommodate the new parameter structure [3]. Callbacks defined in useMutation execute for every mutate call, whereas callbacks passed directly to the mutate function run only once and only if the component remains mounted [4][6].
Citations:
- 1: https://tanstack.com/query/v5/docs/framework/react/reference/useMutation.md
- 2: https://tanstack.com/query/latest/docs/framework/react/reference/useMutation
- 3: v5.89.0: onError, onSuccess and onSettled signature change breaks existing code TanStack/query#9660
- 4: https://tanstack.com/query/v5/docs/framework/react/guides/mutations
- 5: https://github.com/tanstack/query/blob/main/docs/framework/react/reference/useMutation.md
- 6: https://tanstack.com/query/latest/docs/framework/react/guides/mutations
Não deixe ...options sobrescrever os callbacks internos. onSuccess/onError precisam vir depois do spread das opções; hoje um callback do consumidor substitui invalidações/toasts e o wrapper também perde o 4º argumento do TanStack Query v5. Faça o wrapper repassar data, variables, onMutateResult, context e await/return dos callbacks assíncronos em todas as factories.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/services/api/mutationFactory.ts` around lines 59 - 63, Atualize todas as
factories de mutação em torno dos callbacks onSuccess e onError para aplicar
...options antes dos callbacks internos, impedindo que opções do consumidor os
sobrescrevam. Faça os wrappers repassarem os quatro argumentos do TanStack Query
v5 — data, variables, onMutateResult e context — e aguardarem/retornarem
callbacks assíncronos, preservando invalidações e toasts.
Sources: Path instructions, MCP tools
Conflicts resolved by accepting main's canonical changes:
- ExternalProductManagement: buildFilters(page) explicit arg
- ConversationSummary: unconditional summary reset on contact change
- useChatMediaSending: add contactPhone to dep arrays (x2)
- useRealtimeInbox: remove reconcile useEffect (removed in main)
- useAudioManagement: drop stable setBlobUrl from dep array
- useTypingPresence: void .track().catch(()=>{}) pattern
- useVoiceManagement: lang (not language) in SpeechRecognitionInstance
- silentErrorPrevention: ignore-audit comment on AnyFn
- AdminDevDiagnosticsPage: browser field from userAgent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jZX3jD8iLBNBqvgPVLBnE
|
Deployment failed with the following error: |
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
|
Descrição
Follow-up to merged PR #584. Resolves 9 remaining
react-hooks/exhaustive-depsviolations that were missed in the original batches, plus removes a build-breaking duplicate function body inuseSipConnection.tsleft by the merge conflict resolution.Tipo de mudança
fix: Correção de bugAlterações
useSipConnection.ts— build-breaking duplicate bodyThe merge conflict resolution for PR #584 left the
connectuseCallback with itstry/catchbody duplicated: HEAD's complete try/catch remained, then main's try body was appended as dead code followed by an orphanedcatchwith no matchingtry. esbuild failed withExpected ")" but found "catch". Removed the 58 dead-code lines.useAudioRecorder.ts— 3 fixesuseEffect(unmount cleanup): addedcleanupRecordingResourcesto deps array (it is auseCallbackwith[]deps — stable, but ESLint requires it declared)cancelRecording: addedsetBlobUrlto deps (called at line 351;setBlobUrlis auseCallbackwith[]deps)restoreRecording: addedsetBlobUrlto deps (called at line 359)useAudioManagement.ts— 3 fixesstartRecording: addedsetBlobUrlto[maxDuration, onRecordingComplete](called at line 854)cancelRecording: addedsetBlobUrlto[isRecording, isPaused, transcription](called at line 1072)restoreRecording: addedsetBlobUrlto[onRecordingComplete](called at line 1081)useChatMediaSending.ts— 3 fixeshandleSendSticker,handleSendCustomEmoji,handleSendAudioMeme: removedcontactPhonefrom all three dep arrays.contactPhoneis not referenced directly in these callbacks — it is captured bygetSafePhone(already in the dep array), which closes overcontactPhonevia its own[contactPhone]dep.Checklist de qualidade
Para todo PR
tipo: descrição em minúsculas)bun run build→✓ built in 1m 57s)tsc --noEmit --skipLibCheck→ 0 erros)Para PRs com
fix:Testes relacionados
None added. The changes are dep-array corrections — adding stable
useCallbackrefs that ESLint requires declared. Adding them does not change runtime behavior (stable identity means no extra re-registrations). The build + typecheck serve as the primary validation gate.Notas para o revisor
setBlobUrlin both audio hooks is auseCallback(() => {...}, [])— its identity never changes, so adding it to dep arrays is semantically a no-op at runtime but required by ESLint for correctness.contactPhonefrom the three media-sending callbacks is safe: the rule flags it as unnecessary because none of those callbacks referencecontactPhonedirectly in their bodies;getSafePhone(already in deps) handles the capture.Generated by Claude Code
Summary by cubic
Fixes a build failure in
useSipConnection, completes thereact-hooks/exhaustive-depsaudit across the app, restores CI workflows so required checks run reliably, and reconciles withmainwhile keeping our hook fixes; also bumps a few dependencies and restores a corrupted audio player component.Bug Fixes
useSipConnection: removed duplicatedconnecttry/catch body and centralized reconnect limits; teardown no longer triggers auto-reconnect.react-hooks/exhaustive-depsfixes across hooks/components; resolved merge withmainwithout losing these corrections..github/workflows/ci-gate.yml,pr-size-gate.yml,fix-schema-refs.yml, andts-nocheck-ratchet.ymlto restore the “ci” status gate and other checks.AudioMessagePlayer: restored the file from corrupted content and added unsubscribe-before-remove cleanup to prevent Realtime leaks.Refactors
@sentry/reactto10.68.0,web-vitalsto6.0.1, and@commitlint/*to21.x; syncedbun.lock; restructuredsrc/components/ui/registry.json(no functional changes).main’s canonical updates in several areas (e.g., explicit filter args, SpeechRecognitionlang, userAgentbrowserfield) while retaining this branch’s type-safety and lint cleanup.Written for commit a13acb7. Summary will update on new commits.
Summary by CodeRabbit
Novos recursos
Correções