[{"data":1,"prerenderedAt":1253},["ShallowReactive",2],{"blog-uk-edge-function-returned-a-non-2xx-status-code":3,"blog-index-uk":727},{"id":4,"title":5,"body":6,"category":685,"cover":686,"coverAlt":687,"description":688,"draft":689,"extension":690,"faq":691,"image":706,"keywords":707,"meta":715,"navigation":716,"ogTitle":717,"path":718,"published":719,"seo":720,"stem":721,"tldr":722,"updated":719,"__hash__":726},"blog_uk\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code.md","\"Edge Function returned a non-2xx status code\": справжня помилка",{"type":7,"value":8,"toc":672},"minimark",[9,13,24,27,35,40,43,62,65,82,88,92,95,120,133,139,171,175,178,300,315,319,322,337,343,362,379,383,391,408,437,440,460,465,469,472,508,514,518,521,541,556,564,571,575,581,590,604,614,631,635,660],[10,11,12],"p",{},"Ви натискаєте у своєму застосунку кнопку, що викликає Edge Function, і замість\nрезультату застосунок показує ось це:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","Edge Function returned a non-2xx status code\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Це те саме речення, хоч би що пішло не так. Відсутній ключ, функція, що впала,\nзапит, відхилений ще до запуску вашого коду: усе це звучить як\n\"Edge Function returned a non-2xx status code\", тож саме повідомлення майже\nнічого не каже про те, що лагодити.",[10,28,29,30,34],{},"Чого воно не каже, то це що причина вже прийшла. ",[31,32,33],"strong",{},"Помилка повернулася в тій\nсамій відповіді, що й це речення, а supabase-js вам її не зачитує."," Пошук за\nреченням дасть вам чужі здогадки. Читання відповіді дасть вашу власну.",[36,37,39],"h2",{"id":38},"що-означає-edge-function-returned-a-non-2xx-status-code","Що означає \"Edge Function returned a non-2xx status code\"?",[10,41,42],{},"Ваша функція відповіла, і відповіддю була помилка. Це все, що каже речення.",[10,44,45,46,49,50,57,58,61],{},"Кожна відповідь у вебі несе код статусу, тризначне число, яке каже, як пройшов\nзапит. Усе в межах 200-х означає, що спрацювало. Коли ваш застосунок викликає\nфункцію через ",[21,47,48],{},"supabase.functions.invoke",", supabase-js дивиться на це число, і\nякщо воно поза межами 200-х, віддає застосунку незмінне речення замість даних.\nЦе речення слово в слово записане\n",[51,52,56],"a",{"href":53,"rel":54},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Ffunctions-js\u002Fsrc\u002Ftypes.ts",[55],"nofollow","у самому supabase-js",",\nа помилка, що його несе, зветься ",[21,59,60],{},"FunctionsHttpError",".",[10,63,64],{},"Уявіть виклик як лист, який ви надсилаєте в контору в задніх кімнатах. Контора\nабо відповідає на ваше питання, або повертає лист. Коли він повертається,\nsupabase-js читає штамп на конверті й повідомляє, що лист повернули. Конверта\nвін не відкриває. Записка всередині пояснює чому, а контора вела журнал усього,\nщо відбувалося, поки ваш лист був у неї.",[10,66,67,68,71,72,76,77,81],{},"Двоє близьких родичів виглядають схоже, а означають інше. ",[21,69,70],{},"Failed to send a request to the Edge Function"," означає, що жодної читабельної відповіді взагалі\nне прийшло, і в браузері це часто відсутній заголовок CORS, про який розповідає\n",[51,73,75],{"href":74},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","допис про це повідомлення",". А\nякщо кілька не повʼязаних між собою частин застосунку зламалися одночасно,\nспершу перевірте,\n",[51,78,80],{"href":79},"\u002Fblog\u002Fis-supabase-down-or-your-app","чи справа в Supabase, чи у вашому застосунку",",\nперш ніж відкривати будь-який код.",[83,84],"diagram",{"alt":85,"caption":86,"src":87},"Запит іде з браузера до Edge Function. Відповідь, що повертається, несе статус 500 і вміст, повний рядків. supabase-js зводить її до однієї сірої смуги для застосунку, а пунктирна лінія веде від смуги назад до відкритої відповіді й далі до логу функції.","Відповідь несе статус і причину. supabase-js передає застосунку одне речення, а причина лишається прикріпленою до помилки та в лозі функції.","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fthe-reason-rides-back-1600x740.png",[36,89,91],{"id":90},"де-справжня-помилка","Де справжня помилка?",[10,93,94],{},"У двох місцях, і обидва можна прочитати, не змінивши жодного рядка коду.",[10,96,97,100,101,104,105,108,109,112,113,116,117,61],{},[31,98,99],{},"Сама відповідь."," Відкрийте опублікований застосунок у Chrome, Edge чи\nFirefox, натисніть F12, оберіть вкладку ",[31,102,103],{},"Network"," і повторіть те, що не\nспрацювало. Клацніть запит, адреса якого містить ",[21,106,107],{},"\u002Ffunctions\u002Fv1\u002F"," і далі назву\nвашої функції. У стовпці ",[31,110,111],{},"Status"," буде число, а на вкладці ",[31,114,115],{},"Response"," те, що\nфункція надіслала разом із ним: повідомлення, яке написав ваш власний код,\nкороткий JSON від платформи Supabase або слова ",[21,118,119],{},"Internal Server Error",[10,121,122,123,128,129,132],{},"Якщо ви або інструмент, що пише ваш код, можете змінити виклик,\n",[51,124,127],{"href":125,"rel":126},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Ferror-handling",[55],"посібник Supabase з обробки помилок","\nпоказує, як прочитати ту саму відповідь усередині застосунку, бо початкова\nвідповідь подорожує разом із помилкою як ",[21,130,131],{},"error.context",":",[14,134,137],{"className":135,"code":136,"language":19},[17],"const { data, error } = await supabase.functions.invoke('your-function', { body })\nif (error) console.log(error.context.status, await error.context.text())\n",[21,138,136],{"__ignoreMap":23},[10,140,141,144,145,148,149,152,153,156,157,162,163,166,167,170],{},[31,142,143],{},"Журнал функції."," У панелі Supabase відкрийте ",[31,146,147],{},"Edge Functions",", оберіть\nфункцію й прочитайте дві вкладки. ",[31,150,151],{},"Invocations"," показує кожен запит із його\nкодом статусу та тривалістю. ",[31,154,155],{},"Logs"," містить те, що\n",[51,158,161],{"href":159,"rel":160},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Flogging",[55],"посібник Supabase з логування","\nназиває подіями платформи, неперехопленими винятками та власними повідомленнями\nлогу, тобто все, що ваш код вивів через ",[21,164,165],{},"console.log"," чи ",[21,168,169],{},"console.error",".\nВідтворіть збій один раз, запамʼятайте час і прочитайте обидві вкладки за ту\nхвилину.",[36,172,174],{"id":173},"спершу-прочитайте-код-статусу","Спершу прочитайте код статусу",[10,176,177],{},"Число каже, як далеко зайшов ваш запит, перш ніж його повернули, і від цього\nзалежить, де записана причина.",[179,180,181,197],"table",{},[182,183,184],"thead",{},[185,186,187,191,194],"tr",{},[188,189,190],"th",{},"Статус",[188,192,193],{},"Що сталося",[188,195,196],{},"Де причина",[198,199,200,221,237,250,263,276,289],"tbody",{},[185,201,202,208,211],{},[203,204,205],"td",{},[21,206,207],{},"401",[203,209,210],{},"Відхилено до запуску вашого коду, або його відхилив ваш код",[203,212,213,214,166,217,220],{},"Відповідь. ",[21,215,216],{},"Invalid JWT",[21,218,219],{},"Missing authorization header"," означає платформу",[185,222,223,228,231],{},[203,224,225],{},[21,226,227],{},"404",[203,229,230],{},"У цьому проєкті не розгорнуто функції з такою назвою",[203,232,233,234],{},"У відповіді ",[21,235,236],{},"Requested function was not found",[185,238,239,244,247],{},[203,240,241],{},[21,242,243],{},"500",[203,245,246],{},"Ваш код запустився й кинув помилку або навмисно повернув 500",[203,248,249],{},"Вкладка Logs",[185,251,252,257,260],{},[203,253,254],{},[21,255,256],{},"503",[203,258,259],{},"Функція взагалі не запустилася",[203,261,262],{},"Вкладка Logs: імпорт, синтаксична помилка чи конфігурація функції",[185,264,265,270,273],{},[203,266,267],{},[21,268,269],{},"504",[203,271,272],{},"Жодної відповіді за 150 секунд",[203,274,275],{},"Вкладка Invocations, а потім те, чого чекав ваш код",[185,277,278,283,286],{},[203,279,280],{},[21,281,282],{},"546",[203,284,285],{},"Забракло процесорного часу чи памʼяті",[203,287,288],{},"Вкладка Logs каже, чого саме",[185,290,291,294,297],{},[203,292,293],{},"Будь-який інший 4xx",[203,295,296],{},"Його обрав ваш власний код, наприклад передавши відповідь якогось сервісу",[203,298,299],{},"Відповідь",[10,301,302,303,308,309,314],{},"Значення взято з\n",[51,304,307],{"href":305,"rel":306},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fstatus-codes",[55],"довідника кодів статусу Supabase","\nі його ",[51,310,313],{"href":311,"rel":312},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Flimits",[55],"сторінки з лімітами",".\nДля 404 досить цієї таблиці: звірте назву функції у вашому застосунку зі списком\nу панелі й перевірте, що її розгорнуто в тому проєкті, з яким говорить ваш\nзастосунок. Решта рядків має по окремому розділу нижче.",[36,316,318],{"id":317},"_500-ваша-функція-запустилася-й-упала","500: ваша функція запустилася й упала",[10,320,321],{},"Щось у вашому коді кинуло помилку, і вкладка Logs має цей рядок.",[10,323,324,329,330,332,333,336],{},[51,325,328],{"href":326,"rel":327},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fedge-function-500-error-response",[55],"Сторінка Supabase про цю помилку","\nділить її на два випадки. Якщо у відповіді рівно ",[21,331,119],{},", ваш\nкод упав, а лог показує тип помилки й рядок, де вона сталася, наприклад\n",[21,334,335],{},"TypeError: Cannot read properties of undefined",". Якщо у відповіді щось інше,\nваш код сам написав це повідомлення й повернув 500 навмисно, тож пошукайте у\nфункції статус, який вона надіслала.",[10,338,339,340],{},"Одну причину варто виключити раніше за всі інші, якщо функція викликає OpenAI,\nStripe чи будь-яке платне API: ",[31,341,342],{},"секрет, який є на вашому компʼютері й відсутній\nв опублікованому проєкті.",[10,344,345,346,349,350,358,359,361],{},"Усередині функції секрет читають через ",[21,347,348],{},"Deno.env.get('OPENAI_API_KEY')",". Коли\nсекрету з такою назвою не задано, документація Deno каже, що це\n",[51,351,354,355],{"href":352,"rel":353},"https:\u002F\u002Fdocs.deno.com\u002Fapi\u002Fdeno\u002F~\u002FDeno.Env.get",[55],"повертає ",[21,356,357],{},"undefined",", а не\nпадає. Тож функція йде далі, складає запит зі словом ",[21,360,357],{}," там, де мав\nбути ключ, і надсилає його. OpenAI відповідає власним 401, \"Incorrect API key\nprovided\", а ваша функція або передає його далі, або падає, читаючи відповідь,\nякої не очікувала. У картинці з конвертом: контора відкрила ваш лист, підійшла\nдо шухляди, де мав лежати ключ, знайшла її порожньою й відіслала записку про\nнеправильний ключ.",[10,363,364,365,368,369,374,375,378],{},"Лагодять це на сторінці ",[31,366,367],{},"Edge Function Secrets"," вашого проєкту в Supabase.\n",[51,370,373],{"href":371,"rel":372},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fsecrets",[55],"Посібник Supabase із секретів","\nкаже, що функція читає новий секрет одразу, тож розгортати повторно не треба, і\nщо жодна назва секрету не може починатися з ",[21,376,377],{},"SUPABASE_",", бо цей префікс\nзарезервовано для значень, які Supabase задає за вас. Секрет, заданий для\nлокальної розробки, лишається на вашому компʼютері; в опублікованого проєкту\nвласний список.",[36,380,382],{"id":381},"_401-відхилено-до-запуску-вашого-коду","401: відхилено до запуску вашого коду",[10,384,385,386,166,388,390],{},"Якщо у відповіді ",[21,387,216],{},[21,389,219],{},", ваша функція\nтак і не побачила запиту. Платформа Supabase завернула його на порозі.",[10,392,393,394,397,398,401,402,407],{},"Цей поріг є перевіркою на імʼя ",[21,395,396],{},"verify_jwt",", увімкненою за замовчуванням, яка\nчитає заголовок ",[21,399,400],{},"Authorization"," кожного запиту до запуску вашого коду.\n",[51,403,406],{"href":404,"rel":405},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fedge-function-401-error-response",[55],"Сторінка Supabase про 401","\nназиває три способи її не пройти:",[409,410,411,418,431],"ul",{},[412,413,414,417],"li",{},[31,415,416],{},"Ключ не збігається з ключами вашого проєкту."," Наприклад, ключ, скопійований\nз іншого проєкту, або старий, що досі десь прописаний після ротації.",[412,419,420,426,427,430],{},[31,421,422,423,425],{},"Заголовка ",[21,424,400],{}," немає взагалі."," supabase-js додає його за вас.\nПростий ",[21,428,429],{},"fetch"," на адресу функції чи вебхук від іншого сервісу цього не роблять.",[412,432,433,436],{},[31,434,435],{},"Ваш проєкт використовує новіші ключі підпису Supabase."," Вбудована перевірка\nрозуміє лише старий формат, і рішення Supabase полягає в тому, щоб вимкнути\nперевірку для цієї функції.",[10,438,439],{},"Цей останній пункт виходить за межі одного випадку. Supabase тепер радить\nвимкнути вбудовану перевірку й керувати автентифікацією просто в коді вашої\nфункції. Порада має дві половини, і друга якраз та, що губиться.",[10,441,442,443,446,447,451,452,455,456,459],{},"Якщо 401 прийшов із повідомленням, яке написав ваш власний код, платформа\nпропустила запит, а ваша функція його відхилила або передала 401 від сервісу,\nякий викликала, і часто це той самий порожній секрет із розділу про 500. Крім\nтого, це інша перевірка, ніж та, що стоїть за ",[21,444,445],{},"PGRST301"," у ваших запитах до\nбази, і вона ",[51,448,450],{"href":449},"\u002Fblog\u002Fsupabase-invalid-jwt","має окрему сторінку",". Якщо лог\nфункції показує ",[21,453,454],{},"invalid claim: missing sub claim",", вона спитала Supabase Auth,\nхто викликає, і отримала ключ вашого проєкту замість користувача, що ввійшов;\n",[51,457,75],{"href":458},"\u002Fblog\u002Finvalid-claim-missing-sub-claim"," розбирає це\nкрок за кроком.",[83,461],{"alt":462,"caption":463,"src":464},"Запит іде з браузера крізь браму, всередину функції й далі до зовнішнього сервісу. Кожне місце, де він може зупинитися, позначене своїм числом: 401 біля брами, 404 там, де за адресою немає функції, 500 усередині функції, 546 і 504 на годиннику поруч, і 401 від зовнішнього сервісу, який функція повертає назад.","Статус каже, як далеко зайшов запит. 401 біля брами так і не дістався вашого коду; 401, повернутий сервісом, який функція викликала, дістався.","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fhow-far-it-got-1600x720.png",[36,466,468],{"id":467},"_546-і-504-забракло-ресурсів-або-часу","546 і 504: забракло ресурсів або часу",[10,470,471],{},"Supabase зупиняє функцію, яка споживає забагато, і два числа кажуть, у який\nліміт вона вперлася.",[10,473,474,477,481,482,485,486,489,490,493,494,497,498,501,502,507],{},[31,475,476],{},"546 стосується обчислень.",[51,478,480],{"href":311,"rel":479},[55],"Сторінка з лімітами"," дає\nфункції 256 МБ памʼяті, а кожному запиту 2 секунди процесорного часу.\nПеревищте будь-що з цього, і відповідь буде\n",[21,483,484],{},"Function failed due to not having enough compute resources (please check logs)",",\nз кодом ",[21,487,488],{},"WORKER_RESOURCE_LIMIT"," (старі логи кажуть ",[21,491,492],{},"WORKER_LIMIT","). Вкладка Logs\nкаже ",[21,495,496],{},"CPU Time exceeded"," або ",[21,499,500],{},"Memory limit exceeded",".\n",[51,503,506],{"href":504,"rel":505},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fedge-function-546-error-response",[55],"Сторінка Supabase про 546","\nнаводить як приклади обробку зображень, ембединги для ШІ та вебскрейпінг, а її\nпорада полягає в тому, щоб робити менше за один запит або віддати важку частину\nіншому сервісу.",[10,509,510,513],{},[31,511,512],{},"504 стосується часу."," Функція, яка не надіслала відповіді за 150 секунд,\nотримує 504. Ліміт процесорного часу рахує лише час, коли ваш код справді\nобчислює: сторінка з лімітами каже, що асинхронне введення-виведення сюди не\nвходить, а очікування мережі саме ним і є. Тож функція, яка чекає на повільну\nмодель ШІ, процесорного часу не витрачає. Вона спалює годинник на 150 секунд, і\nколи той спливає, ви отримуєте 504, а не 546.",[36,515,517],{"id":516},"два-виправлення-що-роблять-гірше","Два виправлення, що роблять гірше",[10,519,520],{},"Дві зміни прибирають це повідомлення за лічені хвилини, і обидві лишають вас у\nгіршому становищі, ніж сама помилка.",[10,522,523,526,527,530,531,535,536,540],{},[31,524,525],{},"Викликати API просто зі сторінки."," Найшвидший спосіб змусити функцію, що\nпадає, перестати падати, це перестати нею користуватися: покласти ключ у змінну\nз ",[21,528,529],{},"VITE_"," і викликати OpenAI прямо з фронтенду. Це спрацьовує з першої спроби. А\nще кладе ключ у файл, який завантажує кожен відвідувач, бо цей префікс є\n",[51,532,534],{"href":533},"\u002Fblog\u002Fvite-and-next-public-env-vars","вказівкою вкомпілювати значення у ваш бандл",",\nі там його може прочитати будь-хто. Серед опублікованих застосунків, які ми\nпросканували, ключ OpenAI знайшовся в JavaScript у 33, і про те,\n",[51,537,539],{"href":538},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","що з ним може зробити стороння людина",",\nє окрема стаття.",[10,542,543,546,547,549,550,555],{},[31,544,545],{},"Вимкнути перевірку й на цьому зупинитися."," Позбутися 401, вимкнувши\n",[21,548,396],{},", означає виконати першу половину поради самої Supabase.\n",[51,551,554],{"href":552,"rel":553},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Ffunction-configuration",[55],"Посібник Supabase з конфігурації","\nпрямо каже, що це дає саме по собі: тоді будь-хто може викликати вашу Edge\nFunction без дійсного JWT. Адреса вашої функції лежить у вашому фронтенді, і її\nможе прочитати кожен. Якщо функція тримає ключ OpenAI, стороння людина тепер\nможе витрачати його через вас. Якщо вона використовує секретний ключ проєкту,\nякий Supabase кладе в оточення кожної функції, запит сторонньої людини працює з\nключем, що обходить кожне правило row level security, яке ви написали.",[10,557,558,559,563],{},"Друга половина, перевірка всередині функції того, хто викликає, займає кілька\nрядків. ",[51,560,562],{"href":561},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Як перенести секрет в Edge Function","\nмістить їх і пояснює, чому навіть стандартна перевірка пропускає більше\nвикликачів, ніж обіцяє її назва.",[10,565,566,567,61],{},"Першу помилку видно ззовні, і саме так ми її порахували. Наше безкоштовне\nсканування читає JavaScript вашого опублікованого застосунку так, як прочитала б\nстороння людина, і називає кожен ключ, який знаходить, уточнюючи, чи має він там\nбути. Це займає близько 20 секунд і не потребує облікового запису:\n",[51,568,570],{"href":569},"\u002Fsecurity-scanner","проскануйте свій застосунок",[36,572,574],{"id":573},"щоб-ключ-лишався-там-де-ви-його-поклали","Щоб ключ лишався там, де ви його поклали",[10,576,577,580],{},[31,578,579],{},"Сьогоднішнє виправлення може скасувати промпт наступного тижня."," Конструктор,\nякого просять знову змусити працювати якусь функцію, вільний піти тим самим\nкоротким шляхом, а ваш застосунок і далі працює, поки він це робить.",[10,582,583],{},[31,584,585,589],{},[51,586,588],{"href":587},"\u002Fwebsite-monitoring","Reeve Monitor"," перевіряє щогодини замість вас:",[409,591,592,595,598,601],{},[412,593,594],{},"усі девʼять перевірок щогодини, для трьох застосунків",[412,596,597],{},"лист того дня, коли нове сканування оцінить ваш застосунок гірше за попереднє; секретний ключ у вашому JavaScript сам обмежує оцінку рівнем D",[412,599,600],{},"чи застосунок доступний, кожні 60 секунд",[412,602,603],{},"щомісячний звіт про те, що він бачив",[10,605,606],{},[31,607,608,609,613],{},"Функція, що працює з вашим секретним ключем, обходить кожне правило row level\nsecurity. ",[51,610,612],{"href":611},"\u002Fsupabase-backups","Reeve Care"," тримає копію вашої бази Supabase там,\nкуди ніщо у вашому проєкті не дістане.",[409,615,616,619,622,625,628],{},[412,617,618],{},"зашифрована копія за розкладом, у власному сховищі Reeve в ЄС, поза вашим обліковим записом Supabase",[412,620,621],{},"кожна копія перевірена, перш ніж її зарахують, підрахунком рядків у кожній таблиці",[412,623,624],{},"відновлення в один клік, яке зберігає те, що є зараз, перш ніж замінити",[412,626,627],{},"ваші завантажені файли теж, щойно ви приєднаєте доступ до Storage",[412,629,630],{},"усе, що робить Monitor",[36,632,634],{"id":633},"що-зробити-зараз","Що зробити зараз",[636,637,638],"key-takeaways",{},[409,639,640,643,646,649,652,655],{},[412,641,642],{},"Відтворіть збій один раз і запамʼятайте час.",[412,644,645],{},"Відкрийте запит на вкладці Network у браузері й прочитайте його статус і відповідь, перш ніж щось змінювати.",[412,647,648],{},"Прочитайте вкладки Invocations і Logs функції в панелі Supabase за ту хвилину.",[412,650,651],{},"Якщо 500 повертає функція, що викликає платне API, перевірте, чи задано секрет на сторінці Edge Function Secrets опублікованого проєкту. Повторно розгортати після цього не треба.",[412,653,654],{},"Якщо 401 повертає платформа, виправте ключ або вимкніть вбудовану перевірку й у тій самій зміні додайте всередині функції перевірку того, хто викликає.",[412,656,657,658,61],{},"Ніколи не прибирайте цю помилку, переносячи ключ у змінну з ",[21,659,529],{},[10,661,662,663,666,667,671],{},"Перевірку того, хто викликає, пропустити найлегше, і\n",[51,664,665],{"href":561},"посібник про секрети в Edge Functions","\nрозбирає її повністю. ",[51,668,670],{"href":669},"\u002Fchecklist","10-хвилинний чекліст безпеки"," охоплює те, що\nзазвичай лишається відкритим у щойно запущеному застосунку.",{"title":23,"searchDepth":673,"depth":673,"links":674},3,[675,677,678,679,680,681,682,683,684],{"id":38,"depth":676,"text":39},2,{"id":90,"depth":676,"text":91},{"id":173,"depth":676,"text":174},{"id":317,"depth":676,"text":318},{"id":381,"depth":676,"text":382},{"id":467,"depth":676,"text":468},{"id":516,"depth":676,"text":517},{"id":573,"depth":676,"text":574},{"id":633,"depth":676,"text":634},"Основи безпеки","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcover-1200x630.png","Повернений конверт із жовтим штампом навскіс через лицевий бік і відкритим клапаном, а всередині досі складений лист.","\"Edge Function returned a non-2xx status code\" означає, що ваша функція Supabase відповіла помилкою. Ось де прочитати справжню.",false,"md",[692,694,697,700,703],{"q":39,"a":693},"Це означає, що ваша Edge Function у Supabase відповіла статусом помилки, тобто будь-яким числом поза межами 200-х, а supabase-js перетворив цю відповідь на одне незмінне речення. Речення однакове для падіння коду, відсутнього ключа, запиту, відхиленого ще до запуску вашого коду, і вичерпаного часу. Сама відповідь, яка каже, що саме сталося, лишається прикріпленою до помилки, а функція веде власний лог.",{"q":695,"a":696},"Як побачити справжню помилку за цим повідомленням?","Відкрийте свій опублікований застосунок, натисніть F12, оберіть вкладку Network і повторіть те, що не спрацювало. Клацніть запит, адреса якого містить \u002Ffunctions\u002Fv1\u002F, і прочитайте його статус і відповідь: це те, що функція насправді надіслала. Потім відкрийте Edge Functions у панелі Supabase, оберіть функцію й прочитайте вкладки Invocations і Logs за той самий час. У коді посібник Supabase читає ту саму відповідь через await error.context.json().",{"q":698,"a":699},"Чому моя Edge Function працює локально і падає після розгортання?","Спершу перевірте, чи секрет існує на вашому компʼютері й відсутній в опублікованому проєкті. Локальне середовище читає власний файл оточення, а розгорнута функція читає секрети, задані в проєкті. Відсутній секрет повертається як undefined, а не як помилка, тож функція працює далі й падає пізніше, зазвичай коли сервіс, який вона викликає, відхиляє порожній ключ. Задайте його на сторінці Edge Function Secrets; за словами Supabase, новий секрет читається одразу, без повторного розгортання.",{"q":701,"a":702},"Чи варто вимикати перевірку JWT, щоб позбутися 401?","Supabase тепер радить вимкнути вбудовану перевірку й натомість перевіряти того, хто викликає, усередині вашої функції. Важать обидві половини. Вимкнена сама по собі, перевірка вже нічого не зупиняє, і документація Supabase сама попереджає, що тоді будь-хто може викликати вашу функцію без дійсного JWT. Якщо функція тримає ключ OpenAI або секретний ключ проєкту, це будь-хто в інтернеті, хто витрачає вашу квоту чи обходить ваші правила row level security.",{"q":704,"a":705},"Що означає помилка 546 у Supabase Edge Function?","Функції забракло обчислень: понад 2 секунди процесорного часу або більше памʼяті, ніж їй відведено, на одному запиті. Відповідь звучить так: \"Function failed due to not having enough compute resources (please check logs)\", а вкладка Logs каже, який саме ліміт, CPU Time exceeded чи Memory limit exceeded. Очікування повільного API не рахується як процесорний час; функція, яка чекає надто довго, натомість отримує 504.","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",[708,709,60,710,711,712,713,714],"edge function returned a non-2xx status code","помилка edge function supabase","помилка supabase functions invoke","supabase edge function 500","supabase edge function 401","логи edge function supabase","помилка edge function lovable",{},true,"\"Edge Function returned a non-2xx status code\" у Supabase","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","2026-10-27",{"title":5,"description":688},"blog\u002Fedge-function-returned-a-non-2xx-status-code",[723,724,725],"\"Edge Function returned a non-2xx status code\" supabase-js каже про будь-яку відповідь вашої функції поза межами 200-х. Справжня причина прийшла в тій самій відповіді, а решта лежить у логах функції.","Спершу прочитайте номер статусу. 401 означає, що запит відхилили ще до запуску вашого коду, 404, що функції з такою назвою не розгорнуто, 500, що ваш код упав, 546 або 504, що забракло ресурсів чи часу.","Два швидкі виправлення змушують повідомлення замовкнути й відкривають діру: викликати API з фронтенду з ключем усередині та вимкнути перевірку JWT, не поставивши на її місце власної.","ewihqrPINdkKjeQDs-gWJ2UbMT8yvAVrOQBjUgvQKTI",[728,734,740,746,752,758,763,768,774,780,786,793,799,805,806,812,818,824,830,836,842,848,854,860,866,871,877,883,889,895,901,907,913,919,925,931,936,942,948,954,959,965,971,977,983,989,994,1000,1006,1012,1018,1024,1030,1036,1041,1047,1053,1059,1065,1071,1077,1083,1089,1095,1101,1107,1113,1119,1125,1130,1136,1142,1148,1154,1160,1166,1172,1178,1184,1190,1196,1202,1208,1214,1219,1225,1231,1237,1242,1248],{"path":729,"title":730,"description":731,"published":732,"category":685,"image":733,"draft":689},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\": пояснення","Supabase \"max client connections reached\": у пулера немає місця ще для одного клієнта. Ліміт визначає порт у вашому рядку підключення.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":735,"title":736,"description":737,"published":738,"category":685,"image":739,"draft":689},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Помилка Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": вхід через Google вимкнено у вашому проєкті Supabase. Як увімкнути та виправити redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":741,"title":742,"description":743,"published":744,"category":685,"image":745,"draft":689},"\u002Fblog\u002Fviolates-foreign-key-constraint","Помилка Supabase \"violates foreign key constraint\" під час вставки","Supabase \"insert or update on table violates foreign key constraint\": ваш рядок посилається на рядок, якого немає. Який, чому і як це виправити.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":747,"title":748,"description":749,"published":750,"category":685,"image":751,"draft":689},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Помилка Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": обовʼязковий стовпець прийшов порожнім. Звідки взявся null і як це виправити.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":753,"title":754,"description":755,"published":756,"category":685,"image":757,"draft":689},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": куди поділася сесія","\"Auth session missing!\" означає, що supabase-js не знайшла жодної сесії й навіть не спитала Supabase. Куди поділася сесія і як це виправити.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":458,"title":759,"description":760,"published":761,"category":685,"image":762,"draft":689},"Supabase \"invalid claim: missing sub claim\": ніхто не ввійшов","\"invalid claim: missing sub claim\": Supabase Auth отримав справжній токен без жодного користувача, ключ проєкту замість сесії.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":74,"title":764,"description":765,"published":766,"category":685,"image":767,"draft":689},"\"Failed to send a request to the Edge Function\": справжня причина","\"Failed to send a request to the Edge Function\": браузер не отримав відповіді, яку можна прочитати. Його консоль каже, чому, і чи ваша функція запускалася.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":769,"title":770,"description":771,"published":772,"category":685,"image":773,"draft":689},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Чому Supabase перенаправляє посилання з листів на localhost:3000","Якщо Supabase перенаправляє на localhost:3000, Site URL так і не змінили або вашої адреси немає в Redirect URLs. Як виправити і якої маски уникати.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":775,"title":776,"description":777,"published":778,"category":685,"image":779,"draft":689},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" на новому посиланні","На посиланні, надісланому хвилину тому, \"Email link is invalid or has expired\" у Supabase зазвичай означає, що поштовий фільтр використав його першим.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":781,"title":782,"description":783,"published":784,"category":685,"image":785,"draft":689},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\": пояснення","Supabase \"canceling statement due to statement timeout\": запит перевищив ліміт своєї ролі, 3 секунди для відвідувача. Спершу перевірте політику RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":787,"title":788,"description":789,"published":790,"category":791,"image":792,"draft":689},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" у Supabase і що зникає разом","\"Database error deleting user\" у Supabase: ваша база відмовилася видаляти. Причина в логах, а виправлення вирішує, що ще буде видалено.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":794,"title":795,"description":796,"published":797,"category":685,"image":798,"draft":689},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" у Supabase","Вебхук Stripe в Edge Function Supabase пише \"No signatures found matching the expected signature\"? Причин дві. Не вимикайте перевірку.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":800,"title":801,"description":802,"published":803,"category":685,"image":804,"draft":689},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" у Supabase: три причини","Supabase відповідає \"Invalid login credentials\" на неправильний пароль, невідому пошту й акаунт Google. Як зрозуміти, що саме.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":718,"title":5,"description":688,"published":719,"category":685,"image":706,"draft":689},{"path":807,"title":808,"description":809,"published":810,"category":685,"image":811,"draft":689},"\u002Fblog\u002Fcertificate-not-trusted","Сертифікат не довірений: три причини, крім закінчення строку","Сертифікат не довірений, хоча дата в порядку? Він називає іншу адресу, підписав сам себе або в його ланцюжку бракує ланки. Як зрозуміти, що саме.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":813,"title":814,"description":815,"published":816,"category":685,"image":817,"draft":689},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": що в лапках","Supabase \"invalid input syntax for type uuid\" означає, що застосунок надіслав щось, що не є id. Прочитайте лапки, притримайте запит, залиште колонку.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":819,"title":820,"description":821,"published":822,"category":685,"image":823,"draft":689},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\": пояснення","Supabase \"duplicate key value violates unique constraint\": значення вже зайняте. Знайдіть стовпець, оберіть виправлення й сховайте значення від очей.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":825,"title":826,"description":827,"published":828,"category":685,"image":829,"draft":689},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\", хоча таблиця на місці","Supabase \"relation does not exist\" або PGRST205: жодна таблиця не має такої назви в цій схемі. Чотири перевірки, і на що зважити, відкриваючи схему.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":831,"title":832,"description":833,"published":834,"category":685,"image":835,"draft":689},"\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\" показує назви аргументів, які надіслав ваш застосунок. Порівняйте їх із функцією.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":837,"title":838,"description":839,"published":840,"category":685,"image":841,"draft":689},"\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\" зазвичай означає, що назва не збігається. Чотири перевірки і рядок для перезавантаження.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":843,"title":844,"description":845,"published":846,"category":685,"image":847,"draft":689},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": два ліміти, один код помилки","Supabase \"Email Rate Limit Exceeded\" обмежує кожен лист вашого проєкту: 2 на годину з вбудованим відправником. Що враховується і як підняти ліміт.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":849,"title":850,"description":851,"published":852,"category":685,"image":853,"draft":689},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 причини","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" виводить ваших користувачів із системи. Три причини і як лог Auth їх розрізняє.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":855,"title":856,"description":857,"published":858,"category":685,"image":859,"draft":689},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": три причини","Supabase \"permission denied for schema public\" означає, що бракує GRANT на схему. Що його прибрало і який рядок його повертає.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":861,"title":862,"description":863,"published":864,"category":685,"image":865,"draft":689},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": три речі, які це може означати","Supabase \"Bucket not found\" означає одне з трьох: публічне посилання на приватний бакет, неточну назву або не той проєкт.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":449,"title":867,"description":868,"published":869,"category":685,"image":870,"draft":689},"Supabase invalid JWT: який ключ перестав працювати?","Помилка Supabase invalid JWT — це PGRST301: підписаний токен не пройшов перевірку. У новому проєкті йдеться про сесію, а не про ключ API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":872,"title":873,"description":874,"published":875,"category":685,"image":876,"draft":689},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" майже завжди означає нуль","Supabase повертає PGRST116, \"JSON object requested, multiple (or no) rows returned\", коли запит нічого не знайшов. Прихований рядок має вигляд відсутнього.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":878,"title":879,"description":880,"published":881,"category":685,"image":882,"draft":689},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" у Supabase: де шукати","\"Database error saving new user\" означає, що щось причеплене до вашої реєстрації в Supabase впало. Справжня помилка лежить у ваших логах.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":884,"title":885,"description":886,"published":887,"category":685,"image":888,"draft":689},"\u002Fblog\u002Fwhat-is-supabase","Що таке Supabase? База даних, яку обрав ваш білдер","Що таке Supabase: база даних, вхід і сховище файлів за вашим застосунком. Supabase тримає сервери, а правила про те, хто читає ваші рядки, ваші.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":890,"title":891,"description":892,"published":893,"category":685,"image":894,"draft":689},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Відкритий у фронтенді ключ AWS це не те саме, що ключ OpenAI","Ключ доступу AWS, відкритий у вашому фронтенді, читає і пише ваше сховище. Рішення зазвичай presigned URL, а не новий ключ.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":896,"title":897,"description":898,"published":899,"category":685,"image":900,"draft":689},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" при вивантаженні","\"New row violates row-level security policy for table objects\" означає, що вашому вивантаженню бракує правила insert. Публічний бакет його не додає.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":902,"title":903,"description":904,"published":905,"category":685,"image":906,"draft":689},"\u002Fblog\u002Fbase44-security-scan","Сканування безпеки Base44: те, що бачить лише воно","Сканування безпеки Base44 перевіряє сім видів проблем зсередини. Ось половина, яку читає тільки воно, і половина, на яку воно ніколи не дивиться.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":908,"title":909,"description":910,"published":911,"category":685,"image":912,"draft":689},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Ваш API-ключ витік. Порядок дій","API-ключ витік, і ви не знаєте, що робити першим. Не кожен ключ у вашому фронтенді є витоком, а порядок важить більше за швидкість.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":914,"title":915,"description":916,"published":917,"category":685,"image":918,"draft":689},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" без вимкнення RLS","\"Infinite recursion detected in policy for relation\" означає, що ваша policy запитала таблицю, яку вона захищає. Ось як розірвати коло.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":920,"title":921,"description":922,"published":923,"category":685,"image":924,"draft":689},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" у Supabase, і хибне виправлення","\"No API key found in request\" означає, що запит дійшов до Supabase без ключа. Більшість відповідей натомість вказують на правила вашої бази.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":926,"title":927,"description":928,"published":929,"category":685,"image":930,"draft":689},"\u002Fblog\u002Fis-base44-safe","Чи безпечний Base44? Дані 5 442 застосунків","Чи безпечний Base44? Ми прогнали дев’ять перевірок на 5 442 робочих застосунках Base44. Майже всі отримали B з причин, яких власник ніколи не обирав.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":561,"title":932,"description":933,"published":934,"category":685,"image":935,"draft":689},"Сховати ключ API: перенесіть його в Supabase Edge Function","Сховати ключ API означає прибрати його з браузера, а Supabase Edge Function це найменше місце, куди його покласти. Два кроки поруч важать більше.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":937,"title":938,"description":939,"published":940,"category":685,"image":941,"draft":689},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Чи відкритий ваш файл .env? Дванадцять шляхів для перевірки","Чи відкритий ваш файл .env на вашому власному вебсервері? Дванадцять адрес скажуть це за хвилину, а влучання означає, що все в ньому вже публічне.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":943,"title":944,"description":945,"published":946,"category":685,"image":947,"draft":689},"\u002Fblog\u002Fis-v0-safe","Безпека v0: усі 1 790 просканованих застосунків v0 отримали A","Безпека v0 на 1 790 живих застосунках v0: усі отримали A. Лише 17 згадували базу даних, і саме це здебільшого вимірює оцінка A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":949,"title":950,"description":951,"published":952,"category":685,"image":953,"draft":689},"\u002Fblog\u002Fis-bolt-safe","Чи безпечний Bolt? Що показали 1 123 застосунки Bolt","Чи безпечний Bolt? Ми прогнали 1 123 живі застосунки Bolt через дев’ять перевірок. Хостинг був чистим. Знахідки: ключі й відкриті таблиці в самих застосунках.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":79,"title":955,"description":956,"published":957,"category":685,"image":958,"draft":689},"Supabase не працює чи проблема у вашому застосунку? Як розрізнити","Supabase не працює чи зламався ваш застосунок? Пауза, повна база й ваша власна помилка виглядають однаково. Чотири перевірки їх розрізняють.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":960,"title":961,"description":962,"published":963,"category":685,"image":964,"draft":689},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Чи шифрує Supabase мої дані? Так. Ось від чого це захищає","Чи шифрує Supabase дані? Так: AES-256 у стані спокою, TLS під час передавання, SOC 2 та ISO 27001. Що покриває кожне і який витік не зупиняє жодне.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":966,"title":967,"description":968,"published":969,"category":685,"image":970,"draft":689},"\u002Fblog\u002Fsupabase-free-plan-limits","Ліміти безкоштовного тарифу Supabase і що стається на кожному","Ліміти безкоштовного тарифу Supabase: 500 МБ бази, 5 ГБ egress і жодних резервних копій. Що стається на кожній межі і що змінює Pro за $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":972,"title":973,"description":974,"published":975,"category":791,"image":976,"draft":689},"\u002Fblog\u002Ftest-your-supabase-backup","Перевірте резервну копію Supabase до того, як вона знадобиться","Як перевірити резервну копію Supabase: відновити в тестовий проєкт, порахувати рядки, увійти й знайти рядок, якого бракує обрізаному файлу.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":978,"title":979,"description":980,"published":981,"category":791,"image":982,"draft":689},"\u002Fblog\u002Fsupabase-backup-github-action","Безкоштовна резервна копія Supabase через GitHub Action і підступ","Резервна копія Supabase через GitHub Action безкоштовна й годиться багатьом застосункам. Робочий процес, потрібний рядок підключення та egress.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":984,"title":985,"description":986,"published":987,"category":791,"image":988,"draft":689},"\u002Fblog\u002Fdownload-your-supabase-backup","Чому ви не можете завантажити резервну копію Supabase","Завантажити резервну копію Supabase на сучасному проєкті не вийде: щоденна копія там фізична. Як це перевірити і як тримати власну копію.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":990,"title":991,"description":992,"published":987,"category":685,"image":993,"draft":689},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": бракує GRANT","З 30 жовтня нова таблиця в Supabase відповідає \"permission denied for table\", доки ви не дасте доступ. Лист показує лише половину виправлення.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":995,"title":996,"description":997,"published":998,"category":685,"image":999,"draft":689},"\u002Fblog\u002Fopen-api-endpoint-exposed","Чи є відкритий API-ендпоінт проблемою безпеки? Читайте JSON","Ваше сканування позначило відкритий API-ендпоінт. Чи це важливо, залежить від того, що повернулося, і більшість знайдених належали платформі.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1001,"title":1002,"description":1003,"published":1004,"category":685,"image":1005,"draft":689},"\u002Fblog\u002Flovable-security-scan","Сканування безпеки Lovable: чого воно не доведе","Сканування безпеки Lovable: що перевіряють Quick scan і Deep scan, коли запускається кожне, і єдине, чого не доведе жодне сканування зсередини.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1007,"title":1008,"description":1009,"published":1010,"category":791,"image":1011,"draft":689},"\u002Fblog\u002Fsupabase-backup-auth-users","Чому у вашому дампі Supabase немає користувачів","Запустіть supabase db dump окремо і отримаєте форму вашої бази та жодного її рядка, без схеми auth, у якій живуть ваші користувачі.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1013,"title":1014,"description":1015,"published":1016,"category":685,"image":1017,"draft":689},"\u002Fblog\u002Fdomain-and-certificate-expiry","Домен закінчився, сайт лежить: що буде далі","Ваш домен закінчився і сайт лежить. Ось який годинник уже пішов, чому прострочений сертифікат це менша з двох бід, і як перевірити обидва.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1019,"title":1020,"description":1021,"published":1022,"category":685,"image":1023,"draft":689},"\u002Fblog\u002Fis-lovable-safe","Чи безпечний Lovable? Що показали 18 554 застосунки Lovable","Чи безпечний Lovable? Ми прогнали 18 554 живі застосунки Lovable через дев’ять перевірок. Платформа виявилася найчистішою з п’яти. Знахідки були в застосунках.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1025,"title":1026,"description":1027,"published":1028,"category":685,"image":1029,"draft":689},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Чек-лист безпеки для vibe coding, у девʼяти перевірках","Чек-лист безпеки для vibe coding із девʼяти пунктів, кожен з яких будь-хто може перевірити у вашому живому застосунку ззовні, і кожен має тест на один рядок.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1031,"title":1032,"description":1033,"published":1034,"category":685,"image":1035,"draft":689},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Секретний ключ Stripe у фронтенді може рухати гроші","Секретний ключ Stripe, відкритий у вашому фронтенді, може повертати кошти, списувати й читати кожну картку клієнта. А ключ pk_live_ там і має бути.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":533,"title":1037,"description":1038,"published":1039,"category":685,"image":1040,"draft":689},"Змінні оточення Vite відкриті: префікс означає опублікувати це","Змінні оточення Vite відкриті у вашому застосунку, бо так просив префікс. VITE_ і NEXT_PUBLIC_ означають опублікувати це, а ШІ, який їх додав, не знав ціни.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1042,"title":1043,"description":1044,"published":1045,"category":685,"image":1046,"draft":689},"\u002Fblog\u002Fbase44-source-maps","Безпека Base44: що позначає скан і що з цього виправляти вам","Безпека Base44 на 5 438 просканованих застосунках: три знахідки майже на кожному належать платформі, source map є бейджем Base44, а ваша частина коротка.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1048,"title":1049,"description":1050,"published":1051,"category":685,"image":1052,"draft":689},"\u002Fblog\u002Fis-cursor-ai-safe","Чи безпечний Cursor AI? Редактор, код і опублікований застосунок","Чи безпечний Cursor AI? Три запитання в одному пошуку: що Cursor зберігає, у чому помиляється його код і чи відкритий застосунок, який ви опублікували.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1054,"title":1055,"description":1056,"published":1057,"category":685,"image":1058,"draft":689},"\u002Fblog\u002Fis-replit-safe","Чи безпечний Replit? Що ми знайшли в 3 042 живих застосунках Replit","Чи безпечний Replit? Ми прогнали 3 042 живі застосунки Replit через дев’ять зовнішніх перевірок. Знахідки були в опублікованому застосунку, а не в хостингу.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1060,"title":1061,"description":1062,"published":1063,"category":791,"image":1064,"draft":689},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: у копії бази даних немає жодного файлу","Supabase storage backup це окрема робота. Копії бази даних зберігають список ваших файлів і жодного з них, тож після відновлення кожне завантаження зламане.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1066,"title":1067,"description":1068,"published":1069,"category":791,"image":1070,"draft":689},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery у Supabase: ціна та межі","Point-in-time recovery у Supabase відмотує базу на будь-яку секунду за останній тиждень. Коштує $100 на місяць понад Pro і покриває лише базу даних.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1072,"title":1073,"description":1074,"published":1075,"category":791,"image":1076,"draft":689},"\u002Fblog\u002Fsupabase-project-paused-recover","Проєкт Supabase на паузі? Ваші дані нікуди не зникли","Supabase поставив ваш проєкт на паузу після тижня без активності. Нічого не видалено, кнопка Restore стоїть поруч із назвою, і у вас є рік, щоб натиснути.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1078,"title":1079,"description":1080,"published":1081,"category":685,"image":1082,"draft":689},"\u002Fblog\u002Fsafest-ai-app-builder","Який білдер застосунків з ШІ найбезпечніший? 30 998 тестів","Який білдер застосунків з ШІ найбезпечніший? Ми просканували 30 998 живих застосунків з Lovable, Base44, Replit, v0 і Bolt. Оцінку вирішує не білдер.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":1084,"title":1085,"description":1086,"published":1087,"category":685,"image":1088,"draft":689},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Увімкніть Row Level Security на кожній таблиці Supabase і перевірте","Row Level Security у Supabase без політики закриває таблицю повністю. Політика без увімкненого перемикача не робить нічого. Ось SQL, і ось перевірка.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1090,"title":1091,"description":1092,"published":1093,"category":685,"image":1094,"draft":689},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": чого не бачить попередження","Supabase позначає \"RLS disabled in public\" як помилку. Про політику читання, яка лишає вашу таблицю так само відкритою, він не каже нічого.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1096,"title":1097,"description":1098,"published":1099,"category":685,"image":1100,"draft":689},"\u002Fblog\u002Frotate-supabase-service-role-key","Як замінити злитий ключ service_role у Supabase","Supabase каже спершу закрити витік. Інші посібники кажуть міняти негайно. Що правильно, залежить від того, куди саме потрапив ваш ключ service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1102,"title":1103,"description":1104,"published":1105,"category":685,"image":1106,"draft":689},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Сканери безпеки для vibe coding у порівнянні, наш теж","Найкращий сканер безпеки для vibe coding залежить від трьох питань, на які не відповідає жоден перелік функцій. Вісім інструментів і ціни.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1108,"title":1109,"description":1110,"published":1111,"category":685,"image":1112,"draft":689},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: п’ять перевірок, які зробите самі","Supabase security checker читає ваш опублікований застосунок, а не налаштування проєкту. Ось п’ять перевірок і як виконати кожну самостійно.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1114,"title":1115,"description":1116,"published":1117,"category":685,"image":1118,"draft":689},"\u002Fblog\u002Fvibe-coding-security-scanner","Сканер безпеки для vibe coding: чого не бачить скан URL","Сканер безпеки для vibe coding читає ваш робочий застосунок ззовні. Що це охоплює, чотири речі, яких він не бачить, і як читати результат.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1120,"title":1121,"description":1122,"published":1123,"category":685,"image":1124,"draft":689},"\u002Fblog\u002Fmissing-security-headers","Відсутні заголовки безпеки: коли це справді важливо","Відсутні заголовки безпеки трапляються в наших звітах найчастіше. Від чого вони захищають і коли це найменш терміновий рядок вашого звіту.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":538,"title":1126,"description":1127,"published":1128,"category":685,"image":1129,"draft":689},"Ваш ключ API OpenAI відкритий у фронтенді. Замініть його.","Ключ API OpenAI, відкритий у фронтенді, не можна прив'язати до домену. Замініть його сьогодні, перенесіть виклик на свій сервер і обмежте витрати.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1131,"title":1132,"description":1133,"published":1134,"category":685,"image":1135,"draft":689},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Ключ API у фронтенді: що насправді віддають 30 998 застосунків","Ключ API, відкритий у вашому фронтенді, зазвичай є ключем Google Maps. Ми просканували 30 998 vibe-coded застосунків і порахували, що витікає насправді.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1137,"title":1138,"description":1139,"published":1140,"category":791,"image":1141,"draft":689},"\u002Fblog\u002Fsupabase-backup-tools-compared","Інструменти резервного копіювання Supabase, і наш серед них","Чотири види інструментів резервного копіювання Supabase, що копіює кожен і коли безкоштовна GitHub Action виграє в будь-якої оплати, нашої теж.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1143,"title":1144,"description":1145,"published":1146,"category":685,"image":1147,"draft":689},"\u002Fblog\u002Freplit-secrets-explained","Як користуватися секретами в Replit і що все одно публікується","Як користуватися секретами в Replit: додати, прочитати і усунути дві причини undefined. А ще ключі, які цей інструмент не здатен зберегти в таємниці.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1149,"title":1150,"description":1151,"published":1152,"category":791,"image":1153,"draft":689},"\u002Fblog\u002Fback-up-supabase-free-tier","Резервні копії на безкоштовному тарифі Supabase без терміналу","На безкоштовному тарифі Supabase резервних копій немає: копію робите ви. Як зробити її з панелі та що втрачає шлях через CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1155,"title":1156,"description":1157,"published":1158,"category":685,"image":1159,"draft":689},"\u002Fblog\u002Fis-supabase-secure","Чи безпечний Supabase? Так. Ваш проєкт це інше питання","Чи безпечний Supabase? Платформа проходить аудити, шифрує дані й тримає пентести. Їхня документація каже, де це закінчується і починаються ваші налаштування.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1161,"title":1162,"description":1163,"published":1164,"category":685,"image":1165,"draft":689},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Де знайти API-ключі Supabase: anon, service_role і URL","URL проєкту, ключ anon і ключ service_role лежать на одній сторінці панелі. Ось де вона, і яке з чотирьох значень має бути у вашому застосунку.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1167,"title":1168,"description":1169,"published":1170,"category":685,"image":1171,"draft":689},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy в Supabase. Що далі?","\"New row violates row-level security policy\" означає, що Supabase відмовив у записі. Швидке виправлення знову відкриває таблицю для всіх.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1173,"title":1174,"description":1175,"published":1176,"category":685,"image":1177,"draft":689},"\u002Fblog\u002Fcors-wildcard-security-risk","Чи є вайлдкард CORS ризиком для безпеки? Майже ніколи.","Чи є вайлдкард CORS ризиком для безпеки? Зазвичай це типове налаштування вашого білдера, і воно не видає нічого, що ваш сервер і так віддавав кожному.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1179,"title":1180,"description":1181,"published":1182,"category":791,"image":1183,"draft":689},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching у Supabase це не бекап. Він іде тільки вперед.","Чому branching у Supabase це не бекап: гілка стартує без ваших даних, а мердж переносить саму лише схему. Для чого він потрібен і що брати замість нього.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1185,"title":1186,"description":1187,"published":1188,"category":791,"image":1189,"draft":689},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Як відновити резервну копію Supabase, і що ламається потім","Як відновити резервну копію Supabase з панелі або з файлу дампа, що саме замінює відновлення і чому ваш застосунок може лишитися зламаним після нього.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1191,"title":1192,"description":1193,"published":1194,"category":685,"image":1195,"draft":689},"\u002Fblog\u002Fsupabase-storage-bucket-public","Ваш бакет Supabase Storage публічний. Чи це проблема?","Публічний бакет Supabase Storage означає, що той, хто має URL файлу, може його відкрити. Він не означає, що хтось може переглянути список вмісту.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1197,"title":1198,"description":1199,"published":1200,"category":685,"image":1201,"draft":689},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Чи є проблемою ключ API Google у вашому браузері?","Ключ API Google у відкритому коді сторінки наш сканер знаходить найчастіше, і зазвичай усе гаразд. Вирішує це одне безкоштовне налаштування.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1203,"title":1204,"description":1205,"published":1206,"category":791,"image":1207,"draft":689},"\u002Fblog\u002Fai-agent-deleted-my-database","ШІ-агент видалив мої дані в Supabase. Що можна відновити?","ШІ-агент видалив дані з вашої бази. Те, що ви зможете відновити, вирішилося раніше, а наступні хвилини вирішують, скільки з цього вціліє.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1209,"title":1210,"description":1211,"published":1212,"category":685,"image":1213,"draft":689},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Чи може будь-хто прочитати вашу базу Supabase? 3 680 застосунків","Чи може будь-хто прочитати вашу базу даних Supabase без входу? Ми просканували 30 998 живих застосунків, зроблених ШІ-білдерами, і виміряли, як часто так.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1215,"title":1216,"description":1217,"published":1212,"category":685,"image":1218,"draft":689},"\u002Fblog\u002Fsource-maps-exposed-in-production","Відкриті source maps: ваш застосунок публікує свій вихідний код","Відкрита source map дає будь-кому прочитати оригінальний код вашого застосунку, разом із коментарями. Перевірка за 30 секунд, і що важить насправді.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1220,"title":1221,"description":1222,"published":1223,"category":685,"image":1224,"draft":689},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: це той самий anon key?","Supabase замінив anon і service_role публічними та секретними ключами. Який із них має бути у вашому застосунку, а який не має бути ніколи?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1226,"title":1227,"description":1228,"published":1229,"category":791,"image":1230,"draft":689},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Чи робить Supabase резервні копії моєї бази? Залежить від тарифу.","Чи робить Supabase резервні копії вашої бази даних? На платних тарифах щодня, на безкоштовному жодної. Як дізнатися, що у вас насправді є.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1232,"title":1233,"description":1234,"published":1235,"category":685,"image":1236,"draft":689},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security увімкнено. Таблиця досі публічна.","Увімкнути Supabase Row Level Security не означає захистити таблицю. Захищають політики, а та, що полагодила застосунок, часто впускає всіх.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1238,"title":1239,"description":1240,"published":1235,"category":791,"image":1241,"draft":689},"\u002Fblog\u002Fversion-history-is-not-a-backup","Історія версій не є резервною копією. Вона не поверне таблицю.","Lovable і Bolt ведуть історію версій вашого коду. Ваша база даних працює як окремий сервіс, тож відкат назад не поверне ваші дані.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1243,"title":1244,"description":1245,"published":1246,"category":791,"image":1247,"draft":689},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Три способи зробити резервну копію бази Supabase, і чого бракує","Панель, pg_dump і керований сервіс. Що насправді зберігає кожен спосіб, що тихо лишає осторонь і який із них переживе втрату акаунта.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1249,"title":1250,"description":1251,"published":1246,"category":685,"image":1252,"draft":689},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Які API-ключі безпечні у браузері, а які ні","Ваш ключ anon у Supabase створений, щоб бути публічним. Ключ service_role для цього не створений, і він ігнорує всі правила, які ви задали. Як їх розрізнити.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213654285]