[{"data":1,"prerenderedAt":1133},["ShallowReactive",2],{"blog-pt-failed-to-send-a-request-to-the-edge-function":3,"blog-index-pt":604},{"id":4,"title":5,"body":6,"category":560,"cover":561,"coverAlt":562,"description":563,"draft":564,"extension":565,"faq":566,"image":584,"keywords":585,"meta":592,"navigation":593,"ogTitle":594,"path":595,"published":596,"seo":597,"stem":598,"tldr":599,"updated":596,"__hash__":603},"blog_pt\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function.md","\"Failed to send a request to the Edge Function\": a causa real",{"type":7,"value":8,"toc":549},"minimark",[9,13,24,27,35,40,43,65,68,83,95,99,102,115,122,128,137,154,160,164,167,255,274,283,289,308,327,331,334,353,362,370,377,380,392,398,403,407,410,420,428,431,446,450,456,465,480,490,507,511,534],[10,11,12],"p",{},"O seu app tem um botão que chama uma Supabase Edge Function, aquele pedacinho de\ncódigo de servidor que um app feito com Lovable, Bolt, Cursor ou Claude Code usa\npara o trabalho que não pode acontecer no navegador, como chamar a OpenAI com uma\nchave. Você aperta, e em vez de um resultado o seu app mostra isto:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","Failed to send a request to the Edge Function\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"A função está no ar. Chamada pelo terminal, ela pode até responder direitinho.\nPelo seu app, falha toda vez, e \"failed to send a request to the Edge Function\"\ndá a entender que a sua requisição nunca saiu.",[10,28,29,30,34],{},"Pode muito bem ter saído. ",[31,32,33],"strong",{},"A sua função pode ter rodado, feito o trabalho e\nrespondido, e o navegador se recusou a entregar a resposta ao seu app."," Qual das\nduas coisas aconteceu está escrito num lugar só, e não é o erro que o seu app\nrecebeu.",[36,37,39],"h2",{"id":38},"o-que-significa-failed-to-send-a-request-to-the-edge-function","O que significa \"Failed to send a request to the Edge Function\"?",[10,41,42],{},"Significa que o supabase-js pediu uma resposta e não recebeu nenhuma que tivesse\npermissão de ler.",[10,44,45,46,53,54,57,58,64],{},"A frase é um texto fixo dentro do\n",[47,48,52],"a",{"href":49,"rel":50},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Ffunctions-js\u002Fsrc\u002Ftypes.ts",[51],"nofollow","supabase-js",",\npreso a um erro chamado ",[21,55,56],{},"FunctionsFetchError",". O supabase-js lança esse erro\nquando a própria requisição falha, antes de existir qualquer código de status\npara olhar. É isso que o separa do irmão mais conhecido:\n",[47,59,61],{"href":60},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code",[21,62,63],{},"Edge Function returned a non-2xx status code","\nquer dizer que uma resposta voltou e era um erro. Este quer dizer que nenhuma\nresposta legível voltou.",[10,66,67],{},"Uma requisição falha assim por um punhado de motivos. O aparelho está sem\nconexão, o endereço do projeto no seu app está errado, ou as regras do navegador\npara outros endereços recusaram a resposta. Essas regras se chamam CORS, de\nCross-Origin Resource Sharing, e impedem que uma página web leia uma resposta de\noutro endereço, a não ser que a resposta permita. Quando a função responde pelo\nterminal e só falha no seu app, o suspeito é o CORS, e o navegador vai dizer se\nfoi ele.",[10,69,70,71,74,75,78,79,82],{},"O seu app mora num endereço, digamos ",[21,72,73],{},"yourapp.lovable.app",", e a sua função em\noutro, ",[21,76,77],{},"\u003Cproject-ref>.supabase.co",". Pense no navegador como o porteiro do seu\napp. A correspondência que chega de outro endereço só é entregue ao seu app se\ntrouxer uma etiqueta do remetente dizendo que o seu app pode ficar com ela: um\ncabeçalho de resposta chamado ",[21,80,81],{},"Access-Control-Allow-Origin",". Com uma carta como a\nsua, o porteiro primeiro bate à porta do remetente para perguntar se ele aceita.\nE quando recusa alguma coisa, só diz ao seu app que não deu certo. O motivo ele\nanota no próprio caderno.",[10,84,85,86,89,90,94],{},"Uma terceira mensagem é da mesma família. ",[21,87,88],{},"Relay Error invoking the Edge Function"," é o supabase-js avisando que o relay do Supabase não conseguiu alcançar\na sua função, então\n",[47,91,93],{"href":92},"\u002Fblog\u002Fis-supabase-down-or-your-app","confira se o Supabase está com problema","\nantes de mexer no código.",[36,96,98],{"id":97},"por-que-o-seu-app-não-fica-sabendo-de-mais-nada","Por que o seu app não fica sabendo de mais nada",[10,100,101],{},"Porque o navegador esconde o motivo do seu código de propósito.",[10,103,104,105,110,111,114],{},"A ",[47,106,109],{"href":107,"rel":108},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FGuides\u002FCORS\u002FErrors",[51],"página da MDN sobre erros de CORS","\ndiz isso com todas as letras: por motivos de segurança, o código JavaScript não\ntem acesso aos detalhes do que deu errado numa requisição CORS. O seu app fica\nsabendo que algo falhou e mais nada. No Chrome, o erro que o supabase-js embrulha\ndiz ",[21,112,113],{},"TypeError: Failed to fetch",", um texto que o Chromium usa igual para\nqualquer falha de rede, então imprimir esse erro não acrescenta nada. Segundo a\nmesma página da MDN, o único jeito de descobrir o que aconteceu é o console do\nnavegador.",[10,116,117,118,121],{},"Esse é o caderno do porteiro. Abra o seu app publicado no Chrome ou no Edge,\naperte F12, escolha ",[31,119,120],{},"Console"," e aperte de novo o botão no seu app. A linha que\nvocê procura é vermelha e começa assim:",[14,123,126],{"className":124,"code":125,"language":19},[17],"Access to fetch at 'https:\u002F\u002F\u003Cproject-ref>.supabase.co\u002Ffunctions\u002Fv1\u002F\u003Cname>' from origin 'https:\u002F\u002Fyourapp.lovable.app' has been blocked by CORS policy:\n",[21,127,125],{"__ignoreMap":23},[10,129,130,131,136],{},"Tudo o que vem depois dos dois-pontos é o motivo. O Firefox e o Safari escrevem\nde outro jeito; as citações deste post são as do Chrome, tiradas do\n",[47,132,135],{"href":133,"rel":134},"https:\u002F\u002Fgithub.com\u002Fchromium\u002Fchromium\u002Fblob\u002Fmain\u002Fthird_party\u002Fblink\u002Frenderer\u002Fplatform\u002Floader\u002Fcors\u002Fcors_error_string.cc",[51],"código-fonte do Chromium",".",[10,138,139,140,143,144,147,148,153],{},"A batida na porta tem um nome técnico, preflight request. É uma requisição com o\nmétodo ",[21,141,142],{},"OPTIONS"," que o navegador envia antes da sua, e o supabase-js sempre\ndispara uma: ele manda a sua chave num cabeçalho ",[21,145,146],{},"Authorization"," e os seus dados\ncomo JSON, e o\n",[47,149,152],{"href":150,"rel":151},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FGuides\u002FCORS",[51],"guia de CORS da MDN","\nnão inclui nenhuma das duas coisas no que uma página pode enviar sem perguntar\nantes.",[155,156],"diagram",{"alt":157,"caption":158,"src":159},"Duas tentativas da mesma chamada. Em cima, a resposta à batida OPTIONS do navegador volta com um contorno vazio onde deveria estar a etiqueta, o navegador recusa, e a requisição POST nunca sai. Embaixo, a resposta à batida traz a etiqueta e passa, a requisição POST chega à função, que faz o trabalho, e a resposta volta sem etiqueta e é barrada na checagem do navegador.","Em cima, a batida é recusada e a sua requisição nunca sai. Embaixo, a batida passa, a função faz o trabalho e só a resposta dela fica retida.","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fthe-knock-first-1600x760.png",[36,161,163],{"id":162},"qual-metade-falhou-e-a-sua-função-chegou-a-rodar","Qual metade falhou, e a sua função chegou a rodar?",[10,165,166],{},"As palavras \"preflight request\" na linha do console decidem. Se elas estão lá,\no navegador parou na batida e a sua requisição nunca foi enviada. Se não estão, a\nsua requisição passou, a sua função rodou e a resposta dela ficou retida.",[168,169,170,186],"table",{},[171,172,173],"thead",{},[174,175,176,180,183],"tr",{},[177,178,179],"th",{},"A linha do console termina com",[177,181,182],{},"O que aconteceu",[177,184,185],{},"A função fez o trabalho?",[187,188,189,203,216,228,244],"tbody",{},[174,190,191,197,200],{},[192,193,194],"td",{},[21,195,196],{},"Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.",[192,198,199],{},"A batida foi respondida sem etiqueta",[192,201,202],{},"Não. Só a batida chegou a ela",[174,204,205,210,213],{},[192,206,207],{},[21,208,209],{},"Response to preflight request doesn't pass access control check: It does not have HTTP ok status.",[192,211,212],{},"A batida foi respondida com um erro",[192,214,215],{},"Não",[174,217,218,223,226],{},[192,219,220],{},[21,221,222],{},"Request header field \u003Cname> is not allowed by Access-Control-Allow-Headers in preflight response.",[192,224,225],{},"O seu app envia um cabeçalho que a lista da função não nomeia",[192,227,215],{},[174,229,230,236,239],{},[192,231,232,235],{},[21,233,234],{},"No 'Access-Control-Allow-Origin' header is present on the requested resource.",", sem mencionar preflight",[192,237,238],{},"A batida passou, a sua requisição chegou e a resposta veio sem etiqueta",[192,240,241],{},[31,242,243],{},"Sim",[174,245,246,249,252],{},[192,247,248],{},"Nenhuma linha de CORS",[192,250,251],{},"Não é CORS: a conexão, o endereço ou um tempo limite do seu código",[192,253,254],{},"Olhe a aba Invocations",[10,256,257,263,264,269,270,273],{},[31,258,259,260,262],{},"A primeira linha é o que uma função sem tratamento para ",[21,261,142],{},"\nproduz."," A\n",[47,265,268],{"href":266,"rel":267},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fedge-function-500-error-response",[51],"página do Supabase sobre o erro 500","\ndescreve isso do lado da função: a batida chega ao seu código como qualquer\noutra requisição, e a função registra ",[21,271,272],{},"SyntaxError: Unexpected end of JSON input",", porque uma batida na porta não traz conteúdo e o código tentou ler um. A\nresposta dela é um erro sem cabeçalhos, e o Chrome aponta o cabeçalho que falta\nantes de olhar o status. Se essa linha está na aba Logs da função, você achou.",[10,275,276,279,280,282],{},[31,277,278],{},"A segunda linha quer dizer que a batida recebeu os cabeçalhos, e um erro junto\ncom eles."," Um jeito de chegar aí é uma verificação colocada acima do ramo de\n",[21,281,142],{}," que a batida não consegue passar, como uma verificação de quem chama.\nA batida não leva nenhum dos seus cabeçalhos, nem a sua chave, então ela falha\ntoda vez.",[10,284,285,288],{},[31,286,287],{},"A quarta linha é a que pede calma, porque o trabalho foi feito."," Se a função\ngrava uma linha, manda um e-mail ou cobra um cartão, isso já aconteceu, e apertar\no botão de novo faz tudo outra vez. O que falhou foi a resposta, que saiu sem\netiqueta. Procure primeiro um erro: uma quebra cuja resposta o seu código nem\nchegou a escrever, ou um ramo de erro que devolve sem os cabeçalhos. A mesma\npágina do Supabase avisa que, nesse caso, o navegador culpa o CORS por uma falha\ncuja causa real é outra.",[10,290,291,292,295,296,299,300,303,304,307],{},"Então leia o registro da própria função antes de mexer em qualquer cabeçalho. No\npainel do Supabase, abra ",[31,293,294],{},"Edge Functions",", escolha a função e leia as abas\n",[31,297,298],{},"Invocations"," e ",[31,301,302],{},"Logs"," no minuto em que você apertou o botão.\n",[47,305,306],{"href":60},"Ler o erro real"," percorre\nas duas, e o que cada código de status quer dizer.",[10,309,310,313,314,317,318,321,322,326],{},[31,311,312],{},"A última linha quer dizer que o porteiro não recusou nada."," A requisição\nfalhou no caminho: o aparelho perdeu a conexão, ou o endereço de projeto que o\nseu app chama não existe. Um caso vem do seu próprio código. Se ele passa um\n",[21,315,316],{},"timeout"," para ",[21,319,320],{},"supabase.functions.invoke",", o\n",[47,323,52],{"href":324,"rel":325},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Ffunctions-js\u002Fsrc\u002FFunctionsClient.ts",[51],"\ncancela a requisição quando o tempo acaba e informa esta mesma frase, mesmo que\na função talvez ainda esteja trabalhando.",[36,328,330],{"id":329},"como-corrigir-responder-à-batida-e-etiquetar-toda-resposta","Como corrigir: responder à batida e etiquetar toda resposta",[10,332,333],{},"Duas mudanças na função, e elas vão no mesmo deploy.",[335,336,337,347],"ol",{},[338,339,340,346],"li",{},[31,341,342,343,345],{},"Um ramo para ",[21,344,142],{}," antes de tudo",", antes de qualquer linha que leia o\nconteúdo ou verifique quem chama. Ele responde à batida com os cabeçalhos\nCORS e mais nada.",[338,348,349,352],{},[31,350,351],{},"Os cabeçalhos CORS em toda resposta que a função devolve",", as que dão\ncerto e os erros. Uma resposta sem eles fica retida, diga o que disser.",[10,354,355,356,361],{},"O ",[47,357,360],{"href":358,"rel":359},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fcors",[51],"guia de CORS do Supabase","\nmonta uma função mais ou menos assim:",[14,363,368],{"className":364,"code":366,"language":367,"meta":23},[365],"language-ts","import { corsHeaders } from 'npm:@supabase\u002Fsupabase-js@^2\u002Fcors'\n\nDeno.serve(async (req) => {\n  if (req.method === 'OPTIONS') {\n    return Response.json({ ok: true }, { headers: corsHeaders })\n  }\n  try {\n    const body = await req.json()\n    \u002F\u002F the function's own work goes here\n    return Response.json({ done: true }, { headers: corsHeaders })\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error)\n    return Response.json({ error: message }, { status: 400, headers: corsHeaders })\n  }\n})\n","ts",[21,369,366],{"__ignoreMap":23},[10,371,372,373,376],{},"Os cabeçalhos vêm do próprio supabase-js em vez de uma lista colada na função. O\nguia importa os cabeçalhos assim a partir da versão 2.95.0 do supabase-js, para\nque a lista bata com o que as bibliotecas cliente enviam, e diz para fazer o\ndeploy de novo depois de atualizar. Funções mais antigas trazem uma cópia escrita\nà mão da mesma lista, num arquivo chamado ",[21,374,375],{},"_shared\u002Fcors.ts",". É dessa cópia que\nvem a terceira linha da tabela: um cabeçalho que o seu app envia e que a lista\nnão nomeia.",[10,378,379],{},"Se você pedir a correção ao Lovable, ao Bolt, ao Cursor ou ao Claude Code, esses\ndois pontos numerados são o prompt. Cite os dois. O segundo é fácil de esquecer,\ne uma função que só tem o primeiro passa da primeira linha da tabela para a\nquarta na próxima vez que quebrar.",[10,381,382,383,386,387,391],{},"Os exemplos mais novos do Supabase envolvem a função inteira em ",[21,384,385],{},"withSupabase",",\nque responde à batida por você.\n",[47,388,390],{"href":389},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Levar um segredo para uma Edge Function","\nmostra esse envoltório com uma verificação de quem chama, e essa verificação é o\nassunto da próxima seção.",[10,393,394,395,397],{},"Com os cabeçalhos em toda resposta, uma função que quebra para de mostrar esta\nmensagem e passa a mostrar ",[21,396,63],{},". A\nresposta agora chega ao seu app, com o motivo dentro.",[155,399],{"alt":400,"caption":401,"src":402},"Uma função devolve três respostas em direção à checagem do navegador. Uma resposta 200 com etiqueta passa e chega ao app. Uma resposta 500 sem etiqueta é barrada na checagem. Uma resposta 400 com etiqueta passa, então o app recebe o erro e consegue lê-lo.","O navegador procura a etiqueta e nunca olha o que a resposta diz. Um erro que traz os cabeçalhos chega ao seu app; um erro sem eles fica retido e é informado como requisição que falhou.","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Ftag-every-reply-1600x720.png",[36,404,406],{"id":405},"o-cabeçalho-cors-decide-quem-pode-chamar-a-sua-função","O cabeçalho CORS decide quem pode chamar a sua função?",[10,408,409],{},"Não. Ele decide quais páginas web podem ler a resposta, e só navegadores olham\npara ele.",[10,411,412,413,415,416,419],{},"A própria lista do Supabase define ",[21,414,81],{}," como ",[21,417,418],{},"*",", que\nlibera qualquer origem, tanto na cópia que o supabase-js exporta quanto na antiga\nescrita à mão. Numa função que verifica o token de quem chama, tudo bem. Numa\nfunção que não verifica nada, isso deixa qualquer página de qualquer site chamar\na sua função a partir dos navegadores dos próprios visitantes e ler o que volta.",[10,421,422,423,427],{},"Restringir o cabeçalho ao seu próprio domínio também não fecha a função. Um\nscript, um terminal ou outro servidor envia a mesma requisição sem navegador,\nnunca lê o cabeçalho e recebe a resposta inteira.\n",[47,424,426],{"href":425},"\u002Fblog\u002Fcors-wildcard-security-risk","O que um curinga de CORS abre e o que não abre","\nexplica isso em detalhe.",[10,429,430],{},"A tranca de uma Edge Function é uma verificação de quem chama, escrita dentro da\nfunção. Ela importa mais nas funções que acabam atrás deste erro, porque são elas\nque guardam uma chave da OpenAI ou a chave secreta do seu projeto, e a chave\nsecreta passa por cima de todas as regras de row level security que você\nescreveu.",[10,432,433,434,437,438,441,442,136],{},"A outra saída de um erro de CORS é parar de usar a função: colocar a chave numa\nvariável ",[21,435,436],{},"VITE_"," e chamar a OpenAI direto da página. Funciona na hora, e coloca a\nchave no arquivo que todo visitante baixa. É a primeira das\n",[47,439,440],{"href":60},"duas correções que deixam você pior",".\nEsse erro dá para ver de fora. A nossa varredura gratuita lê o JavaScript do seu\napp publicado como um estranho leria e nomeia cada chave que encontra, dizendo\ninclusive se ela devia estar ali. Leva uns 20 segundos e não precisa de conta:\n",[47,443,445],{"href":444},"\u002Fsecurity-scanner","escaneie o seu app",[36,447,449],{"id":448},"manter-a-chave-fora-da-página-depois-da-próxima-mudança","Manter a chave fora da página depois da próxima mudança",[10,451,452,455],{},[31,453,454],{},"Uma função que você corrigiu hoje pode ser reescrita na próxima vez que você\npedir uma funcionalidade ao seu builder",", e o jeito mais rápido de passar por\num erro de CORS é o que coloca a sua chave na página.",[10,457,458],{},[31,459,460,464],{},[47,461,463],{"href":462},"\u002Fwebsite-monitoring","O Reeve Monitor"," varre o seu app publicado de novo a cada hora:",[466,467,468,471,474,477],"ul",{},[338,469,470],{},"as nove verificações a cada hora, em até três apps",[338,472,473],{},"um e-mail no dia em que uma nova varredura avaliar o seu app pior que a anterior; uma chave secreta no seu JavaScript limita sozinha a nota a D",[338,475,476],{},"se o app está no ar, a cada 60 segundos",[338,478,479],{},"um relatório mensal do que ele viu",[10,481,482],{},[31,483,484,485,489],{},"Uma função que guarda a chave secreta do seu projeto pode mudar qualquer linha\ndo seu banco para quem a chamar. ",[47,486,488],{"href":487},"\u002Fsupabase-backups","O Reeve Care"," guarda uma\ncópia do seu banco Supabase onde nada no seu projeto alcança.",[466,491,492,495,498,501,504],{},[338,493,494],{},"uma cópia criptografada conforme uma agenda, guardada no armazenamento do próprio Reeve na UE, fora da sua conta Supabase",[338,496,497],{},"cada cópia verificada antes de contar, contando as linhas de cada tabela",[338,499,500],{},"uma restauração em um clique que salva o que está lá agora antes de substituir",[338,502,503],{},"também os seus arquivos enviados, assim que você conectar uma credencial de Storage",[338,505,506],{},"tudo o que o Monitor faz",[36,508,510],{"id":509},"o-que-fazer-agora","O que fazer agora",[512,513,514],"key-takeaways",{},[466,515,516,519,525,528,531],{},[338,517,518],{},"Abra o console do navegador no seu app publicado, aperte o botão de novo e leia o fim da linha vermelha de CORS.",[338,520,521,522,524],{},"Se a linha menciona a preflight request, coloque no topo da função um ramo para ",[21,523,142],{}," que devolva os cabeçalhos CORS.",[338,526,527],{},"Se não menciona, a sua função rodou. Leia as abas Invocations e Logs dela e confira o que ela já fez antes que alguém aperte o botão de novo.",[338,529,530],{},"Devolva os cabeçalhos CORS em toda resposta, erros incluídos, e importe-os do supabase-js 2.95.0 ou mais novo para a lista ficar em dia.",[338,532,533],{},"Mantenha dentro da função uma verificação de quem chama. O cabeçalho CORS só diz aos navegadores quem pode ler a resposta.",[10,535,536,537,539,540,543,544,548],{},"Quando o erro no seu app mudar para ",[21,538,63],{},", os cabeçalhos estão funcionando e a resposta está passando;\n",[47,541,542],{"href":60},"esse post"," lê a resposta a\npartir daí. O ",[47,545,547],{"href":546},"\u002Fchecklist","checklist de segurança de 10 minutos"," cobre o que mais\num app recém-lançado costuma deixar aberto.",{"title":23,"searchDepth":550,"depth":550,"links":551},3,[552,554,555,556,557,558,559],{"id":38,"depth":553,"text":39},2,{"id":97,"depth":553,"text":98},{"id":162,"depth":553,"text":163},{"id":329,"depth":553,"text":330},{"id":405,"depth":553,"text":406},{"id":448,"depth":553,"text":449},{"id":509,"depth":553,"text":510},"Noções de segurança","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcover-1200x630.png","Uma cancela abaixada atravessando a passagem, com um envelope retido do outro lado e um contorno amarelo vazio onde a etiqueta dele deveria pender.","\"Failed to send a request to the Edge Function\": o navegador não recebeu uma resposta legível. O console dele diz por quê e se a sua função rodou.",false,"md",[567,569,572,575,578,581],{"q":39,"a":568},"Significa que o supabase-js pediu uma resposta à sua Supabase Edge Function e não recebeu nenhuma que tivesse permissão de ler. Ou a requisição falhou no caminho, por exemplo porque o aparelho estava sem conexão, ou o navegador se recusou a entregar a resposta ao seu app pelas regras dele para requisições a outros endereços, chamadas CORS. O navegador esconde o motivo do seu código de propósito e o escreve no console.",{"q":570,"a":571},"Por que a minha Edge Function funciona pelo terminal mas não pelo meu app?","Porque só navegadores aplicam CORS. Um terminal, um script ou outro servidor envia a requisição e lê a resposta inteira. Um navegador confere antes se a resposta diz que o seu app pode lê-la, e antes de uma requisição como a que o supabase-js envia ele ainda pede permissão à função com uma requisição OPTIONS separada. Se qualquer um dos dois passos falhar, o seu app recebe este erro enquanto a mesma chamada funciona em qualquer outro lugar.",{"q":573,"a":574},"A minha Edge Function rodou se eu recebi este erro?","Leia a linha vermelha no console do navegador. Se ela menciona a preflight request, o navegador parou no pedido de permissão e a sua requisição nunca saiu. Se não menciona, a requisição passou, a função fez o trabalho dela e só a resposta ficou retida. Nesse caso, leia as abas Invocations e Logs da função antes de apertar o botão de novo, porque um segundo clique repete o trabalho.",{"q":576,"a":577},"Como corrijo um erro de CORS numa Supabase Edge Function?","Faça a função responder primeiro à requisição OPTIONS, antes de qualquer código que leia o conteúdo ou verifique quem chama, e devolva os cabeçalhos CORS em toda resposta, inclusive nas de erro. O guia de CORS do Supabase importa esses cabeçalhos do supabase-js, versão 2.95.0 ou mais nova, para que a lista bata com o que o cliente envia. Faça o deploy da função de novo depois da mudança.",{"q":579,"a":580},"O que é \"Relay Error invoking the Edge Function\"?","É uma terceira mensagem do supabase-js, que aparece quando o relay do Supabase não conseguiu alcançar a sua função. Não é uma recusa de CORS nem uma resposta do seu próprio código, então confira primeiro se o próprio Supabase está com problema antes de mudar qualquer coisa.",{"q":582,"a":583},"É seguro liberar qualquer origem nos cabeçalhos CORS da minha Edge Function?","Só se a função verificar quem a chama. O cabeçalho CORS diz aos navegadores quais páginas web podem ler a resposta; ele não impede ninguém de chamar a função. Os cabeçalhos do próprio Supabase liberam qualquer origem, o que é tranquilo para uma função que verifica o token de quem chama e deixa qualquer site usar uma que não verifica. Restringir o cabeçalho ao seu domínio também não fecha a função para scripts.","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",[586,56,587,588,589,590,591],"failed to send a request to the edge function","erro cors supabase edge function","supabase edge function blocked by cors policy","response to preflight request doesn't pass access control check","relay error invoking the edge function","lovable edge function cors",{},true,"\"Failed to send a request to the Edge Function\" no Supabase","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","2026-11-03",{"title":5,"description":563},"blog\u002Ffailed-to-send-a-request-to-the-edge-function",[600,601,602],"\"Failed to send a request to the Edge Function\" quer dizer que o supabase-js não recebeu nenhuma resposta que tivesse permissão de ler. Ou a requisição falhou no caminho, ou o navegador segurou a resposta, e o seu app não fica sabendo de mais nada de propósito.","O console do navegador tem o motivo. Uma linha que menciona a preflight request quer dizer que a sua requisição nunca saiu. Uma linha que não menciona quer dizer que a sua função rodou e só a resposta dela ficou retida.","A correção é um ramo para OPTIONS no topo da função e os cabeçalhos CORS em toda resposta, erros incluídos. Esses cabeçalhos só dizem aos navegadores quem pode ler a resposta; quem pode chamar quem decide é uma verificação no seu código.","l7Wm4yGJQAwFaQxdxm7V4xNnwdbo693O25z1LFuwpQ8",[605,611,617,623,629,635,641,642,648,654,660,667,673,679,684,690,696,702,708,714,720,726,732,738,744,750,756,762,768,774,780,786,792,798,804,810,815,821,827,833,838,844,850,856,862,868,873,879,885,891,897,903,909,915,921,927,933,939,945,951,957,963,969,975,981,987,993,999,1005,1011,1017,1023,1029,1035,1041,1047,1053,1058,1064,1070,1076,1082,1088,1094,1099,1105,1111,1117,1122,1128],{"path":606,"title":607,"description":608,"published":609,"category":560,"image":610,"draft":564},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": o pooler não tem lugar para mais um cliente. A porta da sua string de conexão define o limite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":612,"title":613,"description":614,"published":615,"category":560,"image":616,"draft":564},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Erro do Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": o Google está desativado no seu projeto Supabase. Como ativar e corrigir o redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":618,"title":619,"description":620,"published":621,"category":560,"image":622,"draft":564},"\u002Fblog\u002Fviolates-foreign-key-constraint","Erro do Supabase \"violates foreign key constraint\" ao inserir","Supabase \"insert or update on table violates foreign key constraint\": sua linha aponta para uma linha que não existe. Qual, por quê, e como corrigir.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":624,"title":625,"description":626,"published":627,"category":560,"image":628,"draft":564},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Erro do Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": uma coluna obrigatória chegou vazia. De onde veio o null, e como corrigir.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":630,"title":631,"description":632,"published":633,"category":560,"image":634,"draft":564},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": para onde foi a sessão","\"Auth session missing!\" é o supabase-js sem achar nenhuma sessão logada e sem chegar a perguntar ao Supabase. Para onde foi a sessão, e a correção.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":636,"title":637,"description":638,"published":639,"category":560,"image":640,"draft":564},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": ninguém está logado","\"invalid claim: missing sub claim\": o Supabase Auth recebeu um token autêntico sem nenhum usuário, a chave do projeto no lugar de uma sessão.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":595,"title":5,"description":563,"published":596,"category":560,"image":584,"draft":564},{"path":643,"title":644,"description":645,"published":646,"category":560,"image":647,"draft":564},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por que o Supabase redireciona links de e-mail para localhost:3000","Se o Supabase redireciona para localhost:3000, a Site URL nunca foi trocada ou o seu endereço falta em Redirect URLs. A solução, e o curinga a evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":649,"title":650,"description":651,"published":652,"category":560,"image":653,"draft":564},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" num link novo","Num link enviado há um minuto, \"Email link is invalid or has expired\" no Supabase costuma significar que um filtro de e-mail o usou antes. Como resolver.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":655,"title":656,"description":657,"published":658,"category":560,"image":659,"draft":564},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": uma consulta passou do limite do seu papel, 3 segundos para um visitante. Veja antes a política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":661,"title":662,"description":663,"published":664,"category":665,"image":666,"draft":564},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" no Supabase, e o que vai junto","\"Database error deleting user\" no Supabase: seu banco recusou a exclusão. O motivo está nos seus logs, e a correção decide o que mais é apagado.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":668,"title":669,"description":670,"published":671,"category":560,"image":672,"draft":564},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" no Supabase","O webhook do Stripe numa Edge Function do Supabase diz \"No signatures found matching the expected signature\"? São duas causas. Continue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":674,"title":675,"description":676,"published":677,"category":560,"image":678,"draft":564},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" no Supabase: as três causas","O Supabase diz \"Invalid login credentials\" para senha errada, e-mail desconhecido e conta Google. Como saber qual é, e por que é vago.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":60,"title":680,"description":681,"published":682,"category":560,"image":683,"draft":564},"\"Edge Function returned a non-2xx status code\": o erro real","\"Edge Function returned a non-2xx status code\" quer dizer que sua função do Supabase respondeu com um erro. Veja onde ler o erro real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":685,"title":686,"description":687,"published":688,"category":560,"image":689,"draft":564},"\u002Fblog\u002Fcertificate-not-trusted","Certificado não confiável: três causas além do vencimento","Certificado não confiável mesmo com a data certa? Ele cita outro endereço, assinou a si mesmo ou falta um elo na cadeia. Veja como saber qual.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":691,"title":692,"description":693,"published":694,"category":560,"image":695,"draft":564},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": leia as aspas","Supabase \"invalid input syntax for type uuid\": seu app enviou algo que não é um id. Leia as aspas, segure a consulta, mantenha a coluna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":697,"title":698,"description":699,"published":700,"category":560,"image":701,"draft":564},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": o valor já está em uso. Ache a coluna, escolha uma correção e tire o valor da tela.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":703,"title":704,"description":705,"published":706,"category":560,"image":707,"draft":564},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" e a tabela está lá","Supabase \"relation does not exist\" ou PGRST205: nenhuma tabela tem esse nome nesse schema. Quatro verificações, e o que expor um schema abre.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":709,"title":710,"description":711,"published":712,"category":560,"image":713,"draft":564},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" mostra os nomes de argumentos que seu app enviou. Compare-os com a função.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":715,"title":716,"description":717,"published":718,"category":560,"image":719,"draft":564},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" costuma ser um nome que não bate. Quatro verificações e a linha que recarrega.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":721,"title":722,"description":723,"published":724,"category":560,"image":725,"draft":564},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dois limites, um só código","Supabase \"Email Rate Limit Exceeded\" limita cada email que seu projeto envia: 2 por hora no remetente embutido. O que conta e como aumentar.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":727,"title":728,"description":729,"published":730,"category":560,"image":731,"draft":564},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" desconecta seus usuários. Três causas, e como o log do Auth separa cada uma.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":733,"title":734,"description":735,"published":736,"category":560,"image":737,"draft":564},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": três causas","Supabase \"permission denied for schema public\" é um grant que falta no schema. O que o removeu, e a linha que o devolve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":739,"title":740,"description":741,"published":742,"category":560,"image":743,"draft":564},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": as três coisas que isso significa","Supabase \"Bucket not found\" é uma de três coisas: um link público para um bucket privado, um nome que não bate exatamente ou o projeto errado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":745,"title":746,"description":747,"published":748,"category":560,"image":749,"draft":564},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: qual chave parou de funcionar?","Um erro Supabase invalid JWT é o PGRST301: um token assinado não passou na verificação. Num projeto novo isso é a sessão, não a chave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":751,"title":752,"description":753,"published":754,"category":560,"image":755,"draft":564},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" quase sempre é nenhuma","O Supabase devolve PGRST116, \"JSON object requested, multiple (or no) rows returned\", quando a consulta não achou nada. Linha escondida parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":757,"title":758,"description":759,"published":760,"category":560,"image":761,"draft":564},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" no Supabase: onde olhar","\"Database error saving new user\" quer dizer que algo preso ao seu cadastro no Supabase falhou e tudo foi desfeito. O erro real está nos seus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":763,"title":764,"description":765,"published":766,"category":560,"image":767,"draft":564},"\u002Fblog\u002Fwhat-is-supabase","O que é Supabase? O banco de dados que seu builder escolheu","O que é Supabase: o banco de dados, o login e o armazenamento de arquivos do seu app. O Supabase cuida dos servidores; as regras das suas linhas são suas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":769,"title":770,"description":771,"published":772,"category":560,"image":773,"draft":564},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Uma chave AWS exposta no seu frontend não é como uma chave OpenAI","Uma chave de acesso da AWS exposta no seu frontend lê e grava no seu armazenamento. A solução costuma ser uma presigned URL, não uma chave nova.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":775,"title":776,"description":777,"published":778,"category":560,"image":779,"draft":564},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" ao enviar","\"New row violates row-level security policy for table objects\" quer dizer que o seu envio não tem regra insert. Deixar o bucket público não cria nenhuma.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":781,"title":782,"description":783,"published":784,"category":560,"image":785,"draft":564},"\u002Fblog\u002Fbase44-security-scan","Scan de segurança do Base44: o que só ele enxerga","O scan de segurança do Base44 verifica sete tipos de problema por dentro. Esta é a metade que ele lê e mais ninguém, e a metade que ele nunca olha.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":787,"title":788,"description":789,"published":790,"category":560,"image":791,"draft":564},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Sua chave de API vazou. A ordem em que agir","Uma chave de API vazou e você não sabe o que fazer primeiro. Nem toda chave no seu frontend é um vazamento, e a ordem importa mais que a pressa.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":793,"title":794,"description":795,"published":796,"category":560,"image":797,"draft":564},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sem desligar o RLS","\"Infinite recursion detected in policy for relation\" significa que a sua policy perguntou à tabela que ela protege. Veja como quebrar o círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":799,"title":800,"description":801,"published":802,"category":560,"image":803,"draft":564},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" no Supabase, e a correção errada","\"No API key found in request\" significa que sua requisição chegou ao Supabase sem chave. Quase toda resposta aponta para as regras do seu banco.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":805,"title":806,"description":807,"published":808,"category":560,"image":809,"draft":564},"\u002Fblog\u002Fis-base44-safe","O Base44 é seguro? O que vimos em 5.442 apps Base44","O Base44 é seguro? Rodamos nove verificações em 5.442 apps Base44 no ar. Quase todas tiraram B por motivos que o dono nunca escolheu.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":389,"title":811,"description":812,"published":813,"category":560,"image":814,"draft":564},"Esconder uma chave de API: mova para uma Edge Function do Supabase","Esconder uma chave de API é tirá-la do navegador, e uma Edge Function do Supabase é o menor lugar para guardá-la. Dois passos em volta pesam mais.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":816,"title":817,"description":818,"published":819,"category":560,"image":820,"draft":564},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Seu arquivo .env está exposto? Os doze caminhos para testar","Seu arquivo .env está exposto no seu próprio servidor web? Doze endereços dizem isso em um minuto, e um acerto significa que tudo nele já é público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":822,"title":823,"description":824,"published":825,"category":560,"image":826,"draft":564},"\u002Fblog\u002Fis-v0-safe","Segurança do v0: os 1.790 aplicativos v0 escaneados tiraram A","A segurança do v0 medida em 1.790 aplicativos v0 no ar: todos tiraram A. Só 17 citavam um banco de dados, e é sobretudo isso que esse A mede.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":828,"title":829,"description":830,"published":831,"category":560,"image":832,"draft":564},"\u002Fblog\u002Fis-bolt-safe","O Bolt é seguro? O que vimos em 1.123 aplicativos Bolt","O Bolt é seguro? Passamos 1.123 aplicativos Bolt no ar por nove verificações. A hospedagem saiu limpa. Os achados: chaves e tabelas abertas nos aplicativos.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":92,"title":834,"description":835,"published":836,"category":560,"image":837,"draft":564},"O Supabase caiu ou o problema é o seu app? Como saber","O Supabase caiu ou o problema é o seu app? Um projeto pausado, um banco cheio e um erro seu parecem iguais. Quatro verificações separam os casos.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":560,"image":843,"draft":564},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","O Supabase criptografa meus dados? Sim. Veja o que isso impede","O Supabase criptografa os dados? Sim: AES-256 em repouso, TLS em trânsito, SOC 2 e ISO 27001. O que cada um cobre, e o vazamento que nenhum deles impede.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":848,"category":560,"image":849,"draft":564},"\u002Fblog\u002Fsupabase-free-plan-limits","O Supabase é gratuito? Sim, com estes limites e sem backups","Sim: o plano gratuito do Supabase vai até 500 MB de banco e 5 GB de egress, sem nenhum backup. O que para em cada limite e o que muda no Pro de $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":851,"title":852,"description":853,"published":854,"category":665,"image":855,"draft":564},"\u002Fblog\u002Ftest-your-supabase-backup","Teste o backup do seu Supabase antes do dia em que precisar","Como testar o backup do seu Supabase: restaurar num projeto de teste, contar as linhas, entrar e procurar a linha que falta num arquivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":857,"title":858,"description":859,"published":860,"category":665,"image":861,"draft":564},"\u002Fblog\u002Fsupabase-backup-github-action","Backup grátis do Supabase com uma GitHub Action, e a pegadinha","Um backup do Supabase com GitHub Action é grátis e serve para muitos apps. O workflow, a connection string certa e o egress de cada execução.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":863,"title":864,"description":865,"published":866,"category":665,"image":867,"draft":564},"\u002Fblog\u002Fdownload-your-supabase-backup","Por que você não consegue baixar seu backup do Supabase","Você não consegue baixar seu backup do Supabase num projeto atual, porque a cópia diária é um snapshot físico. Como conferir e como ter uma cópia só sua.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":869,"title":870,"description":871,"published":866,"category":560,"image":872,"draft":564},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": o grant que falta","A partir de 30 de outubro, uma tabela nova no Supabase responde \"permission denied for table\" até receber um grant. O e-mail mostra só metade.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":874,"title":875,"description":876,"published":877,"category":560,"image":878,"draft":564},"\u002Fblog\u002Fopen-api-endpoint-exposed","Um endpoint de API aberto é um problema? Leia o JSON","Seu scan apontou um endpoint de API aberto. Se isso importa depende do que voltou, e a maioria dos que encontramos era da própria plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":880,"title":881,"description":882,"published":883,"category":560,"image":884,"draft":564},"\u002Fblog\u002Flovable-security-scan","Escaneamento de segurança do Lovable: o que ele não prova","Escaneamento de segurança do Lovable: o que o Quick scan e o Deep scan checam, quando cada um roda, e a única coisa que nenhum escaneamento por dentro prova.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":886,"title":887,"description":888,"published":889,"category":665,"image":890,"draft":564},"\u002Fblog\u002Fsupabase-backup-auth-users","Por que seu dump do Supabase não tem usuários dentro","Rode supabase db dump sozinho e você recebe a forma do seu banco e nenhuma das linhas dele, sem o schema auth onde seus usuários moram.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":892,"title":893,"description":894,"published":895,"category":560,"image":896,"draft":564},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domínio expirado, site fora do ar: o que acontece agora","Seu domínio expirou e seu site está fora do ar. O relógio que começa a correr, por que o certificado é o problema menor, e como conferir os dois.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":898,"title":899,"description":900,"published":901,"category":560,"image":902,"draft":564},"\u002Fblog\u002Fis-lovable-safe","O Lovable é seguro? O que vimos em 18.554 aplicativos Lovable","O Lovable é seguro? Passamos 18.554 aplicativos Lovable no ar por nove verificações. A plataforma foi a mais limpa de cinco. Os achados estavam nos aplicativos.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":904,"title":905,"description":906,"published":907,"category":560,"image":908,"draft":564},"\u002Fblog\u002Fvibe-coded-app-security-checklist","O checklist de segurança do vibe coding, em nove verificações","Um checklist de segurança do vibe coding com nove itens, cada um verificável no seu app de fora por qualquer pessoa, e cada um com um teste de uma linha.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":910,"title":911,"description":912,"published":913,"category":560,"image":914,"draft":564},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Uma chave secreta da Stripe no frontend pode mover dinheiro","Uma chave secreta da Stripe exposta no seu frontend pode reembolsar, cobrar e ler cada ficha de cliente que você tem. Sua chave pk_live_ é que deve estar aí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":916,"title":917,"description":918,"published":919,"category":560,"image":920,"draft":564},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variáveis de ambiente do Vite expostas: o prefixo diz publique isto","Variáveis de ambiente do Vite expostas no seu app: fizeram o que o prefixo pediu. VITE_ e NEXT_PUBLIC_ significam publique isto, e a IA nunca soube o custo.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":922,"title":923,"description":924,"published":925,"category":560,"image":926,"draft":564},"\u002Fblog\u002Fbase44-source-maps","Segurança no Base44: o que um scan aponta e o que é seu para corrigir","Segurança no Base44 em 5.438 apps escaneados: três achados em quase todos são da plataforma, o source map é o selo do Base44, e a sua parte é uma lista curta.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":928,"title":929,"description":930,"published":931,"category":560,"image":932,"draft":564},"\u002Fblog\u002Fis-cursor-ai-safe","O Cursor AI é seguro? O editor, o código e o app que você publicou","O Cursor AI é seguro? Três perguntas em uma busca: o que o Cursor guarda, o que o código que ele escreve erra, e se o app que você publicou está aberto.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":934,"title":935,"description":936,"published":937,"category":560,"image":938,"draft":564},"\u002Fblog\u002Fis-replit-safe","O Replit é seguro? O que vimos em 3.042 aplicativos Replit no ar","O Replit é seguro? Passamos 3.042 aplicativos Replit no ar por nove verificações externas. Os achados estavam no aplicativo publicado, não no host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":940,"title":941,"description":942,"published":943,"category":665,"image":944,"draft":564},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: sua cópia do banco não tem nenhum arquivo","Um Supabase storage backup é uma tarefa à parte. Os backups do banco guardam a lista dos seus arquivos e nenhum deles, então cada upload fica quebrado.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":946,"title":947,"description":948,"published":949,"category":665,"image":950,"draft":564},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery do Supabase: preço e limites","O point-in-time recovery do Supabase rebobina seu banco para qualquer segundo da última semana. Custa $100 por mês além do Pro e cobre só o banco.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":952,"title":953,"description":954,"published":955,"category":665,"image":956,"draft":564},"\u002Fblog\u002Fsupabase-project-paused-recover","Projeto Supabase pausado? Seus dados continuam lá","O Supabase pausou seu projeto depois de uma semana sem atividade. Nada foi apagado, Restaurar fica ao lado do nome e você tem um ano antes disso mudar.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":958,"title":959,"description":960,"published":961,"category":560,"image":962,"draft":564},"\u002Fblog\u002Fsafest-ai-app-builder","Qual builder de apps com IA é mais seguro? 30.998 apps testados","Qual builder de apps com IA é mais seguro? Escaneamos 30.998 apps no ar do Lovable, Base44, Replit, v0 e Bolt. O builder não é o que decide sua nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":964,"title":965,"description":966,"published":967,"category":560,"image":968,"draft":564},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Ative Row Level Security em toda tabela do Supabase e comprove","Ativar Row Level Security no Supabase sem política fecha a tabela por completo. Uma política sem a chave ligada não faz nada. Aqui está o SQL, e o teste.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":970,"title":971,"description":972,"published":973,"category":560,"image":974,"draft":564},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": o que o aviso não vê","O Supabase marca \"RLS disabled in public\" como erro. Ele não diz nada sobre a política de leitura que deixa a sua tabela igualmente aberta.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":976,"title":977,"description":978,"published":979,"category":560,"image":980,"draft":564},"\u002Fblog\u002Frotate-supabase-service-role-key","Como rotacionar uma chave service_role do Supabase vazada","O Supabase manda fechar o vazamento primeiro. Outros guias mandam rotacionar agora. O que vale depende de para onde a sua chave service_role vazou.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":982,"title":983,"description":984,"published":985,"category":560,"image":986,"draft":564},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Scanners de segurança para vibe coding comparados, o nosso incluído","O melhor scanner de segurança para vibe coding depende de três perguntas que nenhuma lista de recursos responde. Oito ferramentas comparadas, com preços.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":988,"title":989,"description":990,"published":991,"category":560,"image":992,"draft":564},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: faça você mesmo as cinco verificações","Um Supabase security checker lê o seu app publicado em vez das configurações do projeto. Aqui estão as cinco verificações e como fazer cada uma sozinho.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":994,"title":995,"description":996,"published":997,"category":560,"image":998,"draft":564},"\u002Fblog\u002Fvibe-coding-security-scanner","Scanner de segurança para vibe coding: o que ele não vê","Um scanner de segurança para vibe coding lê seu app no ar, de fora. O que isso cobre, as quatro coisas que ele não consegue ver e como ler o resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1000,"title":1001,"description":1002,"published":1003,"category":560,"image":1004,"draft":564},"\u002Fblog\u002Fmissing-security-headers","Cabeçalhos de segurança faltando: quando isso importa","Cabeçalhos de segurança faltando é o achado que nosso scanner mais imprime. Contra o que eles protegem e quando são a linha menos urgente do relatório.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1006,"title":1007,"description":1008,"published":1009,"category":560,"image":1010,"draft":564},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Sua chave de API da OpenAI está exposta no frontend. Troque-a.","Uma chave de API da OpenAI exposta no frontend não pode ser presa a um domínio. Troque-a hoje, mova a chamada para o seu servidor e limite o gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1012,"title":1013,"description":1014,"published":1015,"category":560,"image":1016,"draft":564},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Chave de API exposta no frontend: o que 30.998 apps entregam","Uma chave de API exposta no seu frontend costuma ser uma chave do Google Maps. Escaneamos 30.998 apps vibe-coded e contamos quais segredos vazam de verdade.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1018,"title":1019,"description":1020,"published":1021,"category":665,"image":1022,"draft":564},"\u002Fblog\u002Fsupabase-backup-tools-compared","Ferramentas de backup do Supabase comparadas, a nossa incluída","Quatro tipos de ferramenta de backup do Supabase, o que cada uma copia de verdade e quando uma GitHub Action gratuita ganha de pagar, nós inclusive.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1024,"title":1025,"description":1026,"published":1027,"category":560,"image":1028,"draft":564},"\u002Fblog\u002Freplit-secrets-explained","Como usar secrets no Replit, e o que ainda assim é publicado","Como usar secrets no Replit: adicionar um, ler de volta e resolver as duas causas do undefined. E as chaves que a ferramenta Secrets não consegue proteger.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1030,"title":1031,"description":1032,"published":1033,"category":665,"image":1034,"draft":564},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups do plano gratuito do Supabase: como fazer sem terminal","No plano gratuito do Supabase não existe backup nenhum: a cópia é você que faz. Como fazer uma pelo painel e o que a rota do CSV deixa para trás.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1036,"title":1037,"description":1038,"published":1039,"category":560,"image":1040,"draft":564},"\u002Fblog\u002Fis-supabase-secure","O Supabase é seguro? É. Seu projeto é outra pergunta","O Supabase é seguro? A plataforma é auditada, criptografada e passa por pentests. A documentação deles diz onde isso termina e começam suas configurações.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1042,"title":1043,"description":1044,"published":1045,"category":560,"image":1046,"draft":564},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Onde ficam as chaves de API do Supabase: anon, service_role e URL","A URL do projeto, a chave anon e a chave service_role ficam todas numa página do painel. Aqui está onde ela fica, e qual dos quatro valores vai no seu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1048,"title":1049,"description":1050,"published":1051,"category":560,"image":1052,"draft":564},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy no Supabase. E agora?","\"New row violates row-level security policy\" significa que o Supabase recusou uma escrita. O conserto rápido reabre a tabela para qualquer um.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":425,"title":1054,"description":1055,"published":1056,"category":560,"image":1057,"draft":564},"Um curinga CORS é um risco de segurança? Quase nunca.","Um curinga CORS é um risco de segurança? Em geral é o padrão do seu builder e não entrega nada que o seu servidor já não desse a qualquer um que pedisse.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1059,"title":1060,"description":1061,"published":1062,"category":665,"image":1063,"draft":564},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching do Supabase não é backup. Ele só anda para a frente.","Por que o branching do Supabase não é backup: um branch começa sem os seus dados e um merge só leva o esquema. Para que ele serve e o que usar no lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1065,"title":1066,"description":1067,"published":1068,"category":665,"image":1069,"draft":564},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Como restaurar um backup do Supabase, e o que quebra depois","Como restaurar um backup do Supabase pelo painel ou por um arquivo de dump, o que a restauração substitui e por que o seu app pode continuar quebrado no fim.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1071,"title":1072,"description":1073,"published":1074,"category":560,"image":1075,"draft":564},"\u002Fblog\u002Fsupabase-storage-bucket-public","Seu bucket do Supabase Storage é público. Isso é um problema?","Um bucket público do Supabase Storage significa que quem tem a URL de um arquivo pode abri-lo. Não significa que alguém possa listar o que está lá dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1077,"title":1078,"description":1079,"published":1080,"category":560,"image":1081,"draft":564},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Uma chave de API do Google no frontend é um problema?","Uma chave de API do Google exposta no seu frontend é a chave que nosso scanner mais encontra, e quase sempre está tudo bem. Um ajuste gratuito decide isso.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1083,"title":1084,"description":1085,"published":1086,"category":665,"image":1087,"draft":564},"\u002Fblog\u002Fai-agent-deleted-my-database","Um agente de IA apagou meus dados do Supabase. O que eu recupero?","Um agente de IA apagou dados do seu banco. O que você recupera já estava decidido antes de ele rodar, e os próximos minutos decidem o resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1089,"title":1090,"description":1091,"published":1092,"category":560,"image":1093,"draft":564},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Qualquer um consegue ler seu banco Supabase? Testamos 3.680 apps","Qualquer um consegue ler seu banco de dados Supabase sem fazer login? Escaneamos 30.998 apps no ar criadas com builders de IA e medimos quantas dizem que sim.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1095,"title":1096,"description":1097,"published":1092,"category":560,"image":1098,"draft":564},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expostos: seu app está publicando o código original","Um source map exposto deixa qualquer um ler o código original do seu app, comentários incluídos. A verificação de 30 segundos e o que importa de verdade.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1100,"title":1101,"description":1102,"published":1103,"category":560,"image":1104,"draft":564},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: é a mesma coisa que a anon key?","O Supabase trocou anon e service_role por chaves publicáveis e secretas. Qual delas pertence ao seu app e qual nunca deve estar lá?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1106,"title":1107,"description":1108,"published":1109,"category":665,"image":1110,"draft":564},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","O Supabase faz backup do meu banco de dados? Depende do plano.","O Supabase faz backup do seu banco de dados? Todo dia nos planos pagos, e nada no gratuito. Como descobrir o que você tem e o que essa cópia não cobre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1112,"title":1113,"description":1114,"published":1115,"category":560,"image":1116,"draft":564},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","O Supabase Row Level Security está ligado. A tabela continua pública.","Ligar o Supabase Row Level Security não protege uma tabela. Quem protege são as políticas, e a que consertou o seu app pode deixar qualquer um entrar.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1118,"title":1119,"description":1120,"published":1115,"category":665,"image":1121,"draft":564},"\u002Fblog\u002Fversion-history-is-not-a-backup","O histórico de versões não é backup. Ele não desfaz um delete.","Lovable e Bolt guardam um histórico de versões do seu código. Seu banco de dados é um serviço à parte, e voltar atrás não traz os seus dados de volta.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1123,"title":1124,"description":1125,"published":1126,"category":665,"image":1127,"draft":564},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Três formas de fazer backup de um banco Supabase, e o que falta","O painel, o pg_dump e um serviço gerenciado. O que cada um salva de verdade, o que deixa de fora sem avisar e qual sobrevive a perder a conta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1129,"title":1130,"description":1131,"published":1126,"category":560,"image":1132,"draft":564},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Quais chaves de API são seguras no navegador e quais não são","Sua chave anon do Supabase foi feita para ser pública. Sua chave service_role não, e ela ignora todas as regras que você criar. Como diferenciar as duas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213648760]