Skip to content

fix(contracts): destravar deno check de 15 edge functions (TS2345 em parseContract)#103

Closed
adm01-debug wants to merge 3 commits into
mainfrom
fix/edge-contracts-deno-typecheck
Closed

fix(contracts): destravar deno check de 15 edge functions (TS2345 em parseContract)#103
adm01-debug wants to merge 3 commits into
mainfrom
fix/edge-contracts-deno-typecheck

Conversation

@adm01-debug
Copy link
Copy Markdown
Owner

@adm01-debug adm01-debug commented May 22, 2026

Problema

O workflow CI na main (run #404, commit ca9ca9c) está vermelho. Um dos jobs que falha é Edge Functions — Deno typecheck (node scripts/typecheck-edge-functions.mjs), que quebrava em 15 edge functions que usam parseContract:

bi-copilot, block-ip-temporarily, e2e-cleanup, force-global-logout, kit-ai-builder, market-intelligence-insights, ownership-audit, ownership-repair, product-webhook, send-transactional-email, simulation-orchestrator, step-up-verify, sync-external-db, trends-insights, webhook-dispatcher.

Erro (TS2345):

Argument of type '{ name: string; versions: {...} }' is not assignable to parameter
of type 'ContractSchemas<"1"> & { versions: {...} }'.
  The types returned by 'versions["1"].deepPartial()' are incompatible between these types.
    Type 'ZodOptional<ZodString>' is missing the following properties from type 'ZodString'...

Causa raiz

A assinatura do helper era:

parseContract<V extends string, S extends Record<V, z.ZodTypeAny>>(
  req: Request,
  schemas: ContractSchemas<V> & { versions: S },
  ...
)

A interseção ContractSchemas<V> & { versions: S } força o tipo de versions[k] a virar z.ZodTypeAny & ZodObject<...>. Ao verificar a atribuição do schema concreto, o checker recursa no tipo de retorno de ZodObject.deepPartial() (que referencia o próprio shape com campos tornados opcionais), estourando com variância incompatível. Só dispara em schemas com shape específico — por isso webhook-inbound (shape diferente) passava enquanto os outros 15 falhavam.

Fix

Generalizar parseContract sobre o tipo do objeto de schemas (C extends ContractSchemas), removendo a interseção:

  • versions[k] deixa de ser comparado contra uma interseção com ZodTypeAny → some a recursão em deepPartial().
  • data é inferido por indexação direta do schema da versão default (InferContractData<C>), preservando o tipo que os handlers consomem.
  • version passa a string (já era resolvida em runtime via resolveContractVersion).
  • Nenhum call site externo referencia os tipos ParseResult/ContractSchemas — mudança compatível. Os 16 handlers só usam parseContract(...), checam .ok e desestruturam .data/.version/.responseHeaders.

Verificação

Local, com node scripts/typecheck-edge-functions.mjs (mesmo comando do CI), via Deno 2.7.14:

81/81 edge functions compilam limpo (antes: 15 com erro, exit 1).

Diff cirúrgico: 1 arquivo (supabase/functions/_shared/contracts/parse.ts), apenas tipos + casts internos; zero mudança de comportamento em runtime.


Nota: o CI da main tem outros 2 jobs vermelhos (Lint, Typecheck & Test → step "Run tests"; Test Coverage) na suíte vitest, em investigação separada. Este PR fecha especificamente o job de typecheck das edge functions.

Co-authored-by: Claude noreply@anthropic.com


Summary by cubic

Destrava o job “Edge Functions — Deno typecheck” ao corrigir o TS2345 em parseContract que quebrava 15 funções. O retorno agora preserva a type-safety multi‑versão sem alterar o comportamento em runtime.

  • Bug Fixes

    • Generaliza parseContract para C extends ContractSchemas e remove a interseção que forçava ZodTypeAny & ZodObject.
    • Indexa schemas.versions[version] diretamente (sem interseção), eliminando a recursão de deepPartial(); resultado: 81/81 edge functions passam no deno check.
  • Refactors

    • ParseResult<C> vira união discriminada por version; data casa com o schema da versão retornada.
    • version passa a ser "1" | "2" | ... (não string).

Written for commit c47af9a. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • Refactor
    • API pública de parsing simplificada para maior consistência e facilidade de uso.
    • Parsing agora mantém correlação entre versão e conteúdo retornado, oferecendo respostas mais previsíveis e seguras.
    • Melhorias internas reduzem ambiguidade na validação, resultando em comportamento de parsing mais robusto.

Review Change Stack

…parseContract)

O job "Edge Functions — Deno typecheck" do CI quebrava em 15 functions que
usam parseContract (bi-copilot, block-ip-temporarily, e2e-cleanup,
force-global-logout, kit-ai-builder, market-intelligence-insights,
ownership-audit, ownership-repair, product-webhook, send-transactional-email,
simulation-orchestrator, step-up-verify, sync-external-db, trends-insights,
webhook-dispatcher) com TS2345:

  "The types returned by versions[\"1\"].deepPartial() are incompatible..."

Causa raiz: a assinatura

  parseContract<V, S extends Record<V, z.ZodTypeAny>>(
    req, schemas: ContractSchemas<V> & { versions: S }, ...)

forcava, via a intersecao `ContractSchemas<V> & { versions: S }`, o tipo de
`versions[k]` a virar `z.ZodTypeAny & ZodObject<...>`. Ao verificar a
atribuicao, o checker recursa no retorno de `ZodObject.deepPartial()`
(metodo cujo tipo de retorno referencia o proprio shape), estourando com
variancia incompativel. So disparava em schemas com shape especifico (por isso
webhook-inbound, com schema diferente, passava).

Fix: generalizar `parseContract` sobre o tipo do objeto de schemas (`C extends
ContractSchemas`) e remover a intersecao. `versions[k]` deixa de ser comparado
contra uma intersecao com ZodTypeAny — some a recursao. `data` e inferido por
indexacao direta do schema da versao default (`InferContractData<C>`),
preservando o comportamento de tipo dos handlers. `version` passa a `string`
(ja era resolvida em runtime). Nenhum call site externo referencia os tipos
`ParseResult`/`ContractSchemas`, entao a mudanca e compativel.

Verificado localmente com `node scripts/typecheck-edge-functions.mjs`:
81/81 edge functions compilam limpo (antes: 15 com erro).

Co-authored-by: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 22, 2026 12:20
@vercel
Copy link
Copy Markdown

vercel Bot commented May 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
we-dream-big Ready Ready Preview, Comment May 23, 2026 11:05am

@supabase
Copy link
Copy Markdown

supabase Bot commented May 22, 2026

This pull request has been ignored for the connected project doufsxqlfjyuvxuezpln due to reaching the limit of concurrent preview branches.
Go to Project Integrations Settings ↗︎ if you wish to update this limit.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ee8e59bb-d0cc-4fdf-8a3e-0bc19a3715c8

📥 Commits

Reviewing files that changed from the base of the PR and between af130d2 and c47af9a.

📒 Files selected for processing (1)
  • supabase/functions/_shared/contracts/parse.ts

Walkthrough

ParseResult e parseContract foram retipados para derivar data diretamente de C["versions"]. A assinatura pública agora usa um único genérico C extends ContractSchemas e a seleção do schema em runtime e o retorno de sucesso foram ajustados para alinhar com essa correlação versão↔data.

Changes

Refatoração de Contrato de Parseamento

Layer / File(s) Summary
Tipos auxiliares e ParseResult
supabase/functions/_shared/contracts/parse.ts
Redefine ParseResult<C> como união que correlaciona version e data usando chaves de C["versions"] e atualiza tipos auxiliares para inferência baseada em C.
Indexação runtime e retorno tipado
supabase/functions/_shared/contracts/parse.ts
Seleciona o schema em runtime usando keyof C["versions"] e retorna o objeto de sucesso com cast explícito para ParseResult<C> devido a limitações de inferência dentro do corpo genérico.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs:

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed O título descreve com precisão o problema resolvido: fix de TS2345 no typecheck do Deno que destravava 15 edge functions, correlacionando diretamente com a causa raiz (reimplementação de parseContract).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/edge-contracts-deno-typecheck

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts the TypeScript typings of the shared parseContract helper used by Supabase Edge Functions to avoid a TS+Zod variance recursion (TS2345) that was breaking deno check across multiple functions.

Changes:

  • Refactors parseContract to be generic over the whole ContractSchemas object (C extends ContractSchemas), removing the problematic intersection type.
  • Introduces DefaultSchema / InferContractData helper types and updates ParseResult to infer data from the contract’s default schema.
  • Loosens version typing to string and adds internal casts to keep runtime behavior unchanged while unblocking Deno typechecking.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread supabase/functions/_shared/contracts/parse.ts Outdated
Comment thread supabase/functions/_shared/contracts/parse.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: af130d2d2f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

version: version as V,
data: result.data,
version,
data: result.data as InferContractData<C>,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve data typing for negotiated contract version

parseContract now always casts result.data to InferContractData<C>, which is derived from defaultVersion rather than the negotiated version. For contracts with divergent schemas across versions (for example several "1"/"2" schema pairs in this repo), a request with accept-version: 2 can return v2-shaped data while the function advertises v1-shaped data, removing type safety and allowing handlers to compile with field assumptions that are false at runtime for non-default versions.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@supabase/functions/_shared/contracts/parse.ts`:
- Around line 62-67: ParseResult currently types version as string and data as
the defaultVersion shape (InferContractData<C>), which breaks the runtime
correlation between the resolved version and the parsed data; update the typings
so the returned version and data are linked to the actual resolved schema from
resolveContractVersion/schemas.versions. Concretely, make ParseResult (and
parseContract's return type) parametric or discriminated by V extends keyof
C["versions"] (use that key type instead of string) and type data as
z.infer<C["versions"][V]> (or produce a union of {version: V; data:
z.infer<...>} for each V) so the compile-time type matches the runtime
validation performed in parseContract/resolveContractVersion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 112535d2-380a-48c0-91ed-778236965648

📥 Commits

Reviewing files that changed from the base of the PR and between 1f3621c and af130d2.

📒 Files selected for processing (1)
  • supabase/functions/_shared/contracts/parse.ts

Comment thread supabase/functions/_shared/contracts/parse.ts Outdated
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread supabase/functions/_shared/contracts/parse.ts Outdated
…pe-safety multi-versao)

Atende aos reviews automáticos (Copilot/Codex/CodeRabbit/cubic, P2) no PR #103.

Contexto: o fix anterior tipava `data` como `InferContractData<C>` (sempre o
shape da defaultVersion). Como TODOS os 16 contratos têm v1 e v2 com shapes
DIVERGENTES (strict, discriminated unions, campos obrigatórios distintos), isso
apagava a type-safety para a versão não-default: um request com accept-version:2
retornava data v2 em runtime, mas o tipo anunciava v1.

Mudança: `ParseResult<C>` passa a ser uma UNIÃO discriminada por versão —
`{ version: "1"; data: v1 } | { version: "2"; data: v2 } | ...` — derivada de
`C["versions"]`. Agora `version` é `"1" | "2"` (não `string`) e `data` casa com
o schema da versão correspondente, mantendo version↔data correlacionados em
compile-time.

Preserva a correção do TS2345: continuamos indexando os schemas diretamente,
sem a interseção `ContractSchemas<V> & { versions: S }` que fazia o checker
recursar em `ZodObject.deepPartial()`. O return usa um cast para `ParseResult<C>`
(o TS colapsa a união mapeada para `never` sobre `C` não-resolvido dentro do
corpo genérico; a validação real é feita por resolveContractVersion+safeParse).

Verificado: `node scripts/typecheck-edge-functions.mjs` → 81/81 limpas.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@adm01-debug
Copy link
Copy Markdown
Owner Author

Fechando como redundante — bug já corrigido na main pelo #115

Auditoria de 2026-05-23: revalidei contra a main atual (ab444ff) e o bug-alvo deste PR já foi resolvido e mergeado pelo #115 (0c650ca — "fix(contracts): infer V from keyof S & string in parseContract to fix TS2345 in 15 edge functions").

Evidência:

  • Job Edge Functions — Deno typecheck na main (ab444ff) = success.
  • node scripts/typecheck-edge-functions.mjs na main local → 81/81 functions limpas, exit 0.

As duas abordagens são equivalentes no efeito (ambas removem a interseção ContractSchemas<V> & { versions: S } que fazia o checker recursar em ZodObject.deepPartial() → TS2345) e ambas preservam a type-safety multi-versão:

Como o #115 já está na main, manter o #103 só geraria um conflito garantido em parse.ts sem benefício adicional. Fechando sem merge. Os comentários P2 de type-safety levantados pelos reviewers automáticos aqui já estão atendidos pela solução do #115 na main.

— Encerrado.

@adm01-debug adm01-debug deleted the fix/edge-contracts-deno-typecheck branch May 23, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants