[{"data":1,"prerenderedAt":16907},["ShallowReactive",2],{"navigation_docs":3,"-tu-hoc-database-supabase-api-sdk":420,"-tu-hoc-database-supabase-api-sdk-surround":16902},[4,153],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Phỏng vấn .NET","i-lucide-briefcase","\u002Fphong-van","1.phong-van",[10,27,66,111,128],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":26},"Tổng quan","i-lucide-compass","\u002Fphong-van\u002Ftong-quan","1.phong-van\u002F1.tong-quan",[16,21],{"title":17,"path":18,"stem":19,"icon":20},"Thị trường HCM","\u002Fphong-van\u002Ftong-quan\u002Fthi-truong","1.phong-van\u002F1.tong-quan\u002F1.thi-truong","i-lucide-trending-up",{"title":22,"path":23,"stem":24,"icon":25},"Lộ trình 7 ngày","\u002Fphong-van\u002Ftong-quan\u002Flo-trinh","1.phong-van\u002F1.tong-quan\u002F2.lo-trinh","i-lucide-calendar-days",false,{"title":22,"icon":25,"path":28,"stem":29,"children":30,"page":26},"\u002Fphong-van\u002Flo-trinh","1.phong-van\u002F2.lo-trinh",[31,36,41,46,51,56,61],{"title":32,"path":33,"stem":34,"icon":35},"Ngày 1 — C# cơ bản","\u002Fphong-van\u002Flo-trinh\u002Fngay-1-csharp-co-ban","1.phong-van\u002F2.lo-trinh\u002F1.ngay-1-csharp-co-ban","i-lucide-1",{"title":37,"path":38,"stem":39,"icon":40},"Ngày 2 — OOP và SOLID","\u002Fphong-van\u002Flo-trinh\u002Fngay-2-oop-solid","1.phong-van\u002F2.lo-trinh\u002F2.ngay-2-oop-solid","i-lucide-2",{"title":42,"path":43,"stem":44,"icon":45},"Ngày 3 — C# nâng cao","\u002Fphong-van\u002Flo-trinh\u002Fngay-3-csharp-nang-cao","1.phong-van\u002F2.lo-trinh\u002F3.ngay-3-csharp-nang-cao","i-lucide-3",{"title":47,"path":48,"stem":49,"icon":50},"Ngày 4 — Database và SQL","\u002Fphong-van\u002Flo-trinh\u002Fngay-4-database-sql","1.phong-van\u002F2.lo-trinh\u002F4.ngay-4-database-sql","i-lucide-4",{"title":52,"path":53,"stem":54,"icon":55},"Ngày 5 — ASP.NET Core và EF Core","\u002Fphong-van\u002Flo-trinh\u002Fngay-5-aspnet-efcore","1.phong-van\u002F2.lo-trinh\u002F5.ngay-5-aspnet-efcore","i-lucide-5",{"title":57,"path":58,"stem":59,"icon":60},"Ngày 6 — DSA coding","\u002Fphong-van\u002Flo-trinh\u002Fngay-6-dsa","1.phong-van\u002F2.lo-trinh\u002F6.ngay-6-dsa","i-lucide-6",{"title":62,"path":63,"stem":64,"icon":65},"Ngày 7 — Mock và HR","\u002Fphong-van\u002Flo-trinh\u002Fngay-7-mock-interview","1.phong-van\u002F2.lo-trinh\u002F7.ngay-7-mock-interview","i-lucide-7",{"title":67,"icon":68,"path":69,"stem":70,"children":71,"page":26},"Ngân hàng câu hỏi","i-lucide-database","\u002Fphong-van\u002Fngan-hang-cau-hoi","1.phong-van\u002F3.ngan-hang-cau-hoi",[72,77,82,87,92,97,102,107],{"title":73,"path":74,"stem":75,"icon":76},"C# (60+ câu)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fcsharp","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F1.csharp","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"OOP và SOLID (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Foop","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F2.oop","i-lucide-shapes",{"title":83,"path":84,"stem":85,"icon":86},"SQL (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fsql","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F3.sql","i-lucide-database-zap",{"title":88,"path":89,"stem":90,"icon":91},"ASP.NET và EF (50+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-ef","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F4.aspnet-ef","i-lucide-server",{"title":93,"path":94,"stem":95,"icon":96},"DSA và Coding (30+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdsa-coding","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F5.dsa-coding","i-lucide-binary",{"title":98,"path":99,"stem":100,"icon":101},"HR và Soft skill (25+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fhr-behavior","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F6.hr-behavior","i-lucide-users",{"title":103,"path":104,"stem":105,"icon":106},"Design Pattern (55+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdesign-pattern","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F7.design-pattern","i-lucide-puzzle",{"title":108,"path":109,"stem":110,"icon":91},"ASP.NET MVC và Web API","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-mvc-webapi","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F8.aspnet-mvc-webapi",{"title":112,"itle":113,"icon":114,"path":115,"stem":116,"children":117,"page":26},"Tai Lieu","Tài liệu và Cheat sheet","i-lucide-book-marked","\u002Fphong-van\u002Ftai-lieu","1.phong-van\u002F4.tai-lieu",[118,123],{"title":119,"path":120,"stem":121,"icon":122},"Cheat Sheet","\u002Fphong-van\u002Ftai-lieu\u002Fcheatsheet","1.phong-van\u002F4.tai-lieu\u002F1.cheatsheet","i-lucide-clipboard-list",{"title":124,"path":125,"stem":126,"icon":127},"Nguồn tham khảo","\u002Fphong-van\u002Ftai-lieu\u002Fnguon","1.phong-van\u002F4.tai-lieu\u002F2.nguon","i-lucide-link",{"title":129,"icon":130,"path":131,"stem":132,"children":133,"page":26},"Phỏng vấn English","i-lucide-globe","\u002Fphong-van\u002Fenglish-interview","1.phong-van\u002F5.english-interview",[134,138,143,148],{"title":135,"path":136,"stem":137,"icon":130},"Tổng quan English","\u002Fphong-van\u002Fenglish-interview\u002Ftong-quan","1.phong-van\u002F5.english-interview\u002F1.tong-quan",{"title":139,"path":140,"stem":141,"icon":142},"Vocabulary","\u002Fphong-van\u002Fenglish-interview\u002Fvocabulary","1.phong-van\u002F5.english-interview\u002F2.vocabulary","i-lucide-book-a",{"title":144,"path":145,"stem":146,"icon":147},"Technical Q và A (EN)","\u002Fphong-van\u002Fenglish-interview\u002Ftechnical-en","1.phong-van\u002F5.english-interview\u002F3.technical-en","i-lucide-code",{"title":149,"path":150,"stem":151,"icon":152},"Behavioral (EN)","\u002Fphong-van\u002Fenglish-interview\u002Fbehavioral-en","1.phong-van\u002F5.english-interview\u002F4.behavioral-en","i-lucide-message-square-text",{"title":154,"icon":155,"path":156,"stem":157,"children":158},"Tự học","i-lucide-graduation-cap","\u002Ftu-hoc","2.tu-hoc",[159,161,287,310,333,357,384],{"title":154,"path":156,"stem":160,"icon":155},"2.tu-hoc\u002Findex",{"title":162,"icon":68,"path":163,"stem":164,"children":165},"Database","\u002Ftu-hoc\u002Fdatabase","2.tu-hoc\u002F1.database\u002Findex",[166,167,197,222,243,248],{"title":162,"path":163,"stem":164,"icon":68},{"title":168,"icon":91,"path":169,"stem":170,"children":171,"page":26},"SQL Server","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server","2.tu-hoc\u002F1.database\u002F2.sql-server",[172,177,182,187,192],{"title":173,"path":174,"stem":175,"icon":176},"1. Giới thiệu và Cài đặt","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F1.gioi-thieu-cai-dat","i-lucide-play-circle",{"title":178,"path":179,"stem":180,"icon":181},"2. Cú pháp cơ bản","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F2.cu-phap-co-ban","i-lucide-code-2",{"title":183,"path":184,"stem":185,"icon":186},"3. Truy vấn nâng cao","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F3.truy-van-nang-cao","i-lucide-git-merge",{"title":188,"path":189,"stem":190,"icon":191},"4. Đặc thù và Performance","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F4.dac-thu-performance","i-lucide-gauge",{"title":193,"path":194,"stem":195,"icon":196},"5. Q và A phỏng vấn","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F5.cau-hoi-phong-van","i-lucide-message-circle-question",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":26},"PostgreSQL","i-simple-icons-postgresql","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql","2.tu-hoc\u002F1.database\u002F3.postgresql",[203,206,209,212,215,218],{"title":173,"path":204,"stem":205,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":207,"stem":208,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F2.cu-phap-co-ban",{"title":183,"path":210,"stem":211,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F3.truy-van-nang-cao",{"title":188,"path":213,"stem":214,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F4.dac-thu-performance",{"title":193,"path":216,"stem":217,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F5.cau-hoi-phong-van",{"title":219,"path":220,"stem":221,"icon":96},"6. Tích hợp C# và Postgres","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftich-hop-csharp","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F6.tich-hop-csharp",{"title":223,"icon":224,"path":225,"stem":226,"children":227,"page":26},"MySQL","i-simple-icons-mysql","\u002Ftu-hoc\u002Fdatabase\u002Fmysql","2.tu-hoc\u002F1.database\u002F4.mysql",[228,231,234,237,240],{"title":173,"path":229,"stem":230,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F4.mysql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":232,"stem":233,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F4.mysql\u002F2.cu-phap-co-ban",{"title":183,"path":235,"stem":236,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F4.mysql\u002F3.truy-van-nang-cao",{"title":188,"path":238,"stem":239,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F4.mysql\u002F4.dac-thu-performance",{"title":193,"path":241,"stem":242,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F4.mysql\u002F5.cau-hoi-phong-van",{"title":244,"path":245,"stem":246,"icon":247},"So sánh 3 RDBMS","\u002Ftu-hoc\u002Fdatabase\u002Fso-sanh","2.tu-hoc\u002F1.database\u002F5.so-sanh","i-lucide-columns-3",{"title":249,"path":250,"stem":251,"children":252,"icon":254},"Supabase (BaaS)","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002Findex",[253,255,259,264,269,274,278,283],{"title":249,"path":250,"stem":251,"icon":254},"i-simple-icons-supabase",{"title":256,"path":257,"stem":258,"icon":68},"1. Database","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fdatabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002F1.database",{"title":260,"path":261,"stem":262,"icon":263},"2. Authentication","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fauthentication","2.tu-hoc\u002F1.database\u002F6.supabase\u002F2.authentication","i-lucide-key",{"title":265,"path":266,"stem":267,"icon":268},"3. Storage & Realtime","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fstorage-realtime","2.tu-hoc\u002F1.database\u002F6.supabase\u002F3.storage-realtime","i-lucide-zap",{"title":270,"path":271,"stem":272,"icon":273},"4. Edge Functions & AI","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Ffunctions-ai","2.tu-hoc\u002F1.database\u002F6.supabase\u002F4.functions-ai","i-lucide-brain",{"title":275,"path":276,"stem":277,"icon":181},"5. API & SDKs","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fapi-sdk","2.tu-hoc\u002F1.database\u002F6.supabase\u002F5.api-sdk",{"title":279,"path":280,"stem":281,"icon":282},"6. Platform & Deploy","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fplatform-deploy","2.tu-hoc\u002F1.database\u002F6.supabase\u002F6.platform-deploy","i-lucide-cloud",{"title":284,"path":285,"stem":286,"icon":196},"7. Interview & Q&A","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Finterview","2.tu-hoc\u002F1.database\u002F6.supabase\u002F7.interview",{"title":288,"icon":289,"path":290,"stem":291,"children":292},"TypeScript","i-simple-icons-typescript","\u002Ftu-hoc\u002Ftypescript","2.tu-hoc\u002F2.typescript\u002Findex",[293,294,297,301,306],{"title":288,"path":290,"stem":291,"icon":289},{"title":173,"path":295,"stem":296,"icon":176},"\u002Ftu-hoc\u002Ftypescript\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F2.typescript\u002F1.gioi-thieu-cai-dat",{"title":298,"path":299,"stem":300,"icon":81},"2. Type System","\u002Ftu-hoc\u002Ftypescript\u002Ftype-system","2.tu-hoc\u002F2.typescript\u002F2.type-system",{"title":302,"path":303,"stem":304,"icon":305},"3. Advanced types","\u002Ftu-hoc\u002Ftypescript\u002Fadvanced-types","2.tu-hoc\u002F2.typescript\u002F3.advanced-types","i-lucide-braces",{"title":307,"path":308,"stem":309,"icon":196},"4. Q và A phỏng vấn","\u002Ftu-hoc\u002Ftypescript\u002Fcau-hoi-phong-van","2.tu-hoc\u002F2.typescript\u002F4.cau-hoi-phong-van",{"title":311,"icon":81,"path":312,"stem":313,"children":314},"OOP","\u002Ftu-hoc\u002Foop","2.tu-hoc\u002F3.oop\u002Findex",[315,316,321,326,330],{"title":311,"path":312,"stem":313,"icon":81},{"title":317,"path":318,"stem":319,"icon":320},"1. Bốn tính chất","\u002Ftu-hoc\u002Foop\u002F4-tinh-chat","2.tu-hoc\u002F3.oop\u002F1.4-tinh-chat","i-lucide-circle-dot",{"title":322,"path":323,"stem":324,"icon":325},"2. SOLID","\u002Ftu-hoc\u002Foop\u002Fsolid","2.tu-hoc\u002F3.oop\u002F2.solid","i-lucide-shield",{"title":327,"path":328,"stem":329,"icon":106},"3. Design Pattern","\u002Ftu-hoc\u002Foop\u002Fdesign-pattern","2.tu-hoc\u002F3.oop\u002F3.design-pattern",{"title":307,"path":331,"stem":332,"icon":196},"\u002Ftu-hoc\u002Foop\u002Fcau-hoi-phong-van","2.tu-hoc\u002F3.oop\u002F4.cau-hoi-phong-van",{"title":334,"icon":305,"path":335,"stem":336,"children":337},"Generic","\u002Ftu-hoc\u002Fgeneric","2.tu-hoc\u002F4.generic\u002Findex",[338,339,344,349,354],{"title":334,"path":335,"stem":336,"icon":305},{"title":340,"path":341,"stem":342,"icon":343},"1. Khái niệm và cú pháp","\u002Ftu-hoc\u002Fgeneric\u002Fkhai-niem","2.tu-hoc\u002F4.generic\u002F1.khai-niem","i-lucide-book",{"title":345,"path":346,"stem":347,"icon":348},"2. Constraint và Variance","\u002Ftu-hoc\u002Fgeneric\u002Fconstraint-variance","2.tu-hoc\u002F4.generic\u002F2.constraint-variance","i-lucide-filter",{"title":350,"path":351,"stem":352,"icon":353},"3. C# vs TS","\u002Ftu-hoc\u002Fgeneric\u002Fso-sanh","2.tu-hoc\u002F4.generic\u002F3.so-sanh","i-lucide-git-compare",{"title":307,"path":355,"stem":356,"icon":196},"\u002Ftu-hoc\u002Fgeneric\u002Fcau-hoi-phong-van","2.tu-hoc\u002F4.generic\u002F4.cau-hoi-phong-van",{"title":358,"icon":359,"path":360,"stem":361,"children":362},"Nuxt 4","i-simple-icons-nuxt","\u002Ftu-hoc\u002Fnuxt-4","2.tu-hoc\u002F5.nuxt-4\u002Findex",[363,364,367,372,376,379],{"title":358,"path":360,"stem":361,"icon":359},{"title":173,"path":365,"stem":366,"icon":176},"\u002Ftu-hoc\u002Fnuxt-4\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F5.nuxt-4\u002F1.gioi-thieu-cai-dat",{"title":368,"path":369,"stem":370,"icon":371},"2. Routing và Rendering","\u002Ftu-hoc\u002Fnuxt-4\u002Frouting-rendering","2.tu-hoc\u002F5.nuxt-4\u002F2.routing-rendering","i-lucide-route",{"title":373,"path":374,"stem":375,"icon":91},"3. Data và Server","\u002Ftu-hoc\u002Fnuxt-4\u002Fdata-server","2.tu-hoc\u002F5.nuxt-4\u002F3.data-server",{"title":307,"path":377,"stem":378,"icon":196},"\u002Ftu-hoc\u002Fnuxt-4\u002Fcau-hoi-phong-van","2.tu-hoc\u002F5.nuxt-4\u002F4.cau-hoi-phong-van",{"title":380,"path":381,"stem":382,"icon":383},"5. Practical Todo App","\u002Ftu-hoc\u002Fnuxt-4\u002Fpractical-todo-app","2.tu-hoc\u002F5.nuxt-4\u002F5.practical-todo-app","i-lucide-check-square",{"title":385,"path":386,"stem":387,"children":388,"icon":390},"Tailwind CSS","\u002Ftu-hoc\u002Ftailwindcss","2.tu-hoc\u002F6.tailwindcss\u002Findex",[389,391,396,401,406,411,416],{"title":385,"path":386,"stem":387,"icon":390},"i-simple-icons-tailwindcss",{"title":392,"path":393,"stem":394,"icon":395},"1. Layout & Spacing","\u002Ftu-hoc\u002Ftailwindcss\u002Flayout-spacing","2.tu-hoc\u002F6.tailwindcss\u002F1.layout-spacing","i-lucide-layout",{"title":397,"path":398,"stem":399,"icon":400},"2. Typography & Colors","\u002Ftu-hoc\u002Ftailwindcss\u002Ftypography-colors","2.tu-hoc\u002F6.tailwindcss\u002F2.typography-colors","i-lucide-type",{"title":402,"path":403,"stem":404,"icon":405},"3. Interactive & Effects","\u002Ftu-hoc\u002Ftailwindcss\u002Finteractive-effects","2.tu-hoc\u002F6.tailwindcss\u002F3.interactive-effects","i-lucide-sparkles",{"title":407,"path":408,"stem":409,"icon":410},"4. Responsive & Dark Mode","\u002Ftu-hoc\u002Ftailwindcss\u002Fresponsive-darkmode","2.tu-hoc\u002F6.tailwindcss\u002F4.responsive-darkmode","i-lucide-monitor-smartphone",{"title":412,"path":413,"stem":414,"icon":415},"5. Customization & Theme","\u002Ftu-hoc\u002Ftailwindcss\u002Fcustomization","2.tu-hoc\u002F6.tailwindcss\u002F5.customization","i-lucide-settings-2",{"title":417,"path":418,"stem":419,"icon":181},"6. Practical Projects","\u002Ftu-hoc\u002Ftailwindcss\u002Fpractical-projects","2.tu-hoc\u002F6.tailwindcss\u002F6.practical-projects",{"id":421,"title":422,"body":423,"description":16895,"extension":16896,"links":16897,"meta":16898,"navigation":16899,"path":276,"seo":16900,"stem":277,"__hash__":16901},"docs\u002F2.tu-hoc\u002F1.database\u002F6.supabase\u002F5.api-sdk.md","Supabase API & Client SDKs — REST, GraphQL, JavaScript, Flutter, Python",{"type":424,"value":425,"toc":16843},"minimark",[426,431,449,454,495,518,522,834,838,841,944,948,955,1166,1271,1275,1300,1303,1311,1324,1402,1406,1628,1632,2661,2665,4273,4277,8082,8086,9484,9488,11784,11788,11791,11849,11852,11998,12004,12014,12016,12020,12026,12110,12185,12192,12196,12291,12303,12305,12309,12313,12428,12432,12588,12592,12791,12795,12975,12979,13105,13109,13364,13368,13505,13509,13727,13731,13790,13794,13910,13914,13944,13948,14113,14115,14264,14268,14304,14308,14372,14376,14471,14475,14599,14621,14623,14627,14631,14645,14650,14724,14729,14766,14774,14805,14813,14904,14912,15219,15224,15239,15257,15261,15300,15442,15446,15464,15705,15709,15783,15787,16165,16169,16466,16468,16472,16567,16591,16618,16620,16624,16685,16687,16691,16830,16832,16839],[427,428,430],"h2",{"id":429},"rest-api-data-api-postgrest","REST API (Data API -- PostgREST)",[432,433,434,435,439,440,443,444,448],"p",{},"Supabase ",[436,437,438],"strong",{},"tự động sinh REST API"," từ database schema qua ",[436,441,442],{},"PostgREST",". API có sẵn tại ",[445,446,447],"code",{},"https:\u002F\u002F[PROJECT_REF].supabase.co\u002Frest\u002Fv1\u002F",".",[450,451,453],"h3",{"id":452},"đặc-điểm","Đặc điểm",[455,456,457,464,470,483,489],"ul",{},[458,459,460,463],"li",{},[436,461,462],{},"Auto-generated",": Schema thay đổi, API tự update -- không cần viết code backend",[458,465,466,469],{},[436,467,468],{},"Self-documenting",": Supabase tạo documentation trong Dashboard với đầy đủ endpoints và parameters",[458,471,472,475,476,479,480],{},[436,473,474],{},"Secure",": Tích hợp RLS, API key authentication qua header ",[445,477,478],{},"apikey"," và JWT trong ",[445,481,482],{},"Authorization",[458,484,485,488],{},[436,486,487],{},"Fast",": Hơn 300% nhanh hơn Firebase cho basic reads",[458,490,491,494],{},[436,492,493],{},"Scalable",": Hàng nghìn concurrent requests",[496,497,500,503,504,507,508,507,511,507,514,517],"callout",{"color":498,"icon":499},"primary","i-lucide-star",[436,501,502],{},"Nguyên lý hoạt động:"," PostgREST tự động map HTTP methods sang SQL: ",[445,505,506],{},"GET -> SELECT",", ",[445,509,510],{},"POST -> INSERT",[445,512,513],{},"PATCH -> UPDATE",[445,515,516],{},"DELETE -> DELETE",". URL query params map sang WHERE clause. Đây là lý do Supabase có REST API \"instant\" mà không cần viết code backend.",[450,519,521],{"id":520},"crud-qua-rest-api","CRUD qua REST API",[523,524,529],"pre",{"className":525,"code":526,"language":527,"meta":528,"style":528},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Read (SELECT) -- lấy tất cả posts\ncurl 'https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts?select=*' \\\n  -H 'apikey: [ANON_KEY]' \\\n  -H 'Authorization: Bearer [ANON_KEY]'\n\n# Filter -- lấy posts đã publish, sắp xếp giảm dần, giới hạn 10\ncurl 'https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts?select=id,title&status=eq.published&order=created_at.desc&limit=10' \\\n  -H 'apikey: [ANON_KEY]'\n\n# Insert -- tạo post mới (cần JWT nếu bảng có RLS)\ncurl -X POST 'https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts' \\\n  -H 'apikey: [ANON_KEY]' \\\n  -H 'Authorization: Bearer [JWT]' \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d '{\"title\": \"Hello\", \"content\": \"World\"}'\n\n# Update -- cập nhật post theo id\ncurl -X PATCH 'https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts?id=eq.1' \\\n  -H 'apikey: [ANON_KEY]' \\\n  -H 'Authorization: Bearer [JWT]' \\\n  -d '{\"title\": \"Updated\"}'\n\n# Delete -- xóa post theo id\ncurl -X DELETE 'https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts?id=eq.1' \\\n  -H 'apikey: [ANON_KEY]' \\\n  -H 'Authorization: Bearer [JWT]'\n","bash","",[445,530,531,540,562,577,590,597,603,617,628,633,639,659,672,686,700,713,718,724,743,756,769,781,786,792,810,823],{"__ignoreMap":528},[532,533,536],"span",{"class":534,"line":535},"line",1,[532,537,539],{"class":538},"sHwdD","# Read (SELECT) -- lấy tất cả posts\n",[532,541,543,547,551,555,558],{"class":534,"line":542},2,[532,544,546],{"class":545},"sBMFI","curl",[532,548,550],{"class":549},"sMK4o"," '",[532,552,554],{"class":553},"sfazB","https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts?select=*",[532,556,557],{"class":549},"'",[532,559,561],{"class":560},"sTEyZ"," \\\n",[532,563,565,568,570,573,575],{"class":534,"line":564},3,[532,566,567],{"class":553},"  -H",[532,569,550],{"class":549},[532,571,572],{"class":553},"apikey: [ANON_KEY]",[532,574,557],{"class":549},[532,576,561],{"class":560},[532,578,580,582,584,587],{"class":534,"line":579},4,[532,581,567],{"class":553},[532,583,550],{"class":549},[532,585,586],{"class":553},"Authorization: Bearer [ANON_KEY]",[532,588,589],{"class":549},"'\n",[532,591,593],{"class":534,"line":592},5,[532,594,596],{"emptyLinePlaceholder":595},true,"\n",[532,598,600],{"class":534,"line":599},6,[532,601,602],{"class":538},"# Filter -- lấy posts đã publish, sắp xếp giảm dần, giới hạn 10\n",[532,604,606,608,610,613,615],{"class":534,"line":605},7,[532,607,546],{"class":545},[532,609,550],{"class":549},[532,611,612],{"class":553},"https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts?select=id,title&status=eq.published&order=created_at.desc&limit=10",[532,614,557],{"class":549},[532,616,561],{"class":560},[532,618,620,622,624,626],{"class":534,"line":619},8,[532,621,567],{"class":553},[532,623,550],{"class":549},[532,625,572],{"class":553},[532,627,589],{"class":549},[532,629,631],{"class":534,"line":630},9,[532,632,596],{"emptyLinePlaceholder":595},[532,634,636],{"class":534,"line":635},10,[532,637,638],{"class":538},"# Insert -- tạo post mới (cần JWT nếu bảng có RLS)\n",[532,640,642,644,647,650,652,655,657],{"class":534,"line":641},11,[532,643,546],{"class":545},[532,645,646],{"class":553}," -X",[532,648,649],{"class":553}," POST",[532,651,550],{"class":549},[532,653,654],{"class":553},"https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts",[532,656,557],{"class":549},[532,658,561],{"class":560},[532,660,662,664,666,668,670],{"class":534,"line":661},12,[532,663,567],{"class":553},[532,665,550],{"class":549},[532,667,572],{"class":553},[532,669,557],{"class":549},[532,671,561],{"class":560},[532,673,675,677,679,682,684],{"class":534,"line":674},13,[532,676,567],{"class":553},[532,678,550],{"class":549},[532,680,681],{"class":553},"Authorization: Bearer [JWT]",[532,683,557],{"class":549},[532,685,561],{"class":560},[532,687,689,691,693,696,698],{"class":534,"line":688},14,[532,690,567],{"class":553},[532,692,550],{"class":549},[532,694,695],{"class":553},"Content-Type: application\u002Fjson",[532,697,557],{"class":549},[532,699,561],{"class":560},[532,701,703,706,708,711],{"class":534,"line":702},15,[532,704,705],{"class":553},"  -d",[532,707,550],{"class":549},[532,709,710],{"class":553},"{\"title\": \"Hello\", \"content\": \"World\"}",[532,712,589],{"class":549},[532,714,716],{"class":534,"line":715},16,[532,717,596],{"emptyLinePlaceholder":595},[532,719,721],{"class":534,"line":720},17,[532,722,723],{"class":538},"# Update -- cập nhật post theo id\n",[532,725,727,729,731,734,736,739,741],{"class":534,"line":726},18,[532,728,546],{"class":545},[532,730,646],{"class":553},[532,732,733],{"class":553}," PATCH",[532,735,550],{"class":549},[532,737,738],{"class":553},"https:\u002F\u002F[REF].supabase.co\u002Frest\u002Fv1\u002Fposts?id=eq.1",[532,740,557],{"class":549},[532,742,561],{"class":560},[532,744,746,748,750,752,754],{"class":534,"line":745},19,[532,747,567],{"class":553},[532,749,550],{"class":549},[532,751,572],{"class":553},[532,753,557],{"class":549},[532,755,561],{"class":560},[532,757,759,761,763,765,767],{"class":534,"line":758},20,[532,760,567],{"class":553},[532,762,550],{"class":549},[532,764,681],{"class":553},[532,766,557],{"class":549},[532,768,561],{"class":560},[532,770,772,774,776,779],{"class":534,"line":771},21,[532,773,705],{"class":553},[532,775,550],{"class":549},[532,777,778],{"class":553},"{\"title\": \"Updated\"}",[532,780,589],{"class":549},[532,782,784],{"class":534,"line":783},22,[532,785,596],{"emptyLinePlaceholder":595},[532,787,789],{"class":534,"line":788},23,[532,790,791],{"class":538},"# Delete -- xóa post theo id\n",[532,793,795,797,799,802,804,806,808],{"class":534,"line":794},24,[532,796,546],{"class":545},[532,798,646],{"class":553},[532,800,801],{"class":553}," DELETE",[532,803,550],{"class":549},[532,805,738],{"class":553},[532,807,557],{"class":549},[532,809,561],{"class":560},[532,811,813,815,817,819,821],{"class":534,"line":812},25,[532,814,567],{"class":553},[532,816,550],{"class":549},[532,818,572],{"class":553},[532,820,557],{"class":549},[532,822,561],{"class":560},[532,824,826,828,830,832],{"class":534,"line":825},26,[532,827,567],{"class":553},[532,829,550],{"class":549},[532,831,681],{"class":553},[532,833,589],{"class":549},[450,835,837],{"id":836},"query-parameters-filtering-sorting","Query Parameters -- Filtering & Sorting",[432,839,840],{},"PostgREST hỗ trợ query params mạnh mẽ để lọc, sắp xếp, phân trang trực tiếp qua URL:",[842,843,844,860],"table",{},[845,846,847],"thead",{},[848,849,850,854,857],"tr",{},[851,852,853],"th",{},"Query Param",[851,855,856],{},"Mô tả",[851,858,859],{},"Ví dụ",[861,862,863,879,897,912,927],"tbody",{},[848,864,865,871,874],{},[866,867,868],"td",{},[445,869,870],{},"select",[866,872,873],{},"Chọn cột, JOIN bảng liên quan",[866,875,876],{},[445,877,878],{},"select=id,title,author:author_id(name,avatar)",[848,880,881,886,889],{},[866,882,883],{},[445,884,885],{},"order",[866,887,888],{},"Sắp xếp kết quả",[866,890,891,507,894],{},[445,892,893],{},"order=created_at.desc",[445,895,896],{},"order=name.asc.nullslast",[848,898,899,904,907],{},[866,900,901],{},[445,902,903],{},"limit",[866,905,906],{},"Giới hạn số dòng trả về",[866,908,909],{},[445,910,911],{},"limit=10",[848,913,914,919,922],{},[866,915,916],{},[445,917,918],{},"offset",[866,920,921],{},"Bỏ qua N dòng đầu",[866,923,924],{},[445,925,926],{},"offset=20",[848,928,929,934,937],{},[866,930,931],{},[445,932,933],{},"range",[866,935,936],{},"Phân trang với header Range",[866,938,939,940,943],{},"Dùng ",[445,941,942],{},".range(0, 9)"," trong SDK",[450,945,947],{"id":946},"horizontal-filtering","Horizontal Filtering",[432,949,950,951,954],{},"Filter bằng cách thêm params vào URL với format ",[445,952,953],{},"[cột]=[operator].[value]",":",[842,956,957,969],{},[845,958,959],{},[848,960,961,964,967],{},[851,962,963],{},"Operator",[851,965,966],{},"SQL",[851,968,856],{},[861,970,971,986,1001,1016,1031,1046,1061,1076,1091,1106,1121,1136,1151],{},[848,972,973,978,983],{},[866,974,975],{},[445,976,977],{},"eq",[866,979,980],{},[445,981,982],{},"=",[866,984,985],{},"Bằng",[848,987,988,993,998],{},[866,989,990],{},[445,991,992],{},"neq",[866,994,995],{},[445,996,997],{},"!=",[866,999,1000],{},"Khác",[848,1002,1003,1008,1013],{},[866,1004,1005],{},[445,1006,1007],{},"gt",[866,1009,1010],{},[445,1011,1012],{},">",[866,1014,1015],{},"Lớn hơn",[848,1017,1018,1023,1028],{},[866,1019,1020],{},[445,1021,1022],{},"gte",[866,1024,1025],{},[445,1026,1027],{},">=",[866,1029,1030],{},"Lớn hơn hoặc bằng",[848,1032,1033,1038,1043],{},[866,1034,1035],{},[445,1036,1037],{},"lt",[866,1039,1040],{},[445,1041,1042],{},"\u003C",[866,1044,1045],{},"Nhỏ hơn",[848,1047,1048,1053,1058],{},[866,1049,1050],{},[445,1051,1052],{},"lte",[866,1054,1055],{},[445,1056,1057],{},"\u003C=",[866,1059,1060],{},"Nhỏ hơn hoặc bằng",[848,1062,1063,1068,1073],{},[866,1064,1065],{},[445,1066,1067],{},"like",[866,1069,1070],{},[445,1071,1072],{},"LIKE",[866,1074,1075],{},"Pattern matching (case-sensitive)",[848,1077,1078,1083,1088],{},[866,1079,1080],{},[445,1081,1082],{},"ilike",[866,1084,1085],{},[445,1086,1087],{},"ILIKE",[866,1089,1090],{},"Pattern matching (case-insensitive)",[848,1092,1093,1098,1103],{},[866,1094,1095],{},[445,1096,1097],{},"is",[866,1099,1100],{},[445,1101,1102],{},"IS",[866,1104,1105],{},"Kiểm tra NULL\u002FTRUE\u002FFALSE",[848,1107,1108,1113,1118],{},[866,1109,1110],{},[445,1111,1112],{},"in",[866,1114,1115],{},[445,1116,1117],{},"IN",[866,1119,1120],{},"Trong danh sách giá trị",[848,1122,1123,1128,1133],{},[866,1124,1125],{},[445,1126,1127],{},"contains",[866,1129,1130],{},[445,1131,1132],{},"@>",[866,1134,1135],{},"Chứa (JSONB\u002Farray)",[848,1137,1138,1143,1148],{},[866,1139,1140],{},[445,1141,1142],{},"or",[866,1144,1145],{},[445,1146,1147],{},"OR",[866,1149,1150],{},"Kết hợp điều kiện với OR",[848,1152,1153,1158,1163],{},[866,1154,1155],{},[445,1156,1157],{},"not",[866,1159,1160],{},[445,1161,1162],{},"NOT",[866,1164,1165],{},"Phủ định điều kiện",[523,1167,1169],{"className":525,"code":1168,"language":527,"meta":528,"style":528},"# Filter: status = 'published' AND category IN ('tech', 'science')\n\u002Frest\u002Fv1\u002Fposts?status=eq.published&category=in.(tech,science)\n\n# Filter: price > 100 AND price \u003C 500\n\u002Frest\u002Fv1\u002Fproducts?price=gt.100&price=lt.500\n\n# Filter: title chứa 'supabase' (không phân biệt hoa thường)\n\u002Frest\u002Fv1\u002Fposts?title=ilike.*supabase*\n\n# OR condition: status = 'draft' OR author_id = 'uuid'\n\u002Frest\u002Fv1\u002Fposts?or=(status.eq.draft,author_id.eq.uuid)\n",[445,1170,1171,1176,1204,1208,1213,1231,1235,1240,1248,1252,1257],{"__ignoreMap":528},[532,1172,1173],{"class":534,"line":535},[532,1174,1175],{"class":538},"# Filter: status = 'published' AND category IN ('tech', 'science')\n",[532,1177,1178,1181,1184,1187,1190,1192,1195,1198,1201],{"class":534,"line":542},[532,1179,1180],{"class":545},"\u002Frest\u002Fv1\u002Fposts?status",[532,1182,1183],{"class":553},"=eq.published",[532,1185,1186],{"class":549},"&",[532,1188,1189],{"class":560},"category",[532,1191,982],{"class":549},[532,1193,1194],{"class":553},"in.",[532,1196,1197],{"class":549},"(",[532,1199,1200],{"class":545},"tech,science",[532,1202,1203],{"class":549},")\n",[532,1205,1206],{"class":534,"line":564},[532,1207,596],{"emptyLinePlaceholder":595},[532,1209,1210],{"class":534,"line":579},[532,1211,1212],{"class":538},"# Filter: price > 100 AND price \u003C 500\n",[532,1214,1215,1218,1221,1223,1226,1228],{"class":534,"line":592},[532,1216,1217],{"class":545},"\u002Frest\u002Fv1\u002Fproducts?price",[532,1219,1220],{"class":553},"=gt.100",[532,1222,1186],{"class":549},[532,1224,1225],{"class":560},"price",[532,1227,982],{"class":549},[532,1229,1230],{"class":553},"lt.500\n",[532,1232,1233],{"class":534,"line":599},[532,1234,596],{"emptyLinePlaceholder":595},[532,1236,1237],{"class":534,"line":605},[532,1238,1239],{"class":538},"# Filter: title chứa 'supabase' (không phân biệt hoa thường)\n",[532,1241,1242,1245],{"class":534,"line":619},[532,1243,1244],{"class":545},"\u002Frest\u002Fv1\u002Fposts?title",[532,1246,1247],{"class":553},"=ilike.*supabase*\n",[532,1249,1250],{"class":534,"line":630},[532,1251,596],{"emptyLinePlaceholder":595},[532,1253,1254],{"class":534,"line":635},[532,1255,1256],{"class":538},"# OR condition: status = 'draft' OR author_id = 'uuid'\n",[532,1258,1259,1262,1264,1266,1269],{"class":534,"line":641},[532,1260,1261],{"class":545},"\u002Frest\u002Fv1\u002Fposts?or",[532,1263,982],{"class":553},[532,1265,1197],{"class":560},[532,1267,1268],{"class":553},"status.eq.draft,author_id.eq.uuid",[532,1270,1203],{"class":560},[450,1272,1274],{"id":1273},"embedded-resources-joins","Embedded Resources (JOINs)",[523,1276,1278],{"className":525,"code":1277,"language":527,"meta":528,"style":528},"# JOIN bảng authors để lấy thông tin author cùng post\n\u002Frest\u002Fv1\u002Fposts?select=id,title,created_at,author:author_id(id,name,avatar)\n",[445,1279,1280,1285],{"__ignoreMap":528},[532,1281,1282],{"class":534,"line":535},[532,1283,1284],{"class":538},"# JOIN bảng authors để lấy thông tin author cùng post\n",[532,1286,1287,1290,1293,1295,1298],{"class":534,"line":542},[532,1288,1289],{"class":545},"\u002Frest\u002Fv1\u002Fposts?select",[532,1291,1292],{"class":553},"=id,title,created_at,author:author_id",[532,1294,1197],{"class":560},[532,1296,1297],{"class":553},"id,name,avatar",[532,1299,1203],{"class":560},[1301,1302],"hr",{},[427,1304,1306,1307,1310],{"id":1305},"javascripttypescript-client-supabasesupabase-js","JavaScript\u002FTypeScript Client (",[445,1308,1309],{},"@supabase\u002Fsupabase-js",")",[432,1312,1313,1316,1317,1320,1321,954],{},[445,1314,1315],{},"supabase-js"," là isomorphic JavaScript library, hoạt động cả trên ",[436,1318,1319],{},"browser"," và ",[436,1322,1323],{},"Node.js",[523,1325,1329],{"className":1326,"code":1327,"language":1328,"meta":528,"style":528},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { createClient } from '@supabase\u002Fsupabase-js'\n\nconst supabase = createClient(\n  'https:\u002F\u002F[PROJECT_REF].supabase.co',\n  'your-publishable-key'\n)\n","javascript",[445,1330,1331,1355,1359,1376,1389,1398],{"__ignoreMap":528},[532,1332,1333,1337,1340,1343,1346,1349,1351,1353],{"class":534,"line":535},[532,1334,1336],{"class":1335},"s7zQu","import",[532,1338,1339],{"class":549}," {",[532,1341,1342],{"class":560}," createClient",[532,1344,1345],{"class":549}," }",[532,1347,1348],{"class":1335}," from",[532,1350,550],{"class":549},[532,1352,1309],{"class":553},[532,1354,589],{"class":549},[532,1356,1357],{"class":534,"line":542},[532,1358,596],{"emptyLinePlaceholder":595},[532,1360,1361,1365,1368,1370,1373],{"class":534,"line":564},[532,1362,1364],{"class":1363},"spNyl","const",[532,1366,1367],{"class":560}," supabase ",[532,1369,982],{"class":549},[532,1371,1342],{"class":1372},"s2Zo4",[532,1374,1375],{"class":560},"(\n",[532,1377,1378,1381,1384,1386],{"class":534,"line":579},[532,1379,1380],{"class":549},"  '",[532,1382,1383],{"class":553},"https:\u002F\u002F[PROJECT_REF].supabase.co",[532,1385,557],{"class":549},[532,1387,1388],{"class":549},",\n",[532,1390,1391,1393,1396],{"class":534,"line":592},[532,1392,1380],{"class":549},[532,1394,1395],{"class":553},"your-publishable-key",[532,1397,589],{"class":549},[532,1399,1400],{"class":534,"line":599},[532,1401,1203],{"class":560},[450,1403,1405],{"id":1404},"các-module-chính","Các module chính",[842,1407,1408,1420],{},[845,1409,1410],{},[848,1411,1412,1415,1418],{},[851,1413,1414],{},"Module",[851,1416,1417],{},"Phương thức chính",[851,1419,856],{},[861,1421,1422,1451,1502,1529,1562,1586,1613],{},[848,1423,1424,1428,1448],{},[866,1425,1426],{},[436,1427,162],{},[866,1429,1430,507,1433,507,1436,507,1439,507,1442,507,1445],{},[445,1431,1432],{},".select()",[445,1434,1435],{},".insert()",[445,1437,1438],{},".update()",[445,1440,1441],{},".delete()",[445,1443,1444],{},".upsert()",[445,1446,1447],{},".rpc()",[866,1449,1450],{},"Full CRUD với PostgreSQL",[848,1452,1453,1458,1499],{},[866,1454,1455],{},[436,1456,1457],{},"Filters",[866,1459,1460,507,1463,507,1466,507,1469,507,1472,507,1475,507,1478,507,1481,507,1484,507,1487,507,1490,507,1493,507,1496],{},[445,1461,1462],{},".eq()",[445,1464,1465],{},".neq()",[445,1467,1468],{},".gt()",[445,1470,1471],{},".lt()",[445,1473,1474],{},".gte()",[445,1476,1477],{},".lte()",[445,1479,1480],{},".like()",[445,1482,1483],{},".ilike()",[445,1485,1486],{},".is()",[445,1488,1489],{},".in()",[445,1491,1492],{},".contains()",[445,1494,1495],{},".or()",[445,1497,1498],{},".not()",[866,1500,1501],{},"Horizontal filtering",[848,1503,1504,1509,1526],{},[866,1505,1506],{},[436,1507,1508],{},"Modifiers",[866,1510,1511,507,1514,507,1517,507,1520,507,1523],{},[445,1512,1513],{},".limit()",[445,1515,1516],{},".order()",[445,1518,1519],{},".range()",[445,1521,1522],{},".single()",[445,1524,1525],{},".maybeSingle()",[866,1527,1528],{},"Phân trang, sắp xếp, lấy một bản ghi",[848,1530,1531,1536,1559],{},[866,1532,1533],{},[436,1534,1535],{},"Auth",[866,1537,1538,507,1541,507,1544,507,1547,507,1550,507,1553,507,1556],{},[445,1539,1540],{},".signUp()",[445,1542,1543],{},".signInWithPassword()",[445,1545,1546],{},".signInWithOAuth()",[445,1548,1549],{},".signInWithOtp()",[445,1551,1552],{},".signOut()",[445,1554,1555],{},".getUser()",[445,1557,1558],{},".getSession()",[866,1560,1561],{},"Xác thực người dùng",[848,1563,1564,1569,1583],{},[866,1565,1566],{},[436,1567,1568],{},"Realtime",[866,1570,1571,507,1574,507,1577,507,1580],{},[445,1572,1573],{},".channel()",[445,1575,1576],{},".subscribe()",[445,1578,1579],{},".on()",[445,1581,1582],{},".track()",[866,1584,1585],{},"WebSocket: Broadcast, Presence, Postgres Changes",[848,1587,1588,1593,1610],{},[866,1589,1590],{},[436,1591,1592],{},"Storage",[866,1594,1595,507,1598,507,1601,507,1604,507,1607],{},[445,1596,1597],{},".from().upload()",[445,1599,1600],{},".download()",[445,1602,1603],{},".getPublicUrl()",[445,1605,1606],{},".list()",[445,1608,1609],{},".remove()",[866,1611,1612],{},"Quản lý file storage",[848,1614,1615,1620,1625],{},[866,1616,1617],{},[436,1618,1619],{},"Functions",[866,1621,1622],{},[445,1623,1624],{},".functions.invoke()",[866,1626,1627],{},"Gọi Edge Functions",[450,1629,1631],{"id":1630},"full-crud-với-supabase-js","Full CRUD với supabase-js",[523,1633,1635],{"className":1326,"code":1634,"language":1328,"meta":528,"style":528},"\u002F\u002F ── SELECT với filters + JOINs + phân trang ──\nconst { data, error } = await supabase\n  .from('posts')\n  .select('id, title, author:author_id(name, avatar)')\n  .eq('status', 'published')          \u002F\u002F status = 'published'\n  .order('created_at', { ascending: false }) \u002F\u002F mới nhất trước\n  .range(0, 9)                        \u002F\u002F phân trang: 10 items đầu\n\n\u002F\u002F ── INSERT ──\nconst { data, error } = await supabase\n  .from('posts')\n  .insert({ title: 'Hello', content: 'World' })\n  .select()                           \u002F\u002F trả về row vừa insert\n\n\u002F\u002F ── UPDATE ──\nconst { data, error } = await supabase\n  .from('posts')\n  .update({ status: 'archived' })\n  .eq('id', 1)\n  .select()\n\n\u002F\u002F ── UPSERT ──\nconst { data, error } = await supabase\n  .from('posts')\n  .upsert({ id: 1, title: 'Updated' }, { onConflict: 'id' })\n\n\u002F\u002F ── DELETE ──\nconst { data, error } = await supabase\n  .from('posts')\n  .delete()\n  .eq('id', 1)\n\n\u002F\u002F ── Gọi Postgres function (RPC) ──\nconst { data, error } = await supabase\n  .rpc('get_user_stats', { user_id: 'uuid-here' })\n\n\u002F\u002F ── Auth ──\nconst { data, error } = await supabase.auth.signUp({\n  email: 'user@example.com',\n  password: 'secure-password'\n})\n\n\u002F\u002F ── Realtime subscribe ──\nconst channel = supabase\n  .channel('db-changes')\n  .on('postgres_changes',\n    { event: 'INSERT', schema: 'public', table: 'messages' },\n    (payload) => console.log('New message:', payload.new)\n  )\n  .subscribe()\n\n\u002F\u002F ── Storage ──\nconst { data, error } = await supabase.storage\n  .from('avatars')\n  .upload('public\u002Favatar1.png', file)\n\n\u002F\u002F ── Edge Functions ──\nconst { data, error } = await supabase.functions.invoke('hello-world', {\n  body: { name: 'Vinh' }\n})\n",[445,1636,1637,1642,1669,1688,1705,1735,1772,1795,1799,1804,1824,1840,1882,1894,1898,1903,1923,1939,1966,1988,1997,2001,2006,2026,2042,2093,2097,2103,2124,2141,2151,2172,2177,2183,2204,2241,2246,2252,2289,2306,2321,2328,2333,2339,2351,2370,2389,2438,2480,2486,2496,2501,2507,2533,2551,2573,2578,2584,2629,2654],{"__ignoreMap":528},[532,1638,1639],{"class":534,"line":535},[532,1640,1641],{"class":538},"\u002F\u002F ── SELECT với filters + JOINs + phân trang ──\n",[532,1643,1644,1646,1648,1651,1654,1657,1660,1663,1666],{"class":534,"line":542},[532,1645,1364],{"class":1363},[532,1647,1339],{"class":549},[532,1649,1650],{"class":560}," data",[532,1652,1653],{"class":549},",",[532,1655,1656],{"class":560}," error ",[532,1658,1659],{"class":549},"}",[532,1661,1662],{"class":549}," =",[532,1664,1665],{"class":1335}," await",[532,1667,1668],{"class":560}," supabase\n",[532,1670,1671,1674,1677,1679,1681,1684,1686],{"class":534,"line":564},[532,1672,1673],{"class":549},"  .",[532,1675,1676],{"class":1372},"from",[532,1678,1197],{"class":560},[532,1680,557],{"class":549},[532,1682,1683],{"class":553},"posts",[532,1685,557],{"class":549},[532,1687,1203],{"class":560},[532,1689,1690,1692,1694,1696,1698,1701,1703],{"class":534,"line":579},[532,1691,1673],{"class":549},[532,1693,870],{"class":1372},[532,1695,1197],{"class":560},[532,1697,557],{"class":549},[532,1699,1700],{"class":553},"id, title, author:author_id(name, avatar)",[532,1702,557],{"class":549},[532,1704,1203],{"class":560},[532,1706,1707,1709,1711,1713,1715,1718,1720,1722,1724,1727,1729,1732],{"class":534,"line":592},[532,1708,1673],{"class":549},[532,1710,977],{"class":1372},[532,1712,1197],{"class":560},[532,1714,557],{"class":549},[532,1716,1717],{"class":553},"status",[532,1719,557],{"class":549},[532,1721,1653],{"class":549},[532,1723,550],{"class":549},[532,1725,1726],{"class":553},"published",[532,1728,557],{"class":549},[532,1730,1731],{"class":560},")          ",[532,1733,1734],{"class":538},"\u002F\u002F status = 'published'\n",[532,1736,1737,1739,1741,1743,1745,1748,1750,1752,1754,1758,1760,1764,1766,1769],{"class":534,"line":599},[532,1738,1673],{"class":549},[532,1740,885],{"class":1372},[532,1742,1197],{"class":560},[532,1744,557],{"class":549},[532,1746,1747],{"class":553},"created_at",[532,1749,557],{"class":549},[532,1751,1653],{"class":549},[532,1753,1339],{"class":549},[532,1755,1757],{"class":1756},"swJcz"," ascending",[532,1759,954],{"class":549},[532,1761,1763],{"class":1762},"sfNiH"," false",[532,1765,1345],{"class":549},[532,1767,1768],{"class":560},") ",[532,1770,1771],{"class":538},"\u002F\u002F mới nhất trước\n",[532,1773,1774,1776,1778,1780,1784,1786,1789,1792],{"class":534,"line":605},[532,1775,1673],{"class":549},[532,1777,933],{"class":1372},[532,1779,1197],{"class":560},[532,1781,1783],{"class":1782},"sbssI","0",[532,1785,1653],{"class":549},[532,1787,1788],{"class":1782}," 9",[532,1790,1791],{"class":560},")                        ",[532,1793,1794],{"class":538},"\u002F\u002F phân trang: 10 items đầu\n",[532,1796,1797],{"class":534,"line":619},[532,1798,596],{"emptyLinePlaceholder":595},[532,1800,1801],{"class":534,"line":630},[532,1802,1803],{"class":538},"\u002F\u002F ── INSERT ──\n",[532,1805,1806,1808,1810,1812,1814,1816,1818,1820,1822],{"class":534,"line":635},[532,1807,1364],{"class":1363},[532,1809,1339],{"class":549},[532,1811,1650],{"class":560},[532,1813,1653],{"class":549},[532,1815,1656],{"class":560},[532,1817,1659],{"class":549},[532,1819,1662],{"class":549},[532,1821,1665],{"class":1335},[532,1823,1668],{"class":560},[532,1825,1826,1828,1830,1832,1834,1836,1838],{"class":534,"line":641},[532,1827,1673],{"class":549},[532,1829,1676],{"class":1372},[532,1831,1197],{"class":560},[532,1833,557],{"class":549},[532,1835,1683],{"class":553},[532,1837,557],{"class":549},[532,1839,1203],{"class":560},[532,1841,1842,1844,1847,1849,1852,1855,1857,1859,1862,1864,1866,1869,1871,1873,1876,1878,1880],{"class":534,"line":661},[532,1843,1673],{"class":549},[532,1845,1846],{"class":1372},"insert",[532,1848,1197],{"class":560},[532,1850,1851],{"class":549},"{",[532,1853,1854],{"class":1756}," title",[532,1856,954],{"class":549},[532,1858,550],{"class":549},[532,1860,1861],{"class":553},"Hello",[532,1863,557],{"class":549},[532,1865,1653],{"class":549},[532,1867,1868],{"class":1756}," content",[532,1870,954],{"class":549},[532,1872,550],{"class":549},[532,1874,1875],{"class":553},"World",[532,1877,557],{"class":549},[532,1879,1345],{"class":549},[532,1881,1203],{"class":560},[532,1883,1884,1886,1888,1891],{"class":534,"line":674},[532,1885,1673],{"class":549},[532,1887,870],{"class":1372},[532,1889,1890],{"class":560},"()                           ",[532,1892,1893],{"class":538},"\u002F\u002F trả về row vừa insert\n",[532,1895,1896],{"class":534,"line":688},[532,1897,596],{"emptyLinePlaceholder":595},[532,1899,1900],{"class":534,"line":702},[532,1901,1902],{"class":538},"\u002F\u002F ── UPDATE ──\n",[532,1904,1905,1907,1909,1911,1913,1915,1917,1919,1921],{"class":534,"line":715},[532,1906,1364],{"class":1363},[532,1908,1339],{"class":549},[532,1910,1650],{"class":560},[532,1912,1653],{"class":549},[532,1914,1656],{"class":560},[532,1916,1659],{"class":549},[532,1918,1662],{"class":549},[532,1920,1665],{"class":1335},[532,1922,1668],{"class":560},[532,1924,1925,1927,1929,1931,1933,1935,1937],{"class":534,"line":720},[532,1926,1673],{"class":549},[532,1928,1676],{"class":1372},[532,1930,1197],{"class":560},[532,1932,557],{"class":549},[532,1934,1683],{"class":553},[532,1936,557],{"class":549},[532,1938,1203],{"class":560},[532,1940,1941,1943,1946,1948,1950,1953,1955,1957,1960,1962,1964],{"class":534,"line":726},[532,1942,1673],{"class":549},[532,1944,1945],{"class":1372},"update",[532,1947,1197],{"class":560},[532,1949,1851],{"class":549},[532,1951,1952],{"class":1756}," status",[532,1954,954],{"class":549},[532,1956,550],{"class":549},[532,1958,1959],{"class":553},"archived",[532,1961,557],{"class":549},[532,1963,1345],{"class":549},[532,1965,1203],{"class":560},[532,1967,1968,1970,1972,1974,1976,1979,1981,1983,1986],{"class":534,"line":745},[532,1969,1673],{"class":549},[532,1971,977],{"class":1372},[532,1973,1197],{"class":560},[532,1975,557],{"class":549},[532,1977,1978],{"class":553},"id",[532,1980,557],{"class":549},[532,1982,1653],{"class":549},[532,1984,1985],{"class":1782}," 1",[532,1987,1203],{"class":560},[532,1989,1990,1992,1994],{"class":534,"line":758},[532,1991,1673],{"class":549},[532,1993,870],{"class":1372},[532,1995,1996],{"class":560},"()\n",[532,1998,1999],{"class":534,"line":771},[532,2000,596],{"emptyLinePlaceholder":595},[532,2002,2003],{"class":534,"line":783},[532,2004,2005],{"class":538},"\u002F\u002F ── UPSERT ──\n",[532,2007,2008,2010,2012,2014,2016,2018,2020,2022,2024],{"class":534,"line":788},[532,2009,1364],{"class":1363},[532,2011,1339],{"class":549},[532,2013,1650],{"class":560},[532,2015,1653],{"class":549},[532,2017,1656],{"class":560},[532,2019,1659],{"class":549},[532,2021,1662],{"class":549},[532,2023,1665],{"class":1335},[532,2025,1668],{"class":560},[532,2027,2028,2030,2032,2034,2036,2038,2040],{"class":534,"line":794},[532,2029,1673],{"class":549},[532,2031,1676],{"class":1372},[532,2033,1197],{"class":560},[532,2035,557],{"class":549},[532,2037,1683],{"class":553},[532,2039,557],{"class":549},[532,2041,1203],{"class":560},[532,2043,2044,2046,2049,2051,2053,2056,2058,2060,2062,2064,2066,2068,2071,2073,2076,2078,2081,2083,2085,2087,2089,2091],{"class":534,"line":812},[532,2045,1673],{"class":549},[532,2047,2048],{"class":1372},"upsert",[532,2050,1197],{"class":560},[532,2052,1851],{"class":549},[532,2054,2055],{"class":1756}," id",[532,2057,954],{"class":549},[532,2059,1985],{"class":1782},[532,2061,1653],{"class":549},[532,2063,1854],{"class":1756},[532,2065,954],{"class":549},[532,2067,550],{"class":549},[532,2069,2070],{"class":553},"Updated",[532,2072,557],{"class":549},[532,2074,2075],{"class":549}," },",[532,2077,1339],{"class":549},[532,2079,2080],{"class":1756}," onConflict",[532,2082,954],{"class":549},[532,2084,550],{"class":549},[532,2086,1978],{"class":553},[532,2088,557],{"class":549},[532,2090,1345],{"class":549},[532,2092,1203],{"class":560},[532,2094,2095],{"class":534,"line":825},[532,2096,596],{"emptyLinePlaceholder":595},[532,2098,2100],{"class":534,"line":2099},27,[532,2101,2102],{"class":538},"\u002F\u002F ── DELETE ──\n",[532,2104,2106,2108,2110,2112,2114,2116,2118,2120,2122],{"class":534,"line":2105},28,[532,2107,1364],{"class":1363},[532,2109,1339],{"class":549},[532,2111,1650],{"class":560},[532,2113,1653],{"class":549},[532,2115,1656],{"class":560},[532,2117,1659],{"class":549},[532,2119,1662],{"class":549},[532,2121,1665],{"class":1335},[532,2123,1668],{"class":560},[532,2125,2127,2129,2131,2133,2135,2137,2139],{"class":534,"line":2126},29,[532,2128,1673],{"class":549},[532,2130,1676],{"class":1372},[532,2132,1197],{"class":560},[532,2134,557],{"class":549},[532,2136,1683],{"class":553},[532,2138,557],{"class":549},[532,2140,1203],{"class":560},[532,2142,2144,2146,2149],{"class":534,"line":2143},30,[532,2145,1673],{"class":549},[532,2147,2148],{"class":1372},"delete",[532,2150,1996],{"class":560},[532,2152,2154,2156,2158,2160,2162,2164,2166,2168,2170],{"class":534,"line":2153},31,[532,2155,1673],{"class":549},[532,2157,977],{"class":1372},[532,2159,1197],{"class":560},[532,2161,557],{"class":549},[532,2163,1978],{"class":553},[532,2165,557],{"class":549},[532,2167,1653],{"class":549},[532,2169,1985],{"class":1782},[532,2171,1203],{"class":560},[532,2173,2175],{"class":534,"line":2174},32,[532,2176,596],{"emptyLinePlaceholder":595},[532,2178,2180],{"class":534,"line":2179},33,[532,2181,2182],{"class":538},"\u002F\u002F ── Gọi Postgres function (RPC) ──\n",[532,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202],{"class":534,"line":2185},34,[532,2187,1364],{"class":1363},[532,2189,1339],{"class":549},[532,2191,1650],{"class":560},[532,2193,1653],{"class":549},[532,2195,1656],{"class":560},[532,2197,1659],{"class":549},[532,2199,1662],{"class":549},[532,2201,1665],{"class":1335},[532,2203,1668],{"class":560},[532,2205,2207,2209,2212,2214,2216,2219,2221,2223,2225,2228,2230,2232,2235,2237,2239],{"class":534,"line":2206},35,[532,2208,1673],{"class":549},[532,2210,2211],{"class":1372},"rpc",[532,2213,1197],{"class":560},[532,2215,557],{"class":549},[532,2217,2218],{"class":553},"get_user_stats",[532,2220,557],{"class":549},[532,2222,1653],{"class":549},[532,2224,1339],{"class":549},[532,2226,2227],{"class":1756}," user_id",[532,2229,954],{"class":549},[532,2231,550],{"class":549},[532,2233,2234],{"class":553},"uuid-here",[532,2236,557],{"class":549},[532,2238,1345],{"class":549},[532,2240,1203],{"class":560},[532,2242,2244],{"class":534,"line":2243},36,[532,2245,596],{"emptyLinePlaceholder":595},[532,2247,2249],{"class":534,"line":2248},37,[532,2250,2251],{"class":538},"\u002F\u002F ── Auth ──\n",[532,2253,2255,2257,2259,2261,2263,2265,2267,2269,2271,2274,2276,2279,2281,2284,2286],{"class":534,"line":2254},38,[532,2256,1364],{"class":1363},[532,2258,1339],{"class":549},[532,2260,1650],{"class":560},[532,2262,1653],{"class":549},[532,2264,1656],{"class":560},[532,2266,1659],{"class":549},[532,2268,1662],{"class":549},[532,2270,1665],{"class":1335},[532,2272,2273],{"class":560}," supabase",[532,2275,448],{"class":549},[532,2277,2278],{"class":560},"auth",[532,2280,448],{"class":549},[532,2282,2283],{"class":1372},"signUp",[532,2285,1197],{"class":560},[532,2287,2288],{"class":549},"{\n",[532,2290,2292,2295,2297,2299,2302,2304],{"class":534,"line":2291},39,[532,2293,2294],{"class":1756},"  email",[532,2296,954],{"class":549},[532,2298,550],{"class":549},[532,2300,2301],{"class":553},"user@example.com",[532,2303,557],{"class":549},[532,2305,1388],{"class":549},[532,2307,2309,2312,2314,2316,2319],{"class":534,"line":2308},40,[532,2310,2311],{"class":1756},"  password",[532,2313,954],{"class":549},[532,2315,550],{"class":549},[532,2317,2318],{"class":553},"secure-password",[532,2320,589],{"class":549},[532,2322,2324,2326],{"class":534,"line":2323},41,[532,2325,1659],{"class":549},[532,2327,1203],{"class":560},[532,2329,2331],{"class":534,"line":2330},42,[532,2332,596],{"emptyLinePlaceholder":595},[532,2334,2336],{"class":534,"line":2335},43,[532,2337,2338],{"class":538},"\u002F\u002F ── Realtime subscribe ──\n",[532,2340,2342,2344,2347,2349],{"class":534,"line":2341},44,[532,2343,1364],{"class":1363},[532,2345,2346],{"class":560}," channel ",[532,2348,982],{"class":549},[532,2350,1668],{"class":560},[532,2352,2354,2356,2359,2361,2363,2366,2368],{"class":534,"line":2353},45,[532,2355,1673],{"class":549},[532,2357,2358],{"class":1372},"channel",[532,2360,1197],{"class":560},[532,2362,557],{"class":549},[532,2364,2365],{"class":553},"db-changes",[532,2367,557],{"class":549},[532,2369,1203],{"class":560},[532,2371,2373,2375,2378,2380,2382,2385,2387],{"class":534,"line":2372},46,[532,2374,1673],{"class":549},[532,2376,2377],{"class":1372},"on",[532,2379,1197],{"class":560},[532,2381,557],{"class":549},[532,2383,2384],{"class":553},"postgres_changes",[532,2386,557],{"class":549},[532,2388,1388],{"class":549},[532,2390,2392,2395,2398,2400,2402,2405,2407,2409,2412,2414,2416,2419,2421,2423,2426,2428,2430,2433,2435],{"class":534,"line":2391},47,[532,2393,2394],{"class":549},"    {",[532,2396,2397],{"class":1756}," event",[532,2399,954],{"class":549},[532,2401,550],{"class":549},[532,2403,2404],{"class":553},"INSERT",[532,2406,557],{"class":549},[532,2408,1653],{"class":549},[532,2410,2411],{"class":1756}," schema",[532,2413,954],{"class":549},[532,2415,550],{"class":549},[532,2417,2418],{"class":553},"public",[532,2420,557],{"class":549},[532,2422,1653],{"class":549},[532,2424,2425],{"class":1756}," table",[532,2427,954],{"class":549},[532,2429,550],{"class":549},[532,2431,2432],{"class":553},"messages",[532,2434,557],{"class":549},[532,2436,2437],{"class":549}," },\n",[532,2439,2441,2444,2448,2450,2453,2456,2458,2461,2463,2465,2468,2470,2472,2475,2477],{"class":534,"line":2440},48,[532,2442,2443],{"class":549},"    (",[532,2445,2447],{"class":2446},"sHdIc","payload",[532,2449,1310],{"class":549},[532,2451,2452],{"class":1363}," =>",[532,2454,2455],{"class":560}," console",[532,2457,448],{"class":549},[532,2459,2460],{"class":1372},"log",[532,2462,1197],{"class":560},[532,2464,557],{"class":549},[532,2466,2467],{"class":553},"New message:",[532,2469,557],{"class":549},[532,2471,1653],{"class":549},[532,2473,2474],{"class":560}," payload",[532,2476,448],{"class":549},[532,2478,2479],{"class":560},"new)\n",[532,2481,2483],{"class":534,"line":2482},49,[532,2484,2485],{"class":560},"  )\n",[532,2487,2489,2491,2494],{"class":534,"line":2488},50,[532,2490,1673],{"class":549},[532,2492,2493],{"class":1372},"subscribe",[532,2495,1996],{"class":560},[532,2497,2499],{"class":534,"line":2498},51,[532,2500,596],{"emptyLinePlaceholder":595},[532,2502,2504],{"class":534,"line":2503},52,[532,2505,2506],{"class":538},"\u002F\u002F ── Storage ──\n",[532,2508,2510,2512,2514,2516,2518,2520,2522,2524,2526,2528,2530],{"class":534,"line":2509},53,[532,2511,1364],{"class":1363},[532,2513,1339],{"class":549},[532,2515,1650],{"class":560},[532,2517,1653],{"class":549},[532,2519,1656],{"class":560},[532,2521,1659],{"class":549},[532,2523,1662],{"class":549},[532,2525,1665],{"class":1335},[532,2527,2273],{"class":560},[532,2529,448],{"class":549},[532,2531,2532],{"class":560},"storage\n",[532,2534,2536,2538,2540,2542,2544,2547,2549],{"class":534,"line":2535},54,[532,2537,1673],{"class":549},[532,2539,1676],{"class":1372},[532,2541,1197],{"class":560},[532,2543,557],{"class":549},[532,2545,2546],{"class":553},"avatars",[532,2548,557],{"class":549},[532,2550,1203],{"class":560},[532,2552,2554,2556,2559,2561,2563,2566,2568,2570],{"class":534,"line":2553},55,[532,2555,1673],{"class":549},[532,2557,2558],{"class":1372},"upload",[532,2560,1197],{"class":560},[532,2562,557],{"class":549},[532,2564,2565],{"class":553},"public\u002Favatar1.png",[532,2567,557],{"class":549},[532,2569,1653],{"class":549},[532,2571,2572],{"class":560}," file)\n",[532,2574,2576],{"class":534,"line":2575},56,[532,2577,596],{"emptyLinePlaceholder":595},[532,2579,2581],{"class":534,"line":2580},57,[532,2582,2583],{"class":538},"\u002F\u002F ── Edge Functions ──\n",[532,2585,2587,2589,2591,2593,2595,2597,2599,2601,2603,2605,2607,2610,2612,2615,2617,2619,2622,2624,2626],{"class":534,"line":2586},58,[532,2588,1364],{"class":1363},[532,2590,1339],{"class":549},[532,2592,1650],{"class":560},[532,2594,1653],{"class":549},[532,2596,1656],{"class":560},[532,2598,1659],{"class":549},[532,2600,1662],{"class":549},[532,2602,1665],{"class":1335},[532,2604,2273],{"class":560},[532,2606,448],{"class":549},[532,2608,2609],{"class":560},"functions",[532,2611,448],{"class":549},[532,2613,2614],{"class":1372},"invoke",[532,2616,1197],{"class":560},[532,2618,557],{"class":549},[532,2620,2621],{"class":553},"hello-world",[532,2623,557],{"class":549},[532,2625,1653],{"class":549},[532,2627,2628],{"class":549}," {\n",[532,2630,2632,2635,2637,2639,2642,2644,2646,2649,2651],{"class":534,"line":2631},59,[532,2633,2634],{"class":1756},"  body",[532,2636,954],{"class":549},[532,2638,1339],{"class":549},[532,2640,2641],{"class":1756}," name",[532,2643,954],{"class":549},[532,2645,550],{"class":549},[532,2647,2648],{"class":553},"Vinh",[532,2650,557],{"class":549},[532,2652,2653],{"class":549}," }\n",[532,2655,2657,2659],{"class":534,"line":2656},60,[532,2658,1659],{"class":549},[532,2660,1203],{"class":560},[450,2662,2664],{"id":2663},"database-modifiers-đầy-đủ-tất-cả-filters-modifiers","Database Modifiers — đầy đủ tất cả filters & modifiers",[523,2666,2668],{"className":1326,"code":2667,"language":1328,"meta":528,"style":528},"\u002F\u002F ============ FILTERS (toán tử so sánh) ============\n.eq('column', value)            \u002F\u002F equals: column = value\n.neq('column', value)           \u002F\u002F not equal: column != value\n.gt('column', value)            \u002F\u002F greater than: column > value\n.gte('column', value)           \u002F\u002F greater than or equal: column >= value\n.lt('column', value)            \u002F\u002F less than: column \u003C value\n.lte('column', value)           \u002F\u002F less than or equal: column \u003C= value\n\n\u002F\u002F ============ PATTERN MATCHING ============\n.like('column', '%pattern%')    \u002F\u002F SQL LIKE (case-sensitive)\n.ilike('column', '%pattern%')   \u002F\u002F SQL ILIKE (case-insensitive)\n\n\u002F\u002F ============ NULL \u002F BOOLEAN ============\n.is('column', null)             \u002F\u002F IS NULL\n.is('column', true)             \u002F\u002F IS TRUE\n.is('column', false)            \u002F\u002F IS FALSE\n\n\u002F\u002F ============ ARRAY \u002F LIST ============\n.in('column', [1, 2, 3])        \u002F\u002F IN (1, 2, 3)\n.in('column', '(\"a\",\"b\")')      \u002F\u002F IN ('a', 'b') — string array\n.contains('column', { key: 'val' })  \u002F\u002F @> cho JSONB (column chứa object này)\n.contains('column', [1, 2])     \u002F\u002F @> cho array (column chứa tất cả elements)\n.containedBy('column', [1, 2])  \u002F\u002F \u003C@ cho JSONB\u002Farray (column nằm trong array này)\n.overlaps('column', [1, 2])     \u002F\u002F && cho array\u002Frange (có ít nhất 1 phần tử chung)\n.rangeLt('range_col', '[1,5)')      \u002F\u002F \u003C\u003C range strictly left of\n.rangeGt('range_col', '[1,5)')      \u002F\u002F >> range strictly right of\n.rangeGte('range_col', '[1,5)')     \u002F\u002F &> range does not extend to the left of\n.rangeLte('range_col', '[1,5)')     \u002F\u002F &\u003C range does not extend to the right of\n.rangeAdjacent('range_col', '[1,5)') \u002F\u002F -|- range is adjacent\n.rangeUnion('range_col', '[1,5)')   \u002F\u002F + range union (có overlap hoặc liền kề)\n.rangeIntersect('range_col', '[1,5)')\u002F\u002F * range intersection\n\n\u002F\u002F ============ FULL TEXT SEARCH ============\n.textSearch('column', 'search query')            \u002F\u002F full-text search với tsvector\n.textSearch('column', 'query', { config: 'english' })  \u002F\u002F chỉ định language config\n.textSearch('column', 'query', { type: 'plain' })  \u002F\u002F plainto_tsquery (AND giữa các từ)\n.textSearch('column', 'query', { type: 'websearch' }) \u002F\u002F websearch_to_tsquery\n\n\u002F\u002F ============ MATCH (multiple eq) ============\n.match({ col1: 'val1', col2: 'val2' })   \u002F\u002F WHERE col1 = val1 AND col2 = val2\n\n\u002F\u002F ============ OR \u002F NOT \u002F FILTER ============\n.or('col1.eq.val1, col2.gt.val2')         \u002F\u002F OR conditions (comma-separated)\n.or('col1.eq.val1, col2.gt.val2', { foreignTable: 'comments' })  \u002F\u002F OR trên joined table\n.not('column', 'operator', value)         \u002F\u002F NOT condition\n.filter('column', 'operator', value)      \u002F\u002F custom operator (ít dùng hơn)\n\n\u002F\u002F ============ MODIFIERS (xử lý kết quả) ============\n.order('created_at')                              \u002F\u002F ASC mặc định\n.order('created_at', { ascending: false })        \u002F\u002F DESC\n.order('created_at', { ascending: false, nullsFirst: true })  \u002F\u002F NULLS FIRST\n.order('name', { referencedTable: 'profiles' })   \u002F\u002F order by joined table column\n\n.limit(10)                     \u002F\u002F LIMIT 10\n.range(0, 9)                   \u002F\u002F pages 0-9 (0-indexed), header Range\n.range(10, 19)                 \u002F\u002F pages 10-19 (page 2)\n\n.select()                      \u002F\u002F SELECT * (tất cả columns)\n.select('id, name')            \u002F\u002F SELECT id, name\n.select('id, posts(*)')        \u002F\u002F SELECT id + JOIN posts (tất cả columns của posts)\n.select('id, posts(id, title)') \u002F\u002F SELECT id + JOIN posts (chỉ id, title)\n\n.select('*, profiles!inner(*)') \u002F\u002F INNER JOIN — chỉ posts có profiles\n.select('*, profiles!left(*)')  \u002F\u002F LEFT JOIN — tất cả posts kể cả không có profiles\n.select('*, profiles!right(*)') \u002F\u002F RIGHT JOIN\n\n.single()                      \u002F\u002F expect exactly 1 row — throw nếu != 1\n.maybeSingle()                 \u002F\u002F expect 0 hoặc 1 row — throw nếu > 1\n.returns\u003CMyType>()             \u002F\u002F TypeScript type hint\n.throwOnError()                \u002F\u002F throw error thay vì return { error }\n\n\u002F\u002F ============ ADVANCED ============\n.abortSignal(controller.signal)  \u002F\u002F AbortController để cancel request\n.explain()                       \u002F\u002F EXPLAIN query plan (không chạy query)\n.explain({ analyze: true })      \u002F\u002F EXPLAIN ANALYZE\n.explain({ verbose: true, analyze: true })  \u002F\u002F EXPLAIN (ANALYZE, VERBOSE)\n.csv()                           \u002F\u002F trả về dữ liệu dạng CSV string\n.head()                          \u002F\u002F HEAD request — trả về headers, không body (kiểm tra existence)\n.overrideTypes\u003CMyType>()         \u002F\u002F override type casting\n",[445,2669,2670,2675,2698,2720,2741,2762,2783,2804,2808,2813,2842,2870,2874,2879,2904,2928,2952,2956,2961,2999,3028,3066,3096,3127,3157,3187,3215,3244,3272,3300,3328,3356,3360,3365,3394,3440,3485,3529,3533,3538,3582,3586,3591,3612,3649,3680,3711,3715,3720,3740,3772,3812,3850,3854,3871,3891,3912,3916,3928,3948,3968,3989,3994,4015,4036,4057,4062,4075,4089,4110,4124,4129,4135,4154,4168,4193,4226,4239,4253],{"__ignoreMap":528},[532,2671,2672],{"class":534,"line":535},[532,2673,2674],{"class":538},"\u002F\u002F ============ FILTERS (toán tử so sánh) ============\n",[532,2676,2677,2679,2681,2683,2685,2688,2690,2692,2695],{"class":534,"line":542},[532,2678,448],{"class":549},[532,2680,977],{"class":1372},[532,2682,1197],{"class":560},[532,2684,557],{"class":549},[532,2686,2687],{"class":553},"column",[532,2689,557],{"class":549},[532,2691,1653],{"class":549},[532,2693,2694],{"class":560}," value)            ",[532,2696,2697],{"class":538},"\u002F\u002F equals: column = value\n",[532,2699,2700,2702,2704,2706,2708,2710,2712,2714,2717],{"class":534,"line":564},[532,2701,448],{"class":549},[532,2703,992],{"class":1372},[532,2705,1197],{"class":560},[532,2707,557],{"class":549},[532,2709,2687],{"class":553},[532,2711,557],{"class":549},[532,2713,1653],{"class":549},[532,2715,2716],{"class":560}," value)           ",[532,2718,2719],{"class":538},"\u002F\u002F not equal: column != value\n",[532,2721,2722,2724,2726,2728,2730,2732,2734,2736,2738],{"class":534,"line":579},[532,2723,448],{"class":549},[532,2725,1007],{"class":1372},[532,2727,1197],{"class":560},[532,2729,557],{"class":549},[532,2731,2687],{"class":553},[532,2733,557],{"class":549},[532,2735,1653],{"class":549},[532,2737,2694],{"class":560},[532,2739,2740],{"class":538},"\u002F\u002F greater than: column > value\n",[532,2742,2743,2745,2747,2749,2751,2753,2755,2757,2759],{"class":534,"line":592},[532,2744,448],{"class":549},[532,2746,1022],{"class":1372},[532,2748,1197],{"class":560},[532,2750,557],{"class":549},[532,2752,2687],{"class":553},[532,2754,557],{"class":549},[532,2756,1653],{"class":549},[532,2758,2716],{"class":560},[532,2760,2761],{"class":538},"\u002F\u002F greater than or equal: column >= value\n",[532,2763,2764,2766,2768,2770,2772,2774,2776,2778,2780],{"class":534,"line":599},[532,2765,448],{"class":549},[532,2767,1037],{"class":1372},[532,2769,1197],{"class":560},[532,2771,557],{"class":549},[532,2773,2687],{"class":553},[532,2775,557],{"class":549},[532,2777,1653],{"class":549},[532,2779,2694],{"class":560},[532,2781,2782],{"class":538},"\u002F\u002F less than: column \u003C value\n",[532,2784,2785,2787,2789,2791,2793,2795,2797,2799,2801],{"class":534,"line":605},[532,2786,448],{"class":549},[532,2788,1052],{"class":1372},[532,2790,1197],{"class":560},[532,2792,557],{"class":549},[532,2794,2687],{"class":553},[532,2796,557],{"class":549},[532,2798,1653],{"class":549},[532,2800,2716],{"class":560},[532,2802,2803],{"class":538},"\u002F\u002F less than or equal: column \u003C= value\n",[532,2805,2806],{"class":534,"line":619},[532,2807,596],{"emptyLinePlaceholder":595},[532,2809,2810],{"class":534,"line":630},[532,2811,2812],{"class":538},"\u002F\u002F ============ PATTERN MATCHING ============\n",[532,2814,2815,2817,2819,2821,2823,2825,2827,2829,2831,2834,2836,2839],{"class":534,"line":635},[532,2816,448],{"class":549},[532,2818,1067],{"class":1372},[532,2820,1197],{"class":560},[532,2822,557],{"class":549},[532,2824,2687],{"class":553},[532,2826,557],{"class":549},[532,2828,1653],{"class":549},[532,2830,550],{"class":549},[532,2832,2833],{"class":553},"%pattern%",[532,2835,557],{"class":549},[532,2837,2838],{"class":560},")    ",[532,2840,2841],{"class":538},"\u002F\u002F SQL LIKE (case-sensitive)\n",[532,2843,2844,2846,2848,2850,2852,2854,2856,2858,2860,2862,2864,2867],{"class":534,"line":641},[532,2845,448],{"class":549},[532,2847,1082],{"class":1372},[532,2849,1197],{"class":560},[532,2851,557],{"class":549},[532,2853,2687],{"class":553},[532,2855,557],{"class":549},[532,2857,1653],{"class":549},[532,2859,550],{"class":549},[532,2861,2833],{"class":553},[532,2863,557],{"class":549},[532,2865,2866],{"class":560},")   ",[532,2868,2869],{"class":538},"\u002F\u002F SQL ILIKE (case-insensitive)\n",[532,2871,2872],{"class":534,"line":661},[532,2873,596],{"emptyLinePlaceholder":595},[532,2875,2876],{"class":534,"line":674},[532,2877,2878],{"class":538},"\u002F\u002F ============ NULL \u002F BOOLEAN ============\n",[532,2880,2881,2883,2885,2887,2889,2891,2893,2895,2898,2901],{"class":534,"line":688},[532,2882,448],{"class":549},[532,2884,1097],{"class":1372},[532,2886,1197],{"class":560},[532,2888,557],{"class":549},[532,2890,2687],{"class":553},[532,2892,557],{"class":549},[532,2894,1653],{"class":549},[532,2896,2897],{"class":549}," null",[532,2899,2900],{"class":560},")             ",[532,2902,2903],{"class":538},"\u002F\u002F IS NULL\n",[532,2905,2906,2908,2910,2912,2914,2916,2918,2920,2923,2925],{"class":534,"line":702},[532,2907,448],{"class":549},[532,2909,1097],{"class":1372},[532,2911,1197],{"class":560},[532,2913,557],{"class":549},[532,2915,2687],{"class":553},[532,2917,557],{"class":549},[532,2919,1653],{"class":549},[532,2921,2922],{"class":1762}," true",[532,2924,2900],{"class":560},[532,2926,2927],{"class":538},"\u002F\u002F IS TRUE\n",[532,2929,2930,2932,2934,2936,2938,2940,2942,2944,2946,2949],{"class":534,"line":715},[532,2931,448],{"class":549},[532,2933,1097],{"class":1372},[532,2935,1197],{"class":560},[532,2937,557],{"class":549},[532,2939,2687],{"class":553},[532,2941,557],{"class":549},[532,2943,1653],{"class":549},[532,2945,1763],{"class":1762},[532,2947,2948],{"class":560},")            ",[532,2950,2951],{"class":538},"\u002F\u002F IS FALSE\n",[532,2953,2954],{"class":534,"line":720},[532,2955,596],{"emptyLinePlaceholder":595},[532,2957,2958],{"class":534,"line":726},[532,2959,2960],{"class":538},"\u002F\u002F ============ ARRAY \u002F LIST ============\n",[532,2962,2963,2965,2967,2969,2971,2973,2975,2977,2980,2983,2985,2988,2990,2993,2996],{"class":534,"line":745},[532,2964,448],{"class":549},[532,2966,1112],{"class":1372},[532,2968,1197],{"class":560},[532,2970,557],{"class":549},[532,2972,2687],{"class":553},[532,2974,557],{"class":549},[532,2976,1653],{"class":549},[532,2978,2979],{"class":560}," [",[532,2981,2982],{"class":1782},"1",[532,2984,1653],{"class":549},[532,2986,2987],{"class":1782}," 2",[532,2989,1653],{"class":549},[532,2991,2992],{"class":1782}," 3",[532,2994,2995],{"class":560},"])        ",[532,2997,2998],{"class":538},"\u002F\u002F IN (1, 2, 3)\n",[532,3000,3001,3003,3005,3007,3009,3011,3013,3015,3017,3020,3022,3025],{"class":534,"line":758},[532,3002,448],{"class":549},[532,3004,1112],{"class":1372},[532,3006,1197],{"class":560},[532,3008,557],{"class":549},[532,3010,2687],{"class":553},[532,3012,557],{"class":549},[532,3014,1653],{"class":549},[532,3016,550],{"class":549},[532,3018,3019],{"class":553},"(\"a\",\"b\")",[532,3021,557],{"class":549},[532,3023,3024],{"class":560},")      ",[532,3026,3027],{"class":538},"\u002F\u002F IN ('a', 'b') — string array\n",[532,3029,3030,3032,3034,3036,3038,3040,3042,3044,3046,3049,3051,3053,3056,3058,3060,3063],{"class":534,"line":771},[532,3031,448],{"class":549},[532,3033,1127],{"class":1372},[532,3035,1197],{"class":560},[532,3037,557],{"class":549},[532,3039,2687],{"class":553},[532,3041,557],{"class":549},[532,3043,1653],{"class":549},[532,3045,1339],{"class":549},[532,3047,3048],{"class":1756}," key",[532,3050,954],{"class":549},[532,3052,550],{"class":549},[532,3054,3055],{"class":553},"val",[532,3057,557],{"class":549},[532,3059,1345],{"class":549},[532,3061,3062],{"class":560},")  ",[532,3064,3065],{"class":538},"\u002F\u002F @> cho JSONB (column chứa object này)\n",[532,3067,3068,3070,3072,3074,3076,3078,3080,3082,3084,3086,3088,3090,3093],{"class":534,"line":783},[532,3069,448],{"class":549},[532,3071,1127],{"class":1372},[532,3073,1197],{"class":560},[532,3075,557],{"class":549},[532,3077,2687],{"class":553},[532,3079,557],{"class":549},[532,3081,1653],{"class":549},[532,3083,2979],{"class":560},[532,3085,2982],{"class":1782},[532,3087,1653],{"class":549},[532,3089,2987],{"class":1782},[532,3091,3092],{"class":560},"])     ",[532,3094,3095],{"class":538},"\u002F\u002F @> cho array (column chứa tất cả elements)\n",[532,3097,3098,3100,3103,3105,3107,3109,3111,3113,3115,3117,3119,3121,3124],{"class":534,"line":788},[532,3099,448],{"class":549},[532,3101,3102],{"class":1372},"containedBy",[532,3104,1197],{"class":560},[532,3106,557],{"class":549},[532,3108,2687],{"class":553},[532,3110,557],{"class":549},[532,3112,1653],{"class":549},[532,3114,2979],{"class":560},[532,3116,2982],{"class":1782},[532,3118,1653],{"class":549},[532,3120,2987],{"class":1782},[532,3122,3123],{"class":560},"])  ",[532,3125,3126],{"class":538},"\u002F\u002F \u003C@ cho JSONB\u002Farray (column nằm trong array này)\n",[532,3128,3129,3131,3134,3136,3138,3140,3142,3144,3146,3148,3150,3152,3154],{"class":534,"line":794},[532,3130,448],{"class":549},[532,3132,3133],{"class":1372},"overlaps",[532,3135,1197],{"class":560},[532,3137,557],{"class":549},[532,3139,2687],{"class":553},[532,3141,557],{"class":549},[532,3143,1653],{"class":549},[532,3145,2979],{"class":560},[532,3147,2982],{"class":1782},[532,3149,1653],{"class":549},[532,3151,2987],{"class":1782},[532,3153,3092],{"class":560},[532,3155,3156],{"class":538},"\u002F\u002F && cho array\u002Frange (có ít nhất 1 phần tử chung)\n",[532,3158,3159,3161,3164,3166,3168,3171,3173,3175,3177,3180,3182,3184],{"class":534,"line":812},[532,3160,448],{"class":549},[532,3162,3163],{"class":1372},"rangeLt",[532,3165,1197],{"class":560},[532,3167,557],{"class":549},[532,3169,3170],{"class":553},"range_col",[532,3172,557],{"class":549},[532,3174,1653],{"class":549},[532,3176,550],{"class":549},[532,3178,3179],{"class":553},"[1,5)",[532,3181,557],{"class":549},[532,3183,3024],{"class":560},[532,3185,3186],{"class":538},"\u002F\u002F \u003C\u003C range strictly left of\n",[532,3188,3189,3191,3194,3196,3198,3200,3202,3204,3206,3208,3210,3212],{"class":534,"line":825},[532,3190,448],{"class":549},[532,3192,3193],{"class":1372},"rangeGt",[532,3195,1197],{"class":560},[532,3197,557],{"class":549},[532,3199,3170],{"class":553},[532,3201,557],{"class":549},[532,3203,1653],{"class":549},[532,3205,550],{"class":549},[532,3207,3179],{"class":553},[532,3209,557],{"class":549},[532,3211,3024],{"class":560},[532,3213,3214],{"class":538},"\u002F\u002F >> range strictly right of\n",[532,3216,3217,3219,3222,3224,3226,3228,3230,3232,3234,3236,3238,3241],{"class":534,"line":2099},[532,3218,448],{"class":549},[532,3220,3221],{"class":1372},"rangeGte",[532,3223,1197],{"class":560},[532,3225,557],{"class":549},[532,3227,3170],{"class":553},[532,3229,557],{"class":549},[532,3231,1653],{"class":549},[532,3233,550],{"class":549},[532,3235,3179],{"class":553},[532,3237,557],{"class":549},[532,3239,3240],{"class":560},")     ",[532,3242,3243],{"class":538},"\u002F\u002F &> range does not extend to the left of\n",[532,3245,3246,3248,3251,3253,3255,3257,3259,3261,3263,3265,3267,3269],{"class":534,"line":2105},[532,3247,448],{"class":549},[532,3249,3250],{"class":1372},"rangeLte",[532,3252,1197],{"class":560},[532,3254,557],{"class":549},[532,3256,3170],{"class":553},[532,3258,557],{"class":549},[532,3260,1653],{"class":549},[532,3262,550],{"class":549},[532,3264,3179],{"class":553},[532,3266,557],{"class":549},[532,3268,3240],{"class":560},[532,3270,3271],{"class":538},"\u002F\u002F &\u003C range does not extend to the right of\n",[532,3273,3274,3276,3279,3281,3283,3285,3287,3289,3291,3293,3295,3297],{"class":534,"line":2126},[532,3275,448],{"class":549},[532,3277,3278],{"class":1372},"rangeAdjacent",[532,3280,1197],{"class":560},[532,3282,557],{"class":549},[532,3284,3170],{"class":553},[532,3286,557],{"class":549},[532,3288,1653],{"class":549},[532,3290,550],{"class":549},[532,3292,3179],{"class":553},[532,3294,557],{"class":549},[532,3296,1768],{"class":560},[532,3298,3299],{"class":538},"\u002F\u002F -|- range is adjacent\n",[532,3301,3302,3304,3307,3309,3311,3313,3315,3317,3319,3321,3323,3325],{"class":534,"line":2143},[532,3303,448],{"class":549},[532,3305,3306],{"class":1372},"rangeUnion",[532,3308,1197],{"class":560},[532,3310,557],{"class":549},[532,3312,3170],{"class":553},[532,3314,557],{"class":549},[532,3316,1653],{"class":549},[532,3318,550],{"class":549},[532,3320,3179],{"class":553},[532,3322,557],{"class":549},[532,3324,2866],{"class":560},[532,3326,3327],{"class":538},"\u002F\u002F + range union (có overlap hoặc liền kề)\n",[532,3329,3330,3332,3335,3337,3339,3341,3343,3345,3347,3349,3351,3353],{"class":534,"line":2153},[532,3331,448],{"class":549},[532,3333,3334],{"class":1372},"rangeIntersect",[532,3336,1197],{"class":560},[532,3338,557],{"class":549},[532,3340,3170],{"class":553},[532,3342,557],{"class":549},[532,3344,1653],{"class":549},[532,3346,550],{"class":549},[532,3348,3179],{"class":553},[532,3350,557],{"class":549},[532,3352,1310],{"class":560},[532,3354,3355],{"class":538},"\u002F\u002F * range intersection\n",[532,3357,3358],{"class":534,"line":2174},[532,3359,596],{"emptyLinePlaceholder":595},[532,3361,3362],{"class":534,"line":2179},[532,3363,3364],{"class":538},"\u002F\u002F ============ FULL TEXT SEARCH ============\n",[532,3366,3367,3369,3372,3374,3376,3378,3380,3382,3384,3387,3389,3391],{"class":534,"line":2185},[532,3368,448],{"class":549},[532,3370,3371],{"class":1372},"textSearch",[532,3373,1197],{"class":560},[532,3375,557],{"class":549},[532,3377,2687],{"class":553},[532,3379,557],{"class":549},[532,3381,1653],{"class":549},[532,3383,550],{"class":549},[532,3385,3386],{"class":553},"search query",[532,3388,557],{"class":549},[532,3390,2948],{"class":560},[532,3392,3393],{"class":538},"\u002F\u002F full-text search với tsvector\n",[532,3395,3396,3398,3400,3402,3404,3406,3408,3410,3412,3415,3417,3419,3421,3424,3426,3428,3431,3433,3435,3437],{"class":534,"line":2206},[532,3397,448],{"class":549},[532,3399,3371],{"class":1372},[532,3401,1197],{"class":560},[532,3403,557],{"class":549},[532,3405,2687],{"class":553},[532,3407,557],{"class":549},[532,3409,1653],{"class":549},[532,3411,550],{"class":549},[532,3413,3414],{"class":553},"query",[532,3416,557],{"class":549},[532,3418,1653],{"class":549},[532,3420,1339],{"class":549},[532,3422,3423],{"class":1756}," config",[532,3425,954],{"class":549},[532,3427,550],{"class":549},[532,3429,3430],{"class":553},"english",[532,3432,557],{"class":549},[532,3434,1345],{"class":549},[532,3436,3062],{"class":560},[532,3438,3439],{"class":538},"\u002F\u002F chỉ định language config\n",[532,3441,3442,3444,3446,3448,3450,3452,3454,3456,3458,3460,3462,3464,3466,3469,3471,3473,3476,3478,3480,3482],{"class":534,"line":2243},[532,3443,448],{"class":549},[532,3445,3371],{"class":1372},[532,3447,1197],{"class":560},[532,3449,557],{"class":549},[532,3451,2687],{"class":553},[532,3453,557],{"class":549},[532,3455,1653],{"class":549},[532,3457,550],{"class":549},[532,3459,3414],{"class":553},[532,3461,557],{"class":549},[532,3463,1653],{"class":549},[532,3465,1339],{"class":549},[532,3467,3468],{"class":1756}," type",[532,3470,954],{"class":549},[532,3472,550],{"class":549},[532,3474,3475],{"class":553},"plain",[532,3477,557],{"class":549},[532,3479,1345],{"class":549},[532,3481,3062],{"class":560},[532,3483,3484],{"class":538},"\u002F\u002F plainto_tsquery (AND giữa các từ)\n",[532,3486,3487,3489,3491,3493,3495,3497,3499,3501,3503,3505,3507,3509,3511,3513,3515,3517,3520,3522,3524,3526],{"class":534,"line":2248},[532,3488,448],{"class":549},[532,3490,3371],{"class":1372},[532,3492,1197],{"class":560},[532,3494,557],{"class":549},[532,3496,2687],{"class":553},[532,3498,557],{"class":549},[532,3500,1653],{"class":549},[532,3502,550],{"class":549},[532,3504,3414],{"class":553},[532,3506,557],{"class":549},[532,3508,1653],{"class":549},[532,3510,1339],{"class":549},[532,3512,3468],{"class":1756},[532,3514,954],{"class":549},[532,3516,550],{"class":549},[532,3518,3519],{"class":553},"websearch",[532,3521,557],{"class":549},[532,3523,1345],{"class":549},[532,3525,1768],{"class":560},[532,3527,3528],{"class":538},"\u002F\u002F websearch_to_tsquery\n",[532,3530,3531],{"class":534,"line":2254},[532,3532,596],{"emptyLinePlaceholder":595},[532,3534,3535],{"class":534,"line":2291},[532,3536,3537],{"class":538},"\u002F\u002F ============ MATCH (multiple eq) ============\n",[532,3539,3540,3542,3545,3547,3549,3552,3554,3556,3559,3561,3563,3566,3568,3570,3573,3575,3577,3579],{"class":534,"line":2308},[532,3541,448],{"class":549},[532,3543,3544],{"class":1372},"match",[532,3546,1197],{"class":560},[532,3548,1851],{"class":549},[532,3550,3551],{"class":1756}," col1",[532,3553,954],{"class":549},[532,3555,550],{"class":549},[532,3557,3558],{"class":553},"val1",[532,3560,557],{"class":549},[532,3562,1653],{"class":549},[532,3564,3565],{"class":1756}," col2",[532,3567,954],{"class":549},[532,3569,550],{"class":549},[532,3571,3572],{"class":553},"val2",[532,3574,557],{"class":549},[532,3576,1345],{"class":549},[532,3578,2866],{"class":560},[532,3580,3581],{"class":538},"\u002F\u002F WHERE col1 = val1 AND col2 = val2\n",[532,3583,3584],{"class":534,"line":2323},[532,3585,596],{"emptyLinePlaceholder":595},[532,3587,3588],{"class":534,"line":2330},[532,3589,3590],{"class":538},"\u002F\u002F ============ OR \u002F NOT \u002F FILTER ============\n",[532,3592,3593,3595,3597,3599,3601,3604,3606,3609],{"class":534,"line":2335},[532,3594,448],{"class":549},[532,3596,1142],{"class":1372},[532,3598,1197],{"class":560},[532,3600,557],{"class":549},[532,3602,3603],{"class":553},"col1.eq.val1, col2.gt.val2",[532,3605,557],{"class":549},[532,3607,3608],{"class":560},")         ",[532,3610,3611],{"class":538},"\u002F\u002F OR conditions (comma-separated)\n",[532,3613,3614,3616,3618,3620,3622,3624,3626,3628,3630,3633,3635,3637,3640,3642,3644,3646],{"class":534,"line":2341},[532,3615,448],{"class":549},[532,3617,1142],{"class":1372},[532,3619,1197],{"class":560},[532,3621,557],{"class":549},[532,3623,3603],{"class":553},[532,3625,557],{"class":549},[532,3627,1653],{"class":549},[532,3629,1339],{"class":549},[532,3631,3632],{"class":1756}," foreignTable",[532,3634,954],{"class":549},[532,3636,550],{"class":549},[532,3638,3639],{"class":553},"comments",[532,3641,557],{"class":549},[532,3643,1345],{"class":549},[532,3645,3062],{"class":560},[532,3647,3648],{"class":538},"\u002F\u002F OR trên joined table\n",[532,3650,3651,3653,3655,3657,3659,3661,3663,3665,3667,3670,3672,3674,3677],{"class":534,"line":2353},[532,3652,448],{"class":549},[532,3654,1157],{"class":1372},[532,3656,1197],{"class":560},[532,3658,557],{"class":549},[532,3660,2687],{"class":553},[532,3662,557],{"class":549},[532,3664,1653],{"class":549},[532,3666,550],{"class":549},[532,3668,3669],{"class":553},"operator",[532,3671,557],{"class":549},[532,3673,1653],{"class":549},[532,3675,3676],{"class":560}," value)         ",[532,3678,3679],{"class":538},"\u002F\u002F NOT condition\n",[532,3681,3682,3684,3687,3689,3691,3693,3695,3697,3699,3701,3703,3705,3708],{"class":534,"line":2372},[532,3683,448],{"class":549},[532,3685,3686],{"class":1372},"filter",[532,3688,1197],{"class":560},[532,3690,557],{"class":549},[532,3692,2687],{"class":553},[532,3694,557],{"class":549},[532,3696,1653],{"class":549},[532,3698,550],{"class":549},[532,3700,3669],{"class":553},[532,3702,557],{"class":549},[532,3704,1653],{"class":549},[532,3706,3707],{"class":560}," value)      ",[532,3709,3710],{"class":538},"\u002F\u002F custom operator (ít dùng hơn)\n",[532,3712,3713],{"class":534,"line":2391},[532,3714,596],{"emptyLinePlaceholder":595},[532,3716,3717],{"class":534,"line":2440},[532,3718,3719],{"class":538},"\u002F\u002F ============ MODIFIERS (xử lý kết quả) ============\n",[532,3721,3722,3724,3726,3728,3730,3732,3734,3737],{"class":534,"line":2482},[532,3723,448],{"class":549},[532,3725,885],{"class":1372},[532,3727,1197],{"class":560},[532,3729,557],{"class":549},[532,3731,1747],{"class":553},[532,3733,557],{"class":549},[532,3735,3736],{"class":560},")                              ",[532,3738,3739],{"class":538},"\u002F\u002F ASC mặc định\n",[532,3741,3742,3744,3746,3748,3750,3752,3754,3756,3758,3760,3762,3764,3766,3769],{"class":534,"line":2488},[532,3743,448],{"class":549},[532,3745,885],{"class":1372},[532,3747,1197],{"class":560},[532,3749,557],{"class":549},[532,3751,1747],{"class":553},[532,3753,557],{"class":549},[532,3755,1653],{"class":549},[532,3757,1339],{"class":549},[532,3759,1757],{"class":1756},[532,3761,954],{"class":549},[532,3763,1763],{"class":1762},[532,3765,1345],{"class":549},[532,3767,3768],{"class":560},")        ",[532,3770,3771],{"class":538},"\u002F\u002F DESC\n",[532,3773,3774,3776,3778,3780,3782,3784,3786,3788,3790,3792,3794,3796,3798,3801,3803,3805,3807,3809],{"class":534,"line":2498},[532,3775,448],{"class":549},[532,3777,885],{"class":1372},[532,3779,1197],{"class":560},[532,3781,557],{"class":549},[532,3783,1747],{"class":553},[532,3785,557],{"class":549},[532,3787,1653],{"class":549},[532,3789,1339],{"class":549},[532,3791,1757],{"class":1756},[532,3793,954],{"class":549},[532,3795,1763],{"class":1762},[532,3797,1653],{"class":549},[532,3799,3800],{"class":1756}," nullsFirst",[532,3802,954],{"class":549},[532,3804,2922],{"class":1762},[532,3806,1345],{"class":549},[532,3808,3062],{"class":560},[532,3810,3811],{"class":538},"\u002F\u002F NULLS FIRST\n",[532,3813,3814,3816,3818,3820,3822,3825,3827,3829,3831,3834,3836,3838,3841,3843,3845,3847],{"class":534,"line":2503},[532,3815,448],{"class":549},[532,3817,885],{"class":1372},[532,3819,1197],{"class":560},[532,3821,557],{"class":549},[532,3823,3824],{"class":553},"name",[532,3826,557],{"class":549},[532,3828,1653],{"class":549},[532,3830,1339],{"class":549},[532,3832,3833],{"class":1756}," referencedTable",[532,3835,954],{"class":549},[532,3837,550],{"class":549},[532,3839,3840],{"class":553},"profiles",[532,3842,557],{"class":549},[532,3844,1345],{"class":549},[532,3846,2866],{"class":560},[532,3848,3849],{"class":538},"\u002F\u002F order by joined table column\n",[532,3851,3852],{"class":534,"line":2509},[532,3853,596],{"emptyLinePlaceholder":595},[532,3855,3856,3858,3860,3862,3865,3868],{"class":534,"line":2535},[532,3857,448],{"class":549},[532,3859,903],{"class":1372},[532,3861,1197],{"class":560},[532,3863,3864],{"class":1782},"10",[532,3866,3867],{"class":560},")                     ",[532,3869,3870],{"class":538},"\u002F\u002F LIMIT 10\n",[532,3872,3873,3875,3877,3879,3881,3883,3885,3888],{"class":534,"line":2553},[532,3874,448],{"class":549},[532,3876,933],{"class":1372},[532,3878,1197],{"class":560},[532,3880,1783],{"class":1782},[532,3882,1653],{"class":549},[532,3884,1788],{"class":1782},[532,3886,3887],{"class":560},")                   ",[532,3889,3890],{"class":538},"\u002F\u002F pages 0-9 (0-indexed), header Range\n",[532,3892,3893,3895,3897,3899,3901,3903,3906,3909],{"class":534,"line":2575},[532,3894,448],{"class":549},[532,3896,933],{"class":1372},[532,3898,1197],{"class":560},[532,3900,3864],{"class":1782},[532,3902,1653],{"class":549},[532,3904,3905],{"class":1782}," 19",[532,3907,3908],{"class":560},")                 ",[532,3910,3911],{"class":538},"\u002F\u002F pages 10-19 (page 2)\n",[532,3913,3914],{"class":534,"line":2580},[532,3915,596],{"emptyLinePlaceholder":595},[532,3917,3918,3920,3922,3925],{"class":534,"line":2586},[532,3919,448],{"class":549},[532,3921,870],{"class":1372},[532,3923,3924],{"class":560},"()                      ",[532,3926,3927],{"class":538},"\u002F\u002F SELECT * (tất cả columns)\n",[532,3929,3930,3932,3934,3936,3938,3941,3943,3945],{"class":534,"line":2631},[532,3931,448],{"class":549},[532,3933,870],{"class":1372},[532,3935,1197],{"class":560},[532,3937,557],{"class":549},[532,3939,3940],{"class":553},"id, name",[532,3942,557],{"class":549},[532,3944,2948],{"class":560},[532,3946,3947],{"class":538},"\u002F\u002F SELECT id, name\n",[532,3949,3950,3952,3954,3956,3958,3961,3963,3965],{"class":534,"line":2656},[532,3951,448],{"class":549},[532,3953,870],{"class":1372},[532,3955,1197],{"class":560},[532,3957,557],{"class":549},[532,3959,3960],{"class":553},"id, posts(*)",[532,3962,557],{"class":549},[532,3964,3768],{"class":560},[532,3966,3967],{"class":538},"\u002F\u002F SELECT id + JOIN posts (tất cả columns của posts)\n",[532,3969,3971,3973,3975,3977,3979,3982,3984,3986],{"class":534,"line":3970},61,[532,3972,448],{"class":549},[532,3974,870],{"class":1372},[532,3976,1197],{"class":560},[532,3978,557],{"class":549},[532,3980,3981],{"class":553},"id, posts(id, title)",[532,3983,557],{"class":549},[532,3985,1768],{"class":560},[532,3987,3988],{"class":538},"\u002F\u002F SELECT id + JOIN posts (chỉ id, title)\n",[532,3990,3992],{"class":534,"line":3991},62,[532,3993,596],{"emptyLinePlaceholder":595},[532,3995,3997,3999,4001,4003,4005,4008,4010,4012],{"class":534,"line":3996},63,[532,3998,448],{"class":549},[532,4000,870],{"class":1372},[532,4002,1197],{"class":560},[532,4004,557],{"class":549},[532,4006,4007],{"class":553},"*, profiles!inner(*)",[532,4009,557],{"class":549},[532,4011,1768],{"class":560},[532,4013,4014],{"class":538},"\u002F\u002F INNER JOIN — chỉ posts có profiles\n",[532,4016,4018,4020,4022,4024,4026,4029,4031,4033],{"class":534,"line":4017},64,[532,4019,448],{"class":549},[532,4021,870],{"class":1372},[532,4023,1197],{"class":560},[532,4025,557],{"class":549},[532,4027,4028],{"class":553},"*, profiles!left(*)",[532,4030,557],{"class":549},[532,4032,3062],{"class":560},[532,4034,4035],{"class":538},"\u002F\u002F LEFT JOIN — tất cả posts kể cả không có profiles\n",[532,4037,4039,4041,4043,4045,4047,4050,4052,4054],{"class":534,"line":4038},65,[532,4040,448],{"class":549},[532,4042,870],{"class":1372},[532,4044,1197],{"class":560},[532,4046,557],{"class":549},[532,4048,4049],{"class":553},"*, profiles!right(*)",[532,4051,557],{"class":549},[532,4053,1768],{"class":560},[532,4055,4056],{"class":538},"\u002F\u002F RIGHT JOIN\n",[532,4058,4060],{"class":534,"line":4059},66,[532,4061,596],{"emptyLinePlaceholder":595},[532,4063,4065,4067,4070,4072],{"class":534,"line":4064},67,[532,4066,448],{"class":549},[532,4068,4069],{"class":1372},"single",[532,4071,3924],{"class":560},[532,4073,4074],{"class":538},"\u002F\u002F expect exactly 1 row — throw nếu != 1\n",[532,4076,4078,4080,4083,4086],{"class":534,"line":4077},68,[532,4079,448],{"class":549},[532,4081,4082],{"class":1372},"maybeSingle",[532,4084,4085],{"class":560},"()                 ",[532,4087,4088],{"class":538},"\u002F\u002F expect 0 hoặc 1 row — throw nếu > 1\n",[532,4090,4092,4094,4097,4099,4102,4104,4107],{"class":534,"line":4091},69,[532,4093,448],{"class":549},[532,4095,4096],{"class":1372},"returns",[532,4098,1042],{"class":549},[532,4100,4101],{"class":545},"MyType",[532,4103,1012],{"class":549},[532,4105,4106],{"class":560},"()             ",[532,4108,4109],{"class":538},"\u002F\u002F TypeScript type hint\n",[532,4111,4113,4115,4118,4121],{"class":534,"line":4112},70,[532,4114,448],{"class":549},[532,4116,4117],{"class":1372},"throwOnError",[532,4119,4120],{"class":560},"()                ",[532,4122,4123],{"class":538},"\u002F\u002F throw error thay vì return { error }\n",[532,4125,4127],{"class":534,"line":4126},71,[532,4128,596],{"emptyLinePlaceholder":595},[532,4130,4132],{"class":534,"line":4131},72,[532,4133,4134],{"class":538},"\u002F\u002F ============ ADVANCED ============\n",[532,4136,4138,4140,4143,4146,4148,4151],{"class":534,"line":4137},73,[532,4139,448],{"class":549},[532,4141,4142],{"class":1372},"abortSignal",[532,4144,4145],{"class":560},"(controller",[532,4147,448],{"class":549},[532,4149,4150],{"class":560},"signal)  ",[532,4152,4153],{"class":538},"\u002F\u002F AbortController để cancel request\n",[532,4155,4157,4159,4162,4165],{"class":534,"line":4156},74,[532,4158,448],{"class":549},[532,4160,4161],{"class":1372},"explain",[532,4163,4164],{"class":560},"()                       ",[532,4166,4167],{"class":538},"\u002F\u002F EXPLAIN query plan (không chạy query)\n",[532,4169,4171,4173,4175,4177,4179,4182,4184,4186,4188,4190],{"class":534,"line":4170},75,[532,4172,448],{"class":549},[532,4174,4161],{"class":1372},[532,4176,1197],{"class":560},[532,4178,1851],{"class":549},[532,4180,4181],{"class":1756}," analyze",[532,4183,954],{"class":549},[532,4185,2922],{"class":1762},[532,4187,1345],{"class":549},[532,4189,3024],{"class":560},[532,4191,4192],{"class":538},"\u002F\u002F EXPLAIN ANALYZE\n",[532,4194,4196,4198,4200,4202,4204,4207,4209,4211,4213,4215,4217,4219,4221,4223],{"class":534,"line":4195},76,[532,4197,448],{"class":549},[532,4199,4161],{"class":1372},[532,4201,1197],{"class":560},[532,4203,1851],{"class":549},[532,4205,4206],{"class":1756}," verbose",[532,4208,954],{"class":549},[532,4210,2922],{"class":1762},[532,4212,1653],{"class":549},[532,4214,4181],{"class":1756},[532,4216,954],{"class":549},[532,4218,2922],{"class":1762},[532,4220,1345],{"class":549},[532,4222,3062],{"class":560},[532,4224,4225],{"class":538},"\u002F\u002F EXPLAIN (ANALYZE, VERBOSE)\n",[532,4227,4229,4231,4234,4236],{"class":534,"line":4228},77,[532,4230,448],{"class":549},[532,4232,4233],{"class":1372},"csv",[532,4235,1890],{"class":560},[532,4237,4238],{"class":538},"\u002F\u002F trả về dữ liệu dạng CSV string\n",[532,4240,4242,4244,4247,4250],{"class":534,"line":4241},78,[532,4243,448],{"class":549},[532,4245,4246],{"class":1372},"head",[532,4248,4249],{"class":560},"()                          ",[532,4251,4252],{"class":538},"\u002F\u002F HEAD request — trả về headers, không body (kiểm tra existence)\n",[532,4254,4256,4258,4261,4263,4265,4267,4270],{"class":534,"line":4255},79,[532,4257,448],{"class":549},[532,4259,4260],{"class":1372},"overrideTypes",[532,4262,1042],{"class":549},[532,4264,4101],{"class":545},[532,4266,1012],{"class":549},[532,4268,4269],{"class":560},"()         ",[532,4271,4272],{"class":538},"\u002F\u002F override type casting\n",[450,4274,4276],{"id":4275},"auth-methods-đầy-đủ-tất-cả-api","Auth Methods — đầy đủ tất cả API",[523,4278,4280],{"className":1326,"code":4279,"language":1328,"meta":528,"style":528},"\u002F\u002F ============ SIGN UP & SIGN IN ============\n\n\u002F\u002F Sign up với email + password\nconst { data, error } = await supabase.auth.signUp({\n  email: 'user@example.com',\n  password: 'secure-password',\n  options: {\n    data: { full_name: 'Nguyen Van A', role: 'member' },  \u002F\u002F user metadata\n    emailRedirectTo: 'https:\u002F\u002Fmyapp.com\u002Fwelcome',          \u002F\u002F redirect sau khi verify email\n  }\n})\n\n\u002F\u002F Sign in với email + password\nconst { data, error } = await supabase.auth.signInWithPassword({\n  email: 'user@example.com',\n  password: 'secure-password',\n})\n\n\u002F\u002F Sign in với Magic Link (passwordless — gửi link qua email)\nconst { data, error } = await supabase.auth.signInWithOtp({\n  email: 'user@example.com',\n  options: {\n    emailRedirectTo: 'https:\u002F\u002Fmyapp.com\u002Fauth\u002Fcallback',\n    shouldCreateUser: true,   \u002F\u002F tự động tạo user nếu chưa có\n  }\n})\n\n\u002F\u002F Sign in với SMS OTP\nconst { data, error } = await supabase.auth.signInWithOtp({\n  phone: '+84912345678',\n  options: { channel: 'sms' }\n})\n\n\u002F\u002F Sign in với WhatsApp OTP\nconst { data, error } = await supabase.auth.signInWithOtp({\n  phone: '+84912345678',\n  options: { channel: 'whatsapp' }\n})\n\n\u002F\u002F Sign in với OAuth providers\nconst { data, error } = await supabase.auth.signInWithOAuth({\n  provider: 'google',\n  options: {\n    redirectTo: 'https:\u002F\u002Fmyapp.com\u002Fauth\u002Fcallback',\n    queryParams: { access_type: 'offline', prompt: 'consent' },\n    scopes: 'profile email',   \u002F\u002F additional scopes\n  }\n})\n\n\u002F\u002F OAuth providers hỗ trợ:\n\u002F\u002F 'google', 'github', 'gitlab', 'bitbucket', 'discord',\n\u002F\u002F 'twitter', 'apple', 'facebook', 'figma', 'kakao',\n\u002F\u002F 'keycloak', 'linkedin', 'linkedin_oidc', 'notion',\n\u002F\u002F 'slack', 'slack_oidc', 'spotify', 'twitch',\n\u002F\u002F 'workos', 'zoom', 'azure', 'fly' (tùy project config)\n\n\u002F\u002F Sign in với SSO (Enterprise — SAML 2.0)\nconst { data, error } = await supabase.auth.signInWithSSO({\n  domain: 'company.com',\n  options: {\n    redirectTo: 'https:\u002F\u002Fmyapp.com\u002Fauth\u002Fcallback',\n    captchaToken: '...',  \u002F\u002F nếu bắt buộc CAPTCHA\n  }\n})\n\n\u002F\u002F Anonymous sign-in (user tạm thời, có thể upgrade lên full account)\nconst { data, error } = await supabase.auth.signInAnonymously()\n\n\u002F\u002F Sign in với token từ 3rd party (Apple Game Center, Sign in with Apple native, etc.)\nconst { data, error } = await supabase.auth.signInWithIdToken({\n  provider: 'apple',\n  token: 'id-token-from-apple',\n  access_token: '...',  \u002F\u002F optional\n  nonce: '...',         \u002F\u002F optional\n})\n\n\u002F\u002F ============ SESSION MANAGEMENT ============\n\n\u002F\u002F Lấy session hiện tại (từ localStorage ở browser)\nconst { data: { session }, error } = await supabase.auth.getSession()\n\n\u002F\u002F Lấy user hiện tại từ JWT trong session\nconst { data: { user }, error } = await supabase.auth.getUser()\n\n\u002F\u002F Refresh session (dùng refresh token để lấy access token mới)\nconst { data, error } = await supabase.auth.refreshSession()\nconst { session, user } = data\n\n\u002F\u002F Set session manually (ví dụ: sau khi nhận token từ backend)\nconst { data, error } = await supabase.auth.setSession({\n  access_token: 'eyJ...',\n  refresh_token: '...',\n})\n\n\u002F\u002F Lắng nghe thay đổi trạng thái auth\nconst { data: { subscription } } = supabase.auth.onAuthStateChange(\n  (event, session) => {\n    console.log('Auth event:', event)   \u002F\u002F SIGNED_IN, SIGNED_OUT, USER_UPDATED,\n                                         \u002F\u002F USER_DELETED, PASSWORD_RECOVERY,\n                                         \u002F\u002F TOKEN_REFRESHED, MFA_CHALLENGE_VERIFIED\n    console.log('Session:', session)\n  }\n)\n\u002F\u002F subscription.unsubscribe() — để cleanup\n\n\u002F\u002F Sign out\nconst { error } = await supabase.auth.signOut()\n\u002F\u002F Sign out globally (tất cả devices)\nconst { error } = await supabase.auth.signOut({ scope: 'global' })\n\u002F\u002F Sign out chỉ trên device hiện tại\nconst { error } = await supabase.auth.signOut({ scope: 'local' })\n\n\u002F\u002F ============ USER MANAGEMENT ============\n\n\u002F\u002F Update user profile (email, password, metadata)\nconst { data, error } = await supabase.auth.updateUser({\n  email: 'new-email@example.com',\n  password: 'new-password',\n  data: { full_name: 'New Name', avatar_url: 'https:\u002F\u002F...' },\n})\n\n\u002F\u002F Gửi email reset password\nconst { data, error } = await supabase.auth.resetPasswordForEmail(\n  'user@example.com',\n  { redirectTo: 'https:\u002F\u002Fmyapp.com\u002Freset-password' }\n)\n\n\u002F\u002F Reauthenticate (yêu cầu đăng nhập lại trước khi làm thao tác nhạy cảm)\nconst { data, error } = await supabase.auth.reauthenticate()\n\n\u002F\u002F Resend confirmation email \u002F OTP\nconst { data, error } = await supabase.auth.resend({\n  type: 'signup',      \u002F\u002F 'signup' | 'email_change' | 'sms' | 'phone_change'\n  email: 'user@example.com',\n  options: {\n    emailRedirectTo: 'https:\u002F\u002Fmyapp.com\u002Fconfirm'\n  }\n})\n\n\u002F\u002F Verify OTP (email hoặc phone)\nconst { data, error } = await supabase.auth.verifyOtp({\n  email: 'user@example.com',\n  token: '123456',\n  type: 'signup',       \u002F\u002F 'signup' | 'magiclink' | 'recovery' | 'invite'\n                        \u002F\u002F 'email_change' | 'sms' | 'phone_change'\n})\n\n\u002F\u002F Exchange auth code for session (PKCE flow)\nconst { data, error } = await supabase.auth.exchangeCodeForSession('auth-code-here')\n\n\u002F\u002F Link identity (link Google account vào account đang login)\nconst { data, error } = await supabase.auth.linkIdentity({\n  provider: 'google',\n})\n\n\u002F\u002F Unlink identity\nconst { data, error } = await supabase.auth.unlinkIdentity({\n  identityId: 'identity-uuid'\n})\n\n\u002F\u002F Get user identities (linked OAuth accounts)\nconst { data } = await supabase.auth.getUserIdentities()\n\n\u002F\u002F ============ MFA (Multi-Factor Authentication - BẬT THEO PROJECT) ============\n\n\u002F\u002F Enroll MFA factor (TOTP - Time-based One-Time Password)\nconst { data, error } = await supabase.auth.mfa.enroll({\n  factorType: 'totp',\n  issuer: 'My App',     \u002F\u002F tên hiển thị trong authenticator app\n  friendlyName: 'user@example.com',\n})\n\u002F\u002F data.totp.qr_code — base64 QR code image\n\u002F\u002F data.totp.secret — secret key\n\u002F\u002F data.totp.uri — otpauth:\u002F\u002F URI\n\n\u002F\u002F Challenge — tạo challenge để verify\nconst { data, error } = await supabase.auth.mfa.challenge({\n  factorId: 'factor-uuid-from-enroll',\n})\n\u002F\u002F data.id — challenge ID, dùng trong verify\n\n\u002F\u002F Verify — xác nhận TOTP code\nconst { data, error } = await supabase.auth.mfa.verify({\n  factorId: 'factor-uuid',\n  challengeId: 'challenge-id',\n  code: '123456',\n})\n\n\u002F\u002F Unenroll — gỡ bỏ MFA\nconst { data, error } = await supabase.auth.mfa.unenroll({\n  factorId: 'factor-uuid',\n})\n\n\u002F\u002F List enrolled factors\nconst { data } = await supabase.auth.mfa.listFactors()\n\u002F\u002F data.all — tất cả factors\n\u002F\u002F data.totp — chỉ TOTP factors\n\u002F\u002F data.phone — chỉ phone factors (nếu bật)\n\n\u002F\u002F Get authenticator assurance level (aal)\nconst { data } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel()\n\u002F\u002F data.currentLevel — 'aal1' | 'aal2'\n\u002F\u002F data.nextLevel — level tiếp theo cần đạt\n\u002F\u002F data.currentAuthenticationMethods — array of methods đã dùng\n\n\u002F\u002F ============ AUTH ADMIN (service_role key required) ============\n\u002F\u002F Dùng supabaseAdmin client với SERVICE_ROLE_KEY\n\n\u002F\u002F Tạo user mới (không cần email verification)\nconst { data, error } = await supabaseAdmin.auth.admin.createUser({\n  email: 'newuser@example.com',\n  password: 'password123',\n  email_confirm: true,          \u002F\u002F auto-confirm email\n  phone: '+84912345678',\n  phone_confirm: true,          \u002F\u002F auto-confirm phone\n  user_metadata: { full_name: 'Admin Created User' },\n  app_metadata: { role: 'admin' },\n})\n\n\u002F\u002F Xóa user\nconst { data, error } = await supabaseAdmin.auth.admin.deleteUser('user-uuid')\n\u002F\u002F Xóa user + xóa luôn database identity\nconst { data, error } = await supabaseAdmin.auth.admin.deleteUser('user-uuid', true)\n\n\u002F\u002F Update user by ID\nconst { data, error } = await supabaseAdmin.auth.admin.updateUserById(\n  'user-uuid',\n  {\n    email: 'updated@example.com',\n    password: 'new-password',\n    email_confirm: true,\n    user_metadata: { verified: true },\n    app_metadata: { plan: 'pro' },\n    ban_duration: null,          \u002F\u002F unban user: null = không ban\n                                 \u002F\u002F '24h' = ban 24 giờ\n                                 \u002F\u002F 'none' = ban vĩnh viễn\n  }\n)\n\n\u002F\u002F Get user by ID\nconst { data, error } = await supabaseAdmin.auth.admin.getUserById('user-uuid')\n\n\u002F\u002F List users (có phân trang)\nconst { data, error } = await supabaseAdmin.auth.admin.listUsers({\n  page: 1,\n  perPage: 50,\n})\n\n\u002F\u002F Invite user by email\nconst { data, error } = await supabaseAdmin.auth.admin.inviteUserByEmail(\n  'newuser@example.com',\n  { redirectTo: 'https:\u002F\u002Fmyapp.com\u002Fwelcome' }\n)\n\n\u002F\u002F Generate link (signup confirmation, password reset, email change, magic link)\nconst { data, error } = await supabaseAdmin.auth.admin.generateLink({\n  type: 'signup',              \u002F\u002F 'signup' | 'magiclink' | 'recovery' | 'email_change_current'\n                                \u002F\u002F | 'email_change_new' | 'invite'\n  email: 'user@example.com',\n  password: 'optional-password', \u002F\u002F chỉ cần cho signup\n  newEmail: 'new@example.com',  \u002F\u002F chỉ cần cho email_change_new\n  redirectTo: 'https:\u002F\u002Fmyapp.com\u002Fcallback',\n  data: { custom_key: 'value' }, \u002F\u002F metadata\n})\n\n\u002F\u002F Delete factor (MFA) for a user\nconst { data, error } = await supabaseAdmin.auth.admin.deleteFactor(\n  'user-uuid',\n  'factor-uuid'\n)\n\n\u002F\u002F Get factors for a user\nconst { data, error } = await supabaseAdmin.auth.admin.listFactors('user-uuid')\n\n\u002F\u002F Send OTP code (SMS)\nconst { data, error } = await supabaseAdmin.auth.admin.sendOtpCode({\n  phone: '+84912345678',\n  type: 'sms'\n})\n",[445,4281,4282,4287,4291,4296,4328,4342,4356,4365,4405,4424,4429,4435,4439,4444,4477,4491,4505,4511,4515,4520,4553,4567,4575,4590,4604,4608,4614,4618,4623,4655,4671,4693,4699,4703,4708,4740,4754,4775,4781,4785,4790,4823,4839,4847,4862,4899,4918,4922,4928,4932,4937,4942,4947,4952,4957,4962,4966,4971,5004,5020,5028,5042,5061,5065,5071,5075,5080,5111,5115,5120,5153,5168,5184,5202,5220,5226,5230,5235,5239,5244,5284,5289,5295,5334,5339,5345,5377,5398,5403,5409,5443,5459,5475,5482,5487,5493,5528,5547,5575,5581,5587,5611,5616,5621,5627,5632,5638,5666,5672,5717,5723,5767,5772,5778,5783,5789,5823,5839,5855,5892,5899,5904,5910,5942,5953,5973,5978,5983,5989,6021,6026,6032,6066,6086,6101,6110,6124,6129,6136,6141,6147,6181,6196,6212,6230,6236,6243,6248,6254,6295,6300,6306,6340,6355,6362,6367,6373,6407,6422,6429,6434,6440,6469,6474,6480,6485,6491,6530,6547,6567,6583,6590,6596,6602,6608,6613,6619,6657,6674,6681,6687,6692,6698,6736,6752,6769,6785,6792,6797,6803,6841,6856,6863,6868,6874,6906,6912,6918,6924,6929,6935,6967,6973,6979,6985,6990,6996,7002,7007,7013,7053,7069,7085,7100,7115,7130,7153,7175,7182,7187,7193,7238,7244,7291,7296,7302,7338,7349,7355,7372,7388,7400,7419,7443,7457,7463,7469,7474,7479,7484,7490,7534,7539,7545,7583,7595,7608,7615,7620,7626,7662,7673,7690,7695,7700,7706,7744,7762,7768,7783,7802,7822,7839,7865,7872,7877,7883,7919,7930,7939,7944,7949,7955,7998,8003,8009,8047,8062,8075],{"__ignoreMap":528},[532,4283,4284],{"class":534,"line":535},[532,4285,4286],{"class":538},"\u002F\u002F ============ SIGN UP & SIGN IN ============\n",[532,4288,4289],{"class":534,"line":542},[532,4290,596],{"emptyLinePlaceholder":595},[532,4292,4293],{"class":534,"line":564},[532,4294,4295],{"class":538},"\u002F\u002F Sign up với email + password\n",[532,4297,4298,4300,4302,4304,4306,4308,4310,4312,4314,4316,4318,4320,4322,4324,4326],{"class":534,"line":579},[532,4299,1364],{"class":1363},[532,4301,1339],{"class":549},[532,4303,1650],{"class":560},[532,4305,1653],{"class":549},[532,4307,1656],{"class":560},[532,4309,1659],{"class":549},[532,4311,1662],{"class":549},[532,4313,1665],{"class":1335},[532,4315,2273],{"class":560},[532,4317,448],{"class":549},[532,4319,2278],{"class":560},[532,4321,448],{"class":549},[532,4323,2283],{"class":1372},[532,4325,1197],{"class":560},[532,4327,2288],{"class":549},[532,4329,4330,4332,4334,4336,4338,4340],{"class":534,"line":592},[532,4331,2294],{"class":1756},[532,4333,954],{"class":549},[532,4335,550],{"class":549},[532,4337,2301],{"class":553},[532,4339,557],{"class":549},[532,4341,1388],{"class":549},[532,4343,4344,4346,4348,4350,4352,4354],{"class":534,"line":599},[532,4345,2311],{"class":1756},[532,4347,954],{"class":549},[532,4349,550],{"class":549},[532,4351,2318],{"class":553},[532,4353,557],{"class":549},[532,4355,1388],{"class":549},[532,4357,4358,4361,4363],{"class":534,"line":605},[532,4359,4360],{"class":1756},"  options",[532,4362,954],{"class":549},[532,4364,2628],{"class":549},[532,4366,4367,4370,4372,4374,4377,4379,4381,4384,4386,4388,4391,4393,4395,4398,4400,4402],{"class":534,"line":619},[532,4368,4369],{"class":1756},"    data",[532,4371,954],{"class":549},[532,4373,1339],{"class":549},[532,4375,4376],{"class":1756}," full_name",[532,4378,954],{"class":549},[532,4380,550],{"class":549},[532,4382,4383],{"class":553},"Nguyen Van A",[532,4385,557],{"class":549},[532,4387,1653],{"class":549},[532,4389,4390],{"class":1756}," role",[532,4392,954],{"class":549},[532,4394,550],{"class":549},[532,4396,4397],{"class":553},"member",[532,4399,557],{"class":549},[532,4401,2075],{"class":549},[532,4403,4404],{"class":538},"  \u002F\u002F user metadata\n",[532,4406,4407,4410,4412,4414,4417,4419,4421],{"class":534,"line":630},[532,4408,4409],{"class":1756},"    emailRedirectTo",[532,4411,954],{"class":549},[532,4413,550],{"class":549},[532,4415,4416],{"class":553},"https:\u002F\u002Fmyapp.com\u002Fwelcome",[532,4418,557],{"class":549},[532,4420,1653],{"class":549},[532,4422,4423],{"class":538},"          \u002F\u002F redirect sau khi verify email\n",[532,4425,4426],{"class":534,"line":635},[532,4427,4428],{"class":549},"  }\n",[532,4430,4431,4433],{"class":534,"line":641},[532,4432,1659],{"class":549},[532,4434,1203],{"class":560},[532,4436,4437],{"class":534,"line":661},[532,4438,596],{"emptyLinePlaceholder":595},[532,4440,4441],{"class":534,"line":674},[532,4442,4443],{"class":538},"\u002F\u002F Sign in với email + password\n",[532,4445,4446,4448,4450,4452,4454,4456,4458,4460,4462,4464,4466,4468,4470,4473,4475],{"class":534,"line":688},[532,4447,1364],{"class":1363},[532,4449,1339],{"class":549},[532,4451,1650],{"class":560},[532,4453,1653],{"class":549},[532,4455,1656],{"class":560},[532,4457,1659],{"class":549},[532,4459,1662],{"class":549},[532,4461,1665],{"class":1335},[532,4463,2273],{"class":560},[532,4465,448],{"class":549},[532,4467,2278],{"class":560},[532,4469,448],{"class":549},[532,4471,4472],{"class":1372},"signInWithPassword",[532,4474,1197],{"class":560},[532,4476,2288],{"class":549},[532,4478,4479,4481,4483,4485,4487,4489],{"class":534,"line":702},[532,4480,2294],{"class":1756},[532,4482,954],{"class":549},[532,4484,550],{"class":549},[532,4486,2301],{"class":553},[532,4488,557],{"class":549},[532,4490,1388],{"class":549},[532,4492,4493,4495,4497,4499,4501,4503],{"class":534,"line":715},[532,4494,2311],{"class":1756},[532,4496,954],{"class":549},[532,4498,550],{"class":549},[532,4500,2318],{"class":553},[532,4502,557],{"class":549},[532,4504,1388],{"class":549},[532,4506,4507,4509],{"class":534,"line":720},[532,4508,1659],{"class":549},[532,4510,1203],{"class":560},[532,4512,4513],{"class":534,"line":726},[532,4514,596],{"emptyLinePlaceholder":595},[532,4516,4517],{"class":534,"line":745},[532,4518,4519],{"class":538},"\u002F\u002F Sign in với Magic Link (passwordless — gửi link qua email)\n",[532,4521,4522,4524,4526,4528,4530,4532,4534,4536,4538,4540,4542,4544,4546,4549,4551],{"class":534,"line":758},[532,4523,1364],{"class":1363},[532,4525,1339],{"class":549},[532,4527,1650],{"class":560},[532,4529,1653],{"class":549},[532,4531,1656],{"class":560},[532,4533,1659],{"class":549},[532,4535,1662],{"class":549},[532,4537,1665],{"class":1335},[532,4539,2273],{"class":560},[532,4541,448],{"class":549},[532,4543,2278],{"class":560},[532,4545,448],{"class":549},[532,4547,4548],{"class":1372},"signInWithOtp",[532,4550,1197],{"class":560},[532,4552,2288],{"class":549},[532,4554,4555,4557,4559,4561,4563,4565],{"class":534,"line":771},[532,4556,2294],{"class":1756},[532,4558,954],{"class":549},[532,4560,550],{"class":549},[532,4562,2301],{"class":553},[532,4564,557],{"class":549},[532,4566,1388],{"class":549},[532,4568,4569,4571,4573],{"class":534,"line":783},[532,4570,4360],{"class":1756},[532,4572,954],{"class":549},[532,4574,2628],{"class":549},[532,4576,4577,4579,4581,4583,4586,4588],{"class":534,"line":788},[532,4578,4409],{"class":1756},[532,4580,954],{"class":549},[532,4582,550],{"class":549},[532,4584,4585],{"class":553},"https:\u002F\u002Fmyapp.com\u002Fauth\u002Fcallback",[532,4587,557],{"class":549},[532,4589,1388],{"class":549},[532,4591,4592,4595,4597,4599,4601],{"class":534,"line":794},[532,4593,4594],{"class":1756},"    shouldCreateUser",[532,4596,954],{"class":549},[532,4598,2922],{"class":1762},[532,4600,1653],{"class":549},[532,4602,4603],{"class":538},"   \u002F\u002F tự động tạo user nếu chưa có\n",[532,4605,4606],{"class":534,"line":812},[532,4607,4428],{"class":549},[532,4609,4610,4612],{"class":534,"line":825},[532,4611,1659],{"class":549},[532,4613,1203],{"class":560},[532,4615,4616],{"class":534,"line":2099},[532,4617,596],{"emptyLinePlaceholder":595},[532,4619,4620],{"class":534,"line":2105},[532,4621,4622],{"class":538},"\u002F\u002F Sign in với SMS OTP\n",[532,4624,4625,4627,4629,4631,4633,4635,4637,4639,4641,4643,4645,4647,4649,4651,4653],{"class":534,"line":2126},[532,4626,1364],{"class":1363},[532,4628,1339],{"class":549},[532,4630,1650],{"class":560},[532,4632,1653],{"class":549},[532,4634,1656],{"class":560},[532,4636,1659],{"class":549},[532,4638,1662],{"class":549},[532,4640,1665],{"class":1335},[532,4642,2273],{"class":560},[532,4644,448],{"class":549},[532,4646,2278],{"class":560},[532,4648,448],{"class":549},[532,4650,4548],{"class":1372},[532,4652,1197],{"class":560},[532,4654,2288],{"class":549},[532,4656,4657,4660,4662,4664,4667,4669],{"class":534,"line":2143},[532,4658,4659],{"class":1756},"  phone",[532,4661,954],{"class":549},[532,4663,550],{"class":549},[532,4665,4666],{"class":553},"+84912345678",[532,4668,557],{"class":549},[532,4670,1388],{"class":549},[532,4672,4673,4675,4677,4679,4682,4684,4686,4689,4691],{"class":534,"line":2153},[532,4674,4360],{"class":1756},[532,4676,954],{"class":549},[532,4678,1339],{"class":549},[532,4680,4681],{"class":1756}," channel",[532,4683,954],{"class":549},[532,4685,550],{"class":549},[532,4687,4688],{"class":553},"sms",[532,4690,557],{"class":549},[532,4692,2653],{"class":549},[532,4694,4695,4697],{"class":534,"line":2174},[532,4696,1659],{"class":549},[532,4698,1203],{"class":560},[532,4700,4701],{"class":534,"line":2179},[532,4702,596],{"emptyLinePlaceholder":595},[532,4704,4705],{"class":534,"line":2185},[532,4706,4707],{"class":538},"\u002F\u002F Sign in với WhatsApp OTP\n",[532,4709,4710,4712,4714,4716,4718,4720,4722,4724,4726,4728,4730,4732,4734,4736,4738],{"class":534,"line":2206},[532,4711,1364],{"class":1363},[532,4713,1339],{"class":549},[532,4715,1650],{"class":560},[532,4717,1653],{"class":549},[532,4719,1656],{"class":560},[532,4721,1659],{"class":549},[532,4723,1662],{"class":549},[532,4725,1665],{"class":1335},[532,4727,2273],{"class":560},[532,4729,448],{"class":549},[532,4731,2278],{"class":560},[532,4733,448],{"class":549},[532,4735,4548],{"class":1372},[532,4737,1197],{"class":560},[532,4739,2288],{"class":549},[532,4741,4742,4744,4746,4748,4750,4752],{"class":534,"line":2243},[532,4743,4659],{"class":1756},[532,4745,954],{"class":549},[532,4747,550],{"class":549},[532,4749,4666],{"class":553},[532,4751,557],{"class":549},[532,4753,1388],{"class":549},[532,4755,4756,4758,4760,4762,4764,4766,4768,4771,4773],{"class":534,"line":2248},[532,4757,4360],{"class":1756},[532,4759,954],{"class":549},[532,4761,1339],{"class":549},[532,4763,4681],{"class":1756},[532,4765,954],{"class":549},[532,4767,550],{"class":549},[532,4769,4770],{"class":553},"whatsapp",[532,4772,557],{"class":549},[532,4774,2653],{"class":549},[532,4776,4777,4779],{"class":534,"line":2254},[532,4778,1659],{"class":549},[532,4780,1203],{"class":560},[532,4782,4783],{"class":534,"line":2291},[532,4784,596],{"emptyLinePlaceholder":595},[532,4786,4787],{"class":534,"line":2308},[532,4788,4789],{"class":538},"\u002F\u002F Sign in với OAuth providers\n",[532,4791,4792,4794,4796,4798,4800,4802,4804,4806,4808,4810,4812,4814,4816,4819,4821],{"class":534,"line":2323},[532,4793,1364],{"class":1363},[532,4795,1339],{"class":549},[532,4797,1650],{"class":560},[532,4799,1653],{"class":549},[532,4801,1656],{"class":560},[532,4803,1659],{"class":549},[532,4805,1662],{"class":549},[532,4807,1665],{"class":1335},[532,4809,2273],{"class":560},[532,4811,448],{"class":549},[532,4813,2278],{"class":560},[532,4815,448],{"class":549},[532,4817,4818],{"class":1372},"signInWithOAuth",[532,4820,1197],{"class":560},[532,4822,2288],{"class":549},[532,4824,4825,4828,4830,4832,4835,4837],{"class":534,"line":2330},[532,4826,4827],{"class":1756},"  provider",[532,4829,954],{"class":549},[532,4831,550],{"class":549},[532,4833,4834],{"class":553},"google",[532,4836,557],{"class":549},[532,4838,1388],{"class":549},[532,4840,4841,4843,4845],{"class":534,"line":2335},[532,4842,4360],{"class":1756},[532,4844,954],{"class":549},[532,4846,2628],{"class":549},[532,4848,4849,4852,4854,4856,4858,4860],{"class":534,"line":2341},[532,4850,4851],{"class":1756},"    redirectTo",[532,4853,954],{"class":549},[532,4855,550],{"class":549},[532,4857,4585],{"class":553},[532,4859,557],{"class":549},[532,4861,1388],{"class":549},[532,4863,4864,4867,4869,4871,4874,4876,4878,4881,4883,4885,4888,4890,4892,4895,4897],{"class":534,"line":2353},[532,4865,4866],{"class":1756},"    queryParams",[532,4868,954],{"class":549},[532,4870,1339],{"class":549},[532,4872,4873],{"class":1756}," access_type",[532,4875,954],{"class":549},[532,4877,550],{"class":549},[532,4879,4880],{"class":553},"offline",[532,4882,557],{"class":549},[532,4884,1653],{"class":549},[532,4886,4887],{"class":1756}," prompt",[532,4889,954],{"class":549},[532,4891,550],{"class":549},[532,4893,4894],{"class":553},"consent",[532,4896,557],{"class":549},[532,4898,2437],{"class":549},[532,4900,4901,4904,4906,4908,4911,4913,4915],{"class":534,"line":2372},[532,4902,4903],{"class":1756},"    scopes",[532,4905,954],{"class":549},[532,4907,550],{"class":549},[532,4909,4910],{"class":553},"profile email",[532,4912,557],{"class":549},[532,4914,1653],{"class":549},[532,4916,4917],{"class":538},"   \u002F\u002F additional scopes\n",[532,4919,4920],{"class":534,"line":2391},[532,4921,4428],{"class":549},[532,4923,4924,4926],{"class":534,"line":2440},[532,4925,1659],{"class":549},[532,4927,1203],{"class":560},[532,4929,4930],{"class":534,"line":2482},[532,4931,596],{"emptyLinePlaceholder":595},[532,4933,4934],{"class":534,"line":2488},[532,4935,4936],{"class":538},"\u002F\u002F OAuth providers hỗ trợ:\n",[532,4938,4939],{"class":534,"line":2498},[532,4940,4941],{"class":538},"\u002F\u002F 'google', 'github', 'gitlab', 'bitbucket', 'discord',\n",[532,4943,4944],{"class":534,"line":2503},[532,4945,4946],{"class":538},"\u002F\u002F 'twitter', 'apple', 'facebook', 'figma', 'kakao',\n",[532,4948,4949],{"class":534,"line":2509},[532,4950,4951],{"class":538},"\u002F\u002F 'keycloak', 'linkedin', 'linkedin_oidc', 'notion',\n",[532,4953,4954],{"class":534,"line":2535},[532,4955,4956],{"class":538},"\u002F\u002F 'slack', 'slack_oidc', 'spotify', 'twitch',\n",[532,4958,4959],{"class":534,"line":2553},[532,4960,4961],{"class":538},"\u002F\u002F 'workos', 'zoom', 'azure', 'fly' (tùy project config)\n",[532,4963,4964],{"class":534,"line":2575},[532,4965,596],{"emptyLinePlaceholder":595},[532,4967,4968],{"class":534,"line":2580},[532,4969,4970],{"class":538},"\u002F\u002F Sign in với SSO (Enterprise — SAML 2.0)\n",[532,4972,4973,4975,4977,4979,4981,4983,4985,4987,4989,4991,4993,4995,4997,5000,5002],{"class":534,"line":2586},[532,4974,1364],{"class":1363},[532,4976,1339],{"class":549},[532,4978,1650],{"class":560},[532,4980,1653],{"class":549},[532,4982,1656],{"class":560},[532,4984,1659],{"class":549},[532,4986,1662],{"class":549},[532,4988,1665],{"class":1335},[532,4990,2273],{"class":560},[532,4992,448],{"class":549},[532,4994,2278],{"class":560},[532,4996,448],{"class":549},[532,4998,4999],{"class":1372},"signInWithSSO",[532,5001,1197],{"class":560},[532,5003,2288],{"class":549},[532,5005,5006,5009,5011,5013,5016,5018],{"class":534,"line":2631},[532,5007,5008],{"class":1756},"  domain",[532,5010,954],{"class":549},[532,5012,550],{"class":549},[532,5014,5015],{"class":553},"company.com",[532,5017,557],{"class":549},[532,5019,1388],{"class":549},[532,5021,5022,5024,5026],{"class":534,"line":2656},[532,5023,4360],{"class":1756},[532,5025,954],{"class":549},[532,5027,2628],{"class":549},[532,5029,5030,5032,5034,5036,5038,5040],{"class":534,"line":3970},[532,5031,4851],{"class":1756},[532,5033,954],{"class":549},[532,5035,550],{"class":549},[532,5037,4585],{"class":553},[532,5039,557],{"class":549},[532,5041,1388],{"class":549},[532,5043,5044,5047,5049,5051,5054,5056,5058],{"class":534,"line":3991},[532,5045,5046],{"class":1756},"    captchaToken",[532,5048,954],{"class":549},[532,5050,550],{"class":549},[532,5052,5053],{"class":553},"...",[532,5055,557],{"class":549},[532,5057,1653],{"class":549},[532,5059,5060],{"class":538},"  \u002F\u002F nếu bắt buộc CAPTCHA\n",[532,5062,5063],{"class":534,"line":3996},[532,5064,4428],{"class":549},[532,5066,5067,5069],{"class":534,"line":4017},[532,5068,1659],{"class":549},[532,5070,1203],{"class":560},[532,5072,5073],{"class":534,"line":4038},[532,5074,596],{"emptyLinePlaceholder":595},[532,5076,5077],{"class":534,"line":4059},[532,5078,5079],{"class":538},"\u002F\u002F Anonymous sign-in (user tạm thời, có thể upgrade lên full account)\n",[532,5081,5082,5084,5086,5088,5090,5092,5094,5096,5098,5100,5102,5104,5106,5109],{"class":534,"line":4064},[532,5083,1364],{"class":1363},[532,5085,1339],{"class":549},[532,5087,1650],{"class":560},[532,5089,1653],{"class":549},[532,5091,1656],{"class":560},[532,5093,1659],{"class":549},[532,5095,1662],{"class":549},[532,5097,1665],{"class":1335},[532,5099,2273],{"class":560},[532,5101,448],{"class":549},[532,5103,2278],{"class":560},[532,5105,448],{"class":549},[532,5107,5108],{"class":1372},"signInAnonymously",[532,5110,1996],{"class":560},[532,5112,5113],{"class":534,"line":4077},[532,5114,596],{"emptyLinePlaceholder":595},[532,5116,5117],{"class":534,"line":4091},[532,5118,5119],{"class":538},"\u002F\u002F Sign in với token từ 3rd party (Apple Game Center, Sign in with Apple native, etc.)\n",[532,5121,5122,5124,5126,5128,5130,5132,5134,5136,5138,5140,5142,5144,5146,5149,5151],{"class":534,"line":4112},[532,5123,1364],{"class":1363},[532,5125,1339],{"class":549},[532,5127,1650],{"class":560},[532,5129,1653],{"class":549},[532,5131,1656],{"class":560},[532,5133,1659],{"class":549},[532,5135,1662],{"class":549},[532,5137,1665],{"class":1335},[532,5139,2273],{"class":560},[532,5141,448],{"class":549},[532,5143,2278],{"class":560},[532,5145,448],{"class":549},[532,5147,5148],{"class":1372},"signInWithIdToken",[532,5150,1197],{"class":560},[532,5152,2288],{"class":549},[532,5154,5155,5157,5159,5161,5164,5166],{"class":534,"line":4126},[532,5156,4827],{"class":1756},[532,5158,954],{"class":549},[532,5160,550],{"class":549},[532,5162,5163],{"class":553},"apple",[532,5165,557],{"class":549},[532,5167,1388],{"class":549},[532,5169,5170,5173,5175,5177,5180,5182],{"class":534,"line":4131},[532,5171,5172],{"class":1756},"  token",[532,5174,954],{"class":549},[532,5176,550],{"class":549},[532,5178,5179],{"class":553},"id-token-from-apple",[532,5181,557],{"class":549},[532,5183,1388],{"class":549},[532,5185,5186,5189,5191,5193,5195,5197,5199],{"class":534,"line":4137},[532,5187,5188],{"class":1756},"  access_token",[532,5190,954],{"class":549},[532,5192,550],{"class":549},[532,5194,5053],{"class":553},[532,5196,557],{"class":549},[532,5198,1653],{"class":549},[532,5200,5201],{"class":538},"  \u002F\u002F optional\n",[532,5203,5204,5207,5209,5211,5213,5215,5217],{"class":534,"line":4156},[532,5205,5206],{"class":1756},"  nonce",[532,5208,954],{"class":549},[532,5210,550],{"class":549},[532,5212,5053],{"class":553},[532,5214,557],{"class":549},[532,5216,1653],{"class":549},[532,5218,5219],{"class":538},"         \u002F\u002F optional\n",[532,5221,5222,5224],{"class":534,"line":4170},[532,5223,1659],{"class":549},[532,5225,1203],{"class":560},[532,5227,5228],{"class":534,"line":4195},[532,5229,596],{"emptyLinePlaceholder":595},[532,5231,5232],{"class":534,"line":4228},[532,5233,5234],{"class":538},"\u002F\u002F ============ SESSION MANAGEMENT ============\n",[532,5236,5237],{"class":534,"line":4241},[532,5238,596],{"emptyLinePlaceholder":595},[532,5240,5241],{"class":534,"line":4255},[532,5242,5243],{"class":538},"\u002F\u002F Lấy session hiện tại (từ localStorage ở browser)\n",[532,5245,5247,5249,5251,5253,5255,5257,5260,5263,5265,5267,5269,5271,5273,5275,5277,5279,5282],{"class":534,"line":5246},80,[532,5248,1364],{"class":1363},[532,5250,1339],{"class":549},[532,5252,1650],{"class":1756},[532,5254,954],{"class":549},[532,5256,1339],{"class":549},[532,5258,5259],{"class":560}," session ",[532,5261,5262],{"class":549},"},",[532,5264,1656],{"class":560},[532,5266,1659],{"class":549},[532,5268,1662],{"class":549},[532,5270,1665],{"class":1335},[532,5272,2273],{"class":560},[532,5274,448],{"class":549},[532,5276,2278],{"class":560},[532,5278,448],{"class":549},[532,5280,5281],{"class":1372},"getSession",[532,5283,1996],{"class":560},[532,5285,5287],{"class":534,"line":5286},81,[532,5288,596],{"emptyLinePlaceholder":595},[532,5290,5292],{"class":534,"line":5291},82,[532,5293,5294],{"class":538},"\u002F\u002F Lấy user hiện tại từ JWT trong session\n",[532,5296,5298,5300,5302,5304,5306,5308,5311,5313,5315,5317,5319,5321,5323,5325,5327,5329,5332],{"class":534,"line":5297},83,[532,5299,1364],{"class":1363},[532,5301,1339],{"class":549},[532,5303,1650],{"class":1756},[532,5305,954],{"class":549},[532,5307,1339],{"class":549},[532,5309,5310],{"class":560}," user ",[532,5312,5262],{"class":549},[532,5314,1656],{"class":560},[532,5316,1659],{"class":549},[532,5318,1662],{"class":549},[532,5320,1665],{"class":1335},[532,5322,2273],{"class":560},[532,5324,448],{"class":549},[532,5326,2278],{"class":560},[532,5328,448],{"class":549},[532,5330,5331],{"class":1372},"getUser",[532,5333,1996],{"class":560},[532,5335,5337],{"class":534,"line":5336},84,[532,5338,596],{"emptyLinePlaceholder":595},[532,5340,5342],{"class":534,"line":5341},85,[532,5343,5344],{"class":538},"\u002F\u002F Refresh session (dùng refresh token để lấy access token mới)\n",[532,5346,5348,5350,5352,5354,5356,5358,5360,5362,5364,5366,5368,5370,5372,5375],{"class":534,"line":5347},86,[532,5349,1364],{"class":1363},[532,5351,1339],{"class":549},[532,5353,1650],{"class":560},[532,5355,1653],{"class":549},[532,5357,1656],{"class":560},[532,5359,1659],{"class":549},[532,5361,1662],{"class":549},[532,5363,1665],{"class":1335},[532,5365,2273],{"class":560},[532,5367,448],{"class":549},[532,5369,2278],{"class":560},[532,5371,448],{"class":549},[532,5373,5374],{"class":1372},"refreshSession",[532,5376,1996],{"class":560},[532,5378,5380,5382,5384,5387,5389,5391,5393,5395],{"class":534,"line":5379},87,[532,5381,1364],{"class":1363},[532,5383,1339],{"class":549},[532,5385,5386],{"class":560}," session",[532,5388,1653],{"class":549},[532,5390,5310],{"class":560},[532,5392,1659],{"class":549},[532,5394,1662],{"class":549},[532,5396,5397],{"class":560}," data\n",[532,5399,5401],{"class":534,"line":5400},88,[532,5402,596],{"emptyLinePlaceholder":595},[532,5404,5406],{"class":534,"line":5405},89,[532,5407,5408],{"class":538},"\u002F\u002F Set session manually (ví dụ: sau khi nhận token từ backend)\n",[532,5410,5412,5414,5416,5418,5420,5422,5424,5426,5428,5430,5432,5434,5436,5439,5441],{"class":534,"line":5411},90,[532,5413,1364],{"class":1363},[532,5415,1339],{"class":549},[532,5417,1650],{"class":560},[532,5419,1653],{"class":549},[532,5421,1656],{"class":560},[532,5423,1659],{"class":549},[532,5425,1662],{"class":549},[532,5427,1665],{"class":1335},[532,5429,2273],{"class":560},[532,5431,448],{"class":549},[532,5433,2278],{"class":560},[532,5435,448],{"class":549},[532,5437,5438],{"class":1372},"setSession",[532,5440,1197],{"class":560},[532,5442,2288],{"class":549},[532,5444,5446,5448,5450,5452,5455,5457],{"class":534,"line":5445},91,[532,5447,5188],{"class":1756},[532,5449,954],{"class":549},[532,5451,550],{"class":549},[532,5453,5454],{"class":553},"eyJ...",[532,5456,557],{"class":549},[532,5458,1388],{"class":549},[532,5460,5462,5465,5467,5469,5471,5473],{"class":534,"line":5461},92,[532,5463,5464],{"class":1756},"  refresh_token",[532,5466,954],{"class":549},[532,5468,550],{"class":549},[532,5470,5053],{"class":553},[532,5472,557],{"class":549},[532,5474,1388],{"class":549},[532,5476,5478,5480],{"class":534,"line":5477},93,[532,5479,1659],{"class":549},[532,5481,1203],{"class":560},[532,5483,5485],{"class":534,"line":5484},94,[532,5486,596],{"emptyLinePlaceholder":595},[532,5488,5490],{"class":534,"line":5489},95,[532,5491,5492],{"class":538},"\u002F\u002F Lắng nghe thay đổi trạng thái auth\n",[532,5494,5496,5498,5500,5502,5504,5506,5509,5511,5513,5515,5517,5519,5521,5523,5526],{"class":534,"line":5495},96,[532,5497,1364],{"class":1363},[532,5499,1339],{"class":549},[532,5501,1650],{"class":1756},[532,5503,954],{"class":549},[532,5505,1339],{"class":549},[532,5507,5508],{"class":560}," subscription ",[532,5510,1659],{"class":549},[532,5512,1345],{"class":549},[532,5514,1662],{"class":549},[532,5516,2273],{"class":560},[532,5518,448],{"class":549},[532,5520,2278],{"class":560},[532,5522,448],{"class":549},[532,5524,5525],{"class":1372},"onAuthStateChange",[532,5527,1375],{"class":560},[532,5529,5531,5534,5537,5539,5541,5543,5545],{"class":534,"line":5530},97,[532,5532,5533],{"class":549},"  (",[532,5535,5536],{"class":2446},"event",[532,5538,1653],{"class":549},[532,5540,5386],{"class":2446},[532,5542,1310],{"class":549},[532,5544,2452],{"class":1363},[532,5546,2628],{"class":549},[532,5548,5550,5553,5555,5557,5559,5561,5564,5566,5568,5570,5572],{"class":534,"line":5549},98,[532,5551,5552],{"class":560},"    console",[532,5554,448],{"class":549},[532,5556,2460],{"class":1372},[532,5558,1197],{"class":1756},[532,5560,557],{"class":549},[532,5562,5563],{"class":553},"Auth event:",[532,5565,557],{"class":549},[532,5567,1653],{"class":549},[532,5569,2397],{"class":560},[532,5571,2866],{"class":1756},[532,5573,5574],{"class":538},"\u002F\u002F SIGNED_IN, SIGNED_OUT, USER_UPDATED,\n",[532,5576,5578],{"class":534,"line":5577},99,[532,5579,5580],{"class":538},"                                         \u002F\u002F USER_DELETED, PASSWORD_RECOVERY,\n",[532,5582,5584],{"class":534,"line":5583},100,[532,5585,5586],{"class":538},"                                         \u002F\u002F TOKEN_REFRESHED, MFA_CHALLENGE_VERIFIED\n",[532,5588,5590,5592,5594,5596,5598,5600,5603,5605,5607,5609],{"class":534,"line":5589},101,[532,5591,5552],{"class":560},[532,5593,448],{"class":549},[532,5595,2460],{"class":1372},[532,5597,1197],{"class":1756},[532,5599,557],{"class":549},[532,5601,5602],{"class":553},"Session:",[532,5604,557],{"class":549},[532,5606,1653],{"class":549},[532,5608,5386],{"class":560},[532,5610,1203],{"class":1756},[532,5612,5614],{"class":534,"line":5613},102,[532,5615,4428],{"class":549},[532,5617,5619],{"class":534,"line":5618},103,[532,5620,1203],{"class":560},[532,5622,5624],{"class":534,"line":5623},104,[532,5625,5626],{"class":538},"\u002F\u002F subscription.unsubscribe() — để cleanup\n",[532,5628,5630],{"class":534,"line":5629},105,[532,5631,596],{"emptyLinePlaceholder":595},[532,5633,5635],{"class":534,"line":5634},106,[532,5636,5637],{"class":538},"\u002F\u002F Sign out\n",[532,5639,5641,5643,5645,5647,5649,5651,5653,5655,5657,5659,5661,5664],{"class":534,"line":5640},107,[532,5642,1364],{"class":1363},[532,5644,1339],{"class":549},[532,5646,1656],{"class":560},[532,5648,1659],{"class":549},[532,5650,1662],{"class":549},[532,5652,1665],{"class":1335},[532,5654,2273],{"class":560},[532,5656,448],{"class":549},[532,5658,2278],{"class":560},[532,5660,448],{"class":549},[532,5662,5663],{"class":1372},"signOut",[532,5665,1996],{"class":560},[532,5667,5669],{"class":534,"line":5668},108,[532,5670,5671],{"class":538},"\u002F\u002F Sign out globally (tất cả devices)\n",[532,5673,5675,5677,5679,5681,5683,5685,5687,5689,5691,5693,5695,5697,5699,5701,5704,5706,5708,5711,5713,5715],{"class":534,"line":5674},109,[532,5676,1364],{"class":1363},[532,5678,1339],{"class":549},[532,5680,1656],{"class":560},[532,5682,1659],{"class":549},[532,5684,1662],{"class":549},[532,5686,1665],{"class":1335},[532,5688,2273],{"class":560},[532,5690,448],{"class":549},[532,5692,2278],{"class":560},[532,5694,448],{"class":549},[532,5696,5663],{"class":1372},[532,5698,1197],{"class":560},[532,5700,1851],{"class":549},[532,5702,5703],{"class":1756}," scope",[532,5705,954],{"class":549},[532,5707,550],{"class":549},[532,5709,5710],{"class":553},"global",[532,5712,557],{"class":549},[532,5714,1345],{"class":549},[532,5716,1203],{"class":560},[532,5718,5720],{"class":534,"line":5719},110,[532,5721,5722],{"class":538},"\u002F\u002F Sign out chỉ trên device hiện tại\n",[532,5724,5726,5728,5730,5732,5734,5736,5738,5740,5742,5744,5746,5748,5750,5752,5754,5756,5758,5761,5763,5765],{"class":534,"line":5725},111,[532,5727,1364],{"class":1363},[532,5729,1339],{"class":549},[532,5731,1656],{"class":560},[532,5733,1659],{"class":549},[532,5735,1662],{"class":549},[532,5737,1665],{"class":1335},[532,5739,2273],{"class":560},[532,5741,448],{"class":549},[532,5743,2278],{"class":560},[532,5745,448],{"class":549},[532,5747,5663],{"class":1372},[532,5749,1197],{"class":560},[532,5751,1851],{"class":549},[532,5753,5703],{"class":1756},[532,5755,954],{"class":549},[532,5757,550],{"class":549},[532,5759,5760],{"class":553},"local",[532,5762,557],{"class":549},[532,5764,1345],{"class":549},[532,5766,1203],{"class":560},[532,5768,5770],{"class":534,"line":5769},112,[532,5771,596],{"emptyLinePlaceholder":595},[532,5773,5775],{"class":534,"line":5774},113,[532,5776,5777],{"class":538},"\u002F\u002F ============ USER MANAGEMENT ============\n",[532,5779,5781],{"class":534,"line":5780},114,[532,5782,596],{"emptyLinePlaceholder":595},[532,5784,5786],{"class":534,"line":5785},115,[532,5787,5788],{"class":538},"\u002F\u002F Update user profile (email, password, metadata)\n",[532,5790,5792,5794,5796,5798,5800,5802,5804,5806,5808,5810,5812,5814,5816,5819,5821],{"class":534,"line":5791},116,[532,5793,1364],{"class":1363},[532,5795,1339],{"class":549},[532,5797,1650],{"class":560},[532,5799,1653],{"class":549},[532,5801,1656],{"class":560},[532,5803,1659],{"class":549},[532,5805,1662],{"class":549},[532,5807,1665],{"class":1335},[532,5809,2273],{"class":560},[532,5811,448],{"class":549},[532,5813,2278],{"class":560},[532,5815,448],{"class":549},[532,5817,5818],{"class":1372},"updateUser",[532,5820,1197],{"class":560},[532,5822,2288],{"class":549},[532,5824,5826,5828,5830,5832,5835,5837],{"class":534,"line":5825},117,[532,5827,2294],{"class":1756},[532,5829,954],{"class":549},[532,5831,550],{"class":549},[532,5833,5834],{"class":553},"new-email@example.com",[532,5836,557],{"class":549},[532,5838,1388],{"class":549},[532,5840,5842,5844,5846,5848,5851,5853],{"class":534,"line":5841},118,[532,5843,2311],{"class":1756},[532,5845,954],{"class":549},[532,5847,550],{"class":549},[532,5849,5850],{"class":553},"new-password",[532,5852,557],{"class":549},[532,5854,1388],{"class":549},[532,5856,5858,5861,5863,5865,5867,5869,5871,5874,5876,5878,5881,5883,5885,5888,5890],{"class":534,"line":5857},119,[532,5859,5860],{"class":1756},"  data",[532,5862,954],{"class":549},[532,5864,1339],{"class":549},[532,5866,4376],{"class":1756},[532,5868,954],{"class":549},[532,5870,550],{"class":549},[532,5872,5873],{"class":553},"New Name",[532,5875,557],{"class":549},[532,5877,1653],{"class":549},[532,5879,5880],{"class":1756}," avatar_url",[532,5882,954],{"class":549},[532,5884,550],{"class":549},[532,5886,5887],{"class":553},"https:\u002F\u002F...",[532,5889,557],{"class":549},[532,5891,2437],{"class":549},[532,5893,5895,5897],{"class":534,"line":5894},120,[532,5896,1659],{"class":549},[532,5898,1203],{"class":560},[532,5900,5902],{"class":534,"line":5901},121,[532,5903,596],{"emptyLinePlaceholder":595},[532,5905,5907],{"class":534,"line":5906},122,[532,5908,5909],{"class":538},"\u002F\u002F Gửi email reset password\n",[532,5911,5913,5915,5917,5919,5921,5923,5925,5927,5929,5931,5933,5935,5937,5940],{"class":534,"line":5912},123,[532,5914,1364],{"class":1363},[532,5916,1339],{"class":549},[532,5918,1650],{"class":560},[532,5920,1653],{"class":549},[532,5922,1656],{"class":560},[532,5924,1659],{"class":549},[532,5926,1662],{"class":549},[532,5928,1665],{"class":1335},[532,5930,2273],{"class":560},[532,5932,448],{"class":549},[532,5934,2278],{"class":560},[532,5936,448],{"class":549},[532,5938,5939],{"class":1372},"resetPasswordForEmail",[532,5941,1375],{"class":560},[532,5943,5945,5947,5949,5951],{"class":534,"line":5944},124,[532,5946,1380],{"class":549},[532,5948,2301],{"class":553},[532,5950,557],{"class":549},[532,5952,1388],{"class":549},[532,5954,5956,5959,5962,5964,5966,5969,5971],{"class":534,"line":5955},125,[532,5957,5958],{"class":549},"  {",[532,5960,5961],{"class":1756}," redirectTo",[532,5963,954],{"class":549},[532,5965,550],{"class":549},[532,5967,5968],{"class":553},"https:\u002F\u002Fmyapp.com\u002Freset-password",[532,5970,557],{"class":549},[532,5972,2653],{"class":549},[532,5974,5976],{"class":534,"line":5975},126,[532,5977,1203],{"class":560},[532,5979,5981],{"class":534,"line":5980},127,[532,5982,596],{"emptyLinePlaceholder":595},[532,5984,5986],{"class":534,"line":5985},128,[532,5987,5988],{"class":538},"\u002F\u002F Reauthenticate (yêu cầu đăng nhập lại trước khi làm thao tác nhạy cảm)\n",[532,5990,5992,5994,5996,5998,6000,6002,6004,6006,6008,6010,6012,6014,6016,6019],{"class":534,"line":5991},129,[532,5993,1364],{"class":1363},[532,5995,1339],{"class":549},[532,5997,1650],{"class":560},[532,5999,1653],{"class":549},[532,6001,1656],{"class":560},[532,6003,1659],{"class":549},[532,6005,1662],{"class":549},[532,6007,1665],{"class":1335},[532,6009,2273],{"class":560},[532,6011,448],{"class":549},[532,6013,2278],{"class":560},[532,6015,448],{"class":549},[532,6017,6018],{"class":1372},"reauthenticate",[532,6020,1996],{"class":560},[532,6022,6024],{"class":534,"line":6023},130,[532,6025,596],{"emptyLinePlaceholder":595},[532,6027,6029],{"class":534,"line":6028},131,[532,6030,6031],{"class":538},"\u002F\u002F Resend confirmation email \u002F OTP\n",[532,6033,6035,6037,6039,6041,6043,6045,6047,6049,6051,6053,6055,6057,6059,6062,6064],{"class":534,"line":6034},132,[532,6036,1364],{"class":1363},[532,6038,1339],{"class":549},[532,6040,1650],{"class":560},[532,6042,1653],{"class":549},[532,6044,1656],{"class":560},[532,6046,1659],{"class":549},[532,6048,1662],{"class":549},[532,6050,1665],{"class":1335},[532,6052,2273],{"class":560},[532,6054,448],{"class":549},[532,6056,2278],{"class":560},[532,6058,448],{"class":549},[532,6060,6061],{"class":1372},"resend",[532,6063,1197],{"class":560},[532,6065,2288],{"class":549},[532,6067,6069,6072,6074,6076,6079,6081,6083],{"class":534,"line":6068},133,[532,6070,6071],{"class":1756},"  type",[532,6073,954],{"class":549},[532,6075,550],{"class":549},[532,6077,6078],{"class":553},"signup",[532,6080,557],{"class":549},[532,6082,1653],{"class":549},[532,6084,6085],{"class":538},"      \u002F\u002F 'signup' | 'email_change' | 'sms' | 'phone_change'\n",[532,6087,6089,6091,6093,6095,6097,6099],{"class":534,"line":6088},134,[532,6090,2294],{"class":1756},[532,6092,954],{"class":549},[532,6094,550],{"class":549},[532,6096,2301],{"class":553},[532,6098,557],{"class":549},[532,6100,1388],{"class":549},[532,6102,6104,6106,6108],{"class":534,"line":6103},135,[532,6105,4360],{"class":1756},[532,6107,954],{"class":549},[532,6109,2628],{"class":549},[532,6111,6113,6115,6117,6119,6122],{"class":534,"line":6112},136,[532,6114,4409],{"class":1756},[532,6116,954],{"class":549},[532,6118,550],{"class":549},[532,6120,6121],{"class":553},"https:\u002F\u002Fmyapp.com\u002Fconfirm",[532,6123,589],{"class":549},[532,6125,6127],{"class":534,"line":6126},137,[532,6128,4428],{"class":549},[532,6130,6132,6134],{"class":534,"line":6131},138,[532,6133,1659],{"class":549},[532,6135,1203],{"class":560},[532,6137,6139],{"class":534,"line":6138},139,[532,6140,596],{"emptyLinePlaceholder":595},[532,6142,6144],{"class":534,"line":6143},140,[532,6145,6146],{"class":538},"\u002F\u002F Verify OTP (email hoặc phone)\n",[532,6148,6150,6152,6154,6156,6158,6160,6162,6164,6166,6168,6170,6172,6174,6177,6179],{"class":534,"line":6149},141,[532,6151,1364],{"class":1363},[532,6153,1339],{"class":549},[532,6155,1650],{"class":560},[532,6157,1653],{"class":549},[532,6159,1656],{"class":560},[532,6161,1659],{"class":549},[532,6163,1662],{"class":549},[532,6165,1665],{"class":1335},[532,6167,2273],{"class":560},[532,6169,448],{"class":549},[532,6171,2278],{"class":560},[532,6173,448],{"class":549},[532,6175,6176],{"class":1372},"verifyOtp",[532,6178,1197],{"class":560},[532,6180,2288],{"class":549},[532,6182,6184,6186,6188,6190,6192,6194],{"class":534,"line":6183},142,[532,6185,2294],{"class":1756},[532,6187,954],{"class":549},[532,6189,550],{"class":549},[532,6191,2301],{"class":553},[532,6193,557],{"class":549},[532,6195,1388],{"class":549},[532,6197,6199,6201,6203,6205,6208,6210],{"class":534,"line":6198},143,[532,6200,5172],{"class":1756},[532,6202,954],{"class":549},[532,6204,550],{"class":549},[532,6206,6207],{"class":553},"123456",[532,6209,557],{"class":549},[532,6211,1388],{"class":549},[532,6213,6215,6217,6219,6221,6223,6225,6227],{"class":534,"line":6214},144,[532,6216,6071],{"class":1756},[532,6218,954],{"class":549},[532,6220,550],{"class":549},[532,6222,6078],{"class":553},[532,6224,557],{"class":549},[532,6226,1653],{"class":549},[532,6228,6229],{"class":538},"       \u002F\u002F 'signup' | 'magiclink' | 'recovery' | 'invite'\n",[532,6231,6233],{"class":534,"line":6232},145,[532,6234,6235],{"class":538},"                        \u002F\u002F 'email_change' | 'sms' | 'phone_change'\n",[532,6237,6239,6241],{"class":534,"line":6238},146,[532,6240,1659],{"class":549},[532,6242,1203],{"class":560},[532,6244,6246],{"class":534,"line":6245},147,[532,6247,596],{"emptyLinePlaceholder":595},[532,6249,6251],{"class":534,"line":6250},148,[532,6252,6253],{"class":538},"\u002F\u002F Exchange auth code for session (PKCE flow)\n",[532,6255,6257,6259,6261,6263,6265,6267,6269,6271,6273,6275,6277,6279,6281,6284,6286,6288,6291,6293],{"class":534,"line":6256},149,[532,6258,1364],{"class":1363},[532,6260,1339],{"class":549},[532,6262,1650],{"class":560},[532,6264,1653],{"class":549},[532,6266,1656],{"class":560},[532,6268,1659],{"class":549},[532,6270,1662],{"class":549},[532,6272,1665],{"class":1335},[532,6274,2273],{"class":560},[532,6276,448],{"class":549},[532,6278,2278],{"class":560},[532,6280,448],{"class":549},[532,6282,6283],{"class":1372},"exchangeCodeForSession",[532,6285,1197],{"class":560},[532,6287,557],{"class":549},[532,6289,6290],{"class":553},"auth-code-here",[532,6292,557],{"class":549},[532,6294,1203],{"class":560},[532,6296,6298],{"class":534,"line":6297},150,[532,6299,596],{"emptyLinePlaceholder":595},[532,6301,6303],{"class":534,"line":6302},151,[532,6304,6305],{"class":538},"\u002F\u002F Link identity (link Google account vào account đang login)\n",[532,6307,6309,6311,6313,6315,6317,6319,6321,6323,6325,6327,6329,6331,6333,6336,6338],{"class":534,"line":6308},152,[532,6310,1364],{"class":1363},[532,6312,1339],{"class":549},[532,6314,1650],{"class":560},[532,6316,1653],{"class":549},[532,6318,1656],{"class":560},[532,6320,1659],{"class":549},[532,6322,1662],{"class":549},[532,6324,1665],{"class":1335},[532,6326,2273],{"class":560},[532,6328,448],{"class":549},[532,6330,2278],{"class":560},[532,6332,448],{"class":549},[532,6334,6335],{"class":1372},"linkIdentity",[532,6337,1197],{"class":560},[532,6339,2288],{"class":549},[532,6341,6343,6345,6347,6349,6351,6353],{"class":534,"line":6342},153,[532,6344,4827],{"class":1756},[532,6346,954],{"class":549},[532,6348,550],{"class":549},[532,6350,4834],{"class":553},[532,6352,557],{"class":549},[532,6354,1388],{"class":549},[532,6356,6358,6360],{"class":534,"line":6357},154,[532,6359,1659],{"class":549},[532,6361,1203],{"class":560},[532,6363,6365],{"class":534,"line":6364},155,[532,6366,596],{"emptyLinePlaceholder":595},[532,6368,6370],{"class":534,"line":6369},156,[532,6371,6372],{"class":538},"\u002F\u002F Unlink identity\n",[532,6374,6376,6378,6380,6382,6384,6386,6388,6390,6392,6394,6396,6398,6400,6403,6405],{"class":534,"line":6375},157,[532,6377,1364],{"class":1363},[532,6379,1339],{"class":549},[532,6381,1650],{"class":560},[532,6383,1653],{"class":549},[532,6385,1656],{"class":560},[532,6387,1659],{"class":549},[532,6389,1662],{"class":549},[532,6391,1665],{"class":1335},[532,6393,2273],{"class":560},[532,6395,448],{"class":549},[532,6397,2278],{"class":560},[532,6399,448],{"class":549},[532,6401,6402],{"class":1372},"unlinkIdentity",[532,6404,1197],{"class":560},[532,6406,2288],{"class":549},[532,6408,6410,6413,6415,6417,6420],{"class":534,"line":6409},158,[532,6411,6412],{"class":1756},"  identityId",[532,6414,954],{"class":549},[532,6416,550],{"class":549},[532,6418,6419],{"class":553},"identity-uuid",[532,6421,589],{"class":549},[532,6423,6425,6427],{"class":534,"line":6424},159,[532,6426,1659],{"class":549},[532,6428,1203],{"class":560},[532,6430,6432],{"class":534,"line":6431},160,[532,6433,596],{"emptyLinePlaceholder":595},[532,6435,6437],{"class":534,"line":6436},161,[532,6438,6439],{"class":538},"\u002F\u002F Get user identities (linked OAuth accounts)\n",[532,6441,6443,6445,6447,6450,6452,6454,6456,6458,6460,6462,6464,6467],{"class":534,"line":6442},162,[532,6444,1364],{"class":1363},[532,6446,1339],{"class":549},[532,6448,6449],{"class":560}," data ",[532,6451,1659],{"class":549},[532,6453,1662],{"class":549},[532,6455,1665],{"class":1335},[532,6457,2273],{"class":560},[532,6459,448],{"class":549},[532,6461,2278],{"class":560},[532,6463,448],{"class":549},[532,6465,6466],{"class":1372},"getUserIdentities",[532,6468,1996],{"class":560},[532,6470,6472],{"class":534,"line":6471},163,[532,6473,596],{"emptyLinePlaceholder":595},[532,6475,6477],{"class":534,"line":6476},164,[532,6478,6479],{"class":538},"\u002F\u002F ============ MFA (Multi-Factor Authentication - BẬT THEO PROJECT) ============\n",[532,6481,6483],{"class":534,"line":6482},165,[532,6484,596],{"emptyLinePlaceholder":595},[532,6486,6488],{"class":534,"line":6487},166,[532,6489,6490],{"class":538},"\u002F\u002F Enroll MFA factor (TOTP - Time-based One-Time Password)\n",[532,6492,6494,6496,6498,6500,6502,6504,6506,6508,6510,6512,6514,6516,6518,6521,6523,6526,6528],{"class":534,"line":6493},167,[532,6495,1364],{"class":1363},[532,6497,1339],{"class":549},[532,6499,1650],{"class":560},[532,6501,1653],{"class":549},[532,6503,1656],{"class":560},[532,6505,1659],{"class":549},[532,6507,1662],{"class":549},[532,6509,1665],{"class":1335},[532,6511,2273],{"class":560},[532,6513,448],{"class":549},[532,6515,2278],{"class":560},[532,6517,448],{"class":549},[532,6519,6520],{"class":560},"mfa",[532,6522,448],{"class":549},[532,6524,6525],{"class":1372},"enroll",[532,6527,1197],{"class":560},[532,6529,2288],{"class":549},[532,6531,6533,6536,6538,6540,6543,6545],{"class":534,"line":6532},168,[532,6534,6535],{"class":1756},"  factorType",[532,6537,954],{"class":549},[532,6539,550],{"class":549},[532,6541,6542],{"class":553},"totp",[532,6544,557],{"class":549},[532,6546,1388],{"class":549},[532,6548,6550,6553,6555,6557,6560,6562,6564],{"class":534,"line":6549},169,[532,6551,6552],{"class":1756},"  issuer",[532,6554,954],{"class":549},[532,6556,550],{"class":549},[532,6558,6559],{"class":553},"My App",[532,6561,557],{"class":549},[532,6563,1653],{"class":549},[532,6565,6566],{"class":538},"     \u002F\u002F tên hiển thị trong authenticator app\n",[532,6568,6570,6573,6575,6577,6579,6581],{"class":534,"line":6569},170,[532,6571,6572],{"class":1756},"  friendlyName",[532,6574,954],{"class":549},[532,6576,550],{"class":549},[532,6578,2301],{"class":553},[532,6580,557],{"class":549},[532,6582,1388],{"class":549},[532,6584,6586,6588],{"class":534,"line":6585},171,[532,6587,1659],{"class":549},[532,6589,1203],{"class":560},[532,6591,6593],{"class":534,"line":6592},172,[532,6594,6595],{"class":538},"\u002F\u002F data.totp.qr_code — base64 QR code image\n",[532,6597,6599],{"class":534,"line":6598},173,[532,6600,6601],{"class":538},"\u002F\u002F data.totp.secret — secret key\n",[532,6603,6605],{"class":534,"line":6604},174,[532,6606,6607],{"class":538},"\u002F\u002F data.totp.uri — otpauth:\u002F\u002F URI\n",[532,6609,6611],{"class":534,"line":6610},175,[532,6612,596],{"emptyLinePlaceholder":595},[532,6614,6616],{"class":534,"line":6615},176,[532,6617,6618],{"class":538},"\u002F\u002F Challenge — tạo challenge để verify\n",[532,6620,6622,6624,6626,6628,6630,6632,6634,6636,6638,6640,6642,6644,6646,6648,6650,6653,6655],{"class":534,"line":6621},177,[532,6623,1364],{"class":1363},[532,6625,1339],{"class":549},[532,6627,1650],{"class":560},[532,6629,1653],{"class":549},[532,6631,1656],{"class":560},[532,6633,1659],{"class":549},[532,6635,1662],{"class":549},[532,6637,1665],{"class":1335},[532,6639,2273],{"class":560},[532,6641,448],{"class":549},[532,6643,2278],{"class":560},[532,6645,448],{"class":549},[532,6647,6520],{"class":560},[532,6649,448],{"class":549},[532,6651,6652],{"class":1372},"challenge",[532,6654,1197],{"class":560},[532,6656,2288],{"class":549},[532,6658,6660,6663,6665,6667,6670,6672],{"class":534,"line":6659},178,[532,6661,6662],{"class":1756},"  factorId",[532,6664,954],{"class":549},[532,6666,550],{"class":549},[532,6668,6669],{"class":553},"factor-uuid-from-enroll",[532,6671,557],{"class":549},[532,6673,1388],{"class":549},[532,6675,6677,6679],{"class":534,"line":6676},179,[532,6678,1659],{"class":549},[532,6680,1203],{"class":560},[532,6682,6684],{"class":534,"line":6683},180,[532,6685,6686],{"class":538},"\u002F\u002F data.id — challenge ID, dùng trong verify\n",[532,6688,6690],{"class":534,"line":6689},181,[532,6691,596],{"emptyLinePlaceholder":595},[532,6693,6695],{"class":534,"line":6694},182,[532,6696,6697],{"class":538},"\u002F\u002F Verify — xác nhận TOTP code\n",[532,6699,6701,6703,6705,6707,6709,6711,6713,6715,6717,6719,6721,6723,6725,6727,6729,6732,6734],{"class":534,"line":6700},183,[532,6702,1364],{"class":1363},[532,6704,1339],{"class":549},[532,6706,1650],{"class":560},[532,6708,1653],{"class":549},[532,6710,1656],{"class":560},[532,6712,1659],{"class":549},[532,6714,1662],{"class":549},[532,6716,1665],{"class":1335},[532,6718,2273],{"class":560},[532,6720,448],{"class":549},[532,6722,2278],{"class":560},[532,6724,448],{"class":549},[532,6726,6520],{"class":560},[532,6728,448],{"class":549},[532,6730,6731],{"class":1372},"verify",[532,6733,1197],{"class":560},[532,6735,2288],{"class":549},[532,6737,6739,6741,6743,6745,6748,6750],{"class":534,"line":6738},184,[532,6740,6662],{"class":1756},[532,6742,954],{"class":549},[532,6744,550],{"class":549},[532,6746,6747],{"class":553},"factor-uuid",[532,6749,557],{"class":549},[532,6751,1388],{"class":549},[532,6753,6755,6758,6760,6762,6765,6767],{"class":534,"line":6754},185,[532,6756,6757],{"class":1756},"  challengeId",[532,6759,954],{"class":549},[532,6761,550],{"class":549},[532,6763,6764],{"class":553},"challenge-id",[532,6766,557],{"class":549},[532,6768,1388],{"class":549},[532,6770,6772,6775,6777,6779,6781,6783],{"class":534,"line":6771},186,[532,6773,6774],{"class":1756},"  code",[532,6776,954],{"class":549},[532,6778,550],{"class":549},[532,6780,6207],{"class":553},[532,6782,557],{"class":549},[532,6784,1388],{"class":549},[532,6786,6788,6790],{"class":534,"line":6787},187,[532,6789,1659],{"class":549},[532,6791,1203],{"class":560},[532,6793,6795],{"class":534,"line":6794},188,[532,6796,596],{"emptyLinePlaceholder":595},[532,6798,6800],{"class":534,"line":6799},189,[532,6801,6802],{"class":538},"\u002F\u002F Unenroll — gỡ bỏ MFA\n",[532,6804,6806,6808,6810,6812,6814,6816,6818,6820,6822,6824,6826,6828,6830,6832,6834,6837,6839],{"class":534,"line":6805},190,[532,6807,1364],{"class":1363},[532,6809,1339],{"class":549},[532,6811,1650],{"class":560},[532,6813,1653],{"class":549},[532,6815,1656],{"class":560},[532,6817,1659],{"class":549},[532,6819,1662],{"class":549},[532,6821,1665],{"class":1335},[532,6823,2273],{"class":560},[532,6825,448],{"class":549},[532,6827,2278],{"class":560},[532,6829,448],{"class":549},[532,6831,6520],{"class":560},[532,6833,448],{"class":549},[532,6835,6836],{"class":1372},"unenroll",[532,6838,1197],{"class":560},[532,6840,2288],{"class":549},[532,6842,6844,6846,6848,6850,6852,6854],{"class":534,"line":6843},191,[532,6845,6662],{"class":1756},[532,6847,954],{"class":549},[532,6849,550],{"class":549},[532,6851,6747],{"class":553},[532,6853,557],{"class":549},[532,6855,1388],{"class":549},[532,6857,6859,6861],{"class":534,"line":6858},192,[532,6860,1659],{"class":549},[532,6862,1203],{"class":560},[532,6864,6866],{"class":534,"line":6865},193,[532,6867,596],{"emptyLinePlaceholder":595},[532,6869,6871],{"class":534,"line":6870},194,[532,6872,6873],{"class":538},"\u002F\u002F List enrolled factors\n",[532,6875,6877,6879,6881,6883,6885,6887,6889,6891,6893,6895,6897,6899,6901,6904],{"class":534,"line":6876},195,[532,6878,1364],{"class":1363},[532,6880,1339],{"class":549},[532,6882,6449],{"class":560},[532,6884,1659],{"class":549},[532,6886,1662],{"class":549},[532,6888,1665],{"class":1335},[532,6890,2273],{"class":560},[532,6892,448],{"class":549},[532,6894,2278],{"class":560},[532,6896,448],{"class":549},[532,6898,6520],{"class":560},[532,6900,448],{"class":549},[532,6902,6903],{"class":1372},"listFactors",[532,6905,1996],{"class":560},[532,6907,6909],{"class":534,"line":6908},196,[532,6910,6911],{"class":538},"\u002F\u002F data.all — tất cả factors\n",[532,6913,6915],{"class":534,"line":6914},197,[532,6916,6917],{"class":538},"\u002F\u002F data.totp — chỉ TOTP factors\n",[532,6919,6921],{"class":534,"line":6920},198,[532,6922,6923],{"class":538},"\u002F\u002F data.phone — chỉ phone factors (nếu bật)\n",[532,6925,6927],{"class":534,"line":6926},199,[532,6928,596],{"emptyLinePlaceholder":595},[532,6930,6932],{"class":534,"line":6931},200,[532,6933,6934],{"class":538},"\u002F\u002F Get authenticator assurance level (aal)\n",[532,6936,6938,6940,6942,6944,6946,6948,6950,6952,6954,6956,6958,6960,6962,6965],{"class":534,"line":6937},201,[532,6939,1364],{"class":1363},[532,6941,1339],{"class":549},[532,6943,6449],{"class":560},[532,6945,1659],{"class":549},[532,6947,1662],{"class":549},[532,6949,1665],{"class":1335},[532,6951,2273],{"class":560},[532,6953,448],{"class":549},[532,6955,2278],{"class":560},[532,6957,448],{"class":549},[532,6959,6520],{"class":560},[532,6961,448],{"class":549},[532,6963,6964],{"class":1372},"getAuthenticatorAssuranceLevel",[532,6966,1996],{"class":560},[532,6968,6970],{"class":534,"line":6969},202,[532,6971,6972],{"class":538},"\u002F\u002F data.currentLevel — 'aal1' | 'aal2'\n",[532,6974,6976],{"class":534,"line":6975},203,[532,6977,6978],{"class":538},"\u002F\u002F data.nextLevel — level tiếp theo cần đạt\n",[532,6980,6982],{"class":534,"line":6981},204,[532,6983,6984],{"class":538},"\u002F\u002F data.currentAuthenticationMethods — array of methods đã dùng\n",[532,6986,6988],{"class":534,"line":6987},205,[532,6989,596],{"emptyLinePlaceholder":595},[532,6991,6993],{"class":534,"line":6992},206,[532,6994,6995],{"class":538},"\u002F\u002F ============ AUTH ADMIN (service_role key required) ============\n",[532,6997,6999],{"class":534,"line":6998},207,[532,7000,7001],{"class":538},"\u002F\u002F Dùng supabaseAdmin client với SERVICE_ROLE_KEY\n",[532,7003,7005],{"class":534,"line":7004},208,[532,7006,596],{"emptyLinePlaceholder":595},[532,7008,7010],{"class":534,"line":7009},209,[532,7011,7012],{"class":538},"\u002F\u002F Tạo user mới (không cần email verification)\n",[532,7014,7016,7018,7020,7022,7024,7026,7028,7030,7032,7035,7037,7039,7041,7044,7046,7049,7051],{"class":534,"line":7015},210,[532,7017,1364],{"class":1363},[532,7019,1339],{"class":549},[532,7021,1650],{"class":560},[532,7023,1653],{"class":549},[532,7025,1656],{"class":560},[532,7027,1659],{"class":549},[532,7029,1662],{"class":549},[532,7031,1665],{"class":1335},[532,7033,7034],{"class":560}," supabaseAdmin",[532,7036,448],{"class":549},[532,7038,2278],{"class":560},[532,7040,448],{"class":549},[532,7042,7043],{"class":560},"admin",[532,7045,448],{"class":549},[532,7047,7048],{"class":1372},"createUser",[532,7050,1197],{"class":560},[532,7052,2288],{"class":549},[532,7054,7056,7058,7060,7062,7065,7067],{"class":534,"line":7055},211,[532,7057,2294],{"class":1756},[532,7059,954],{"class":549},[532,7061,550],{"class":549},[532,7063,7064],{"class":553},"newuser@example.com",[532,7066,557],{"class":549},[532,7068,1388],{"class":549},[532,7070,7072,7074,7076,7078,7081,7083],{"class":534,"line":7071},212,[532,7073,2311],{"class":1756},[532,7075,954],{"class":549},[532,7077,550],{"class":549},[532,7079,7080],{"class":553},"password123",[532,7082,557],{"class":549},[532,7084,1388],{"class":549},[532,7086,7088,7091,7093,7095,7097],{"class":534,"line":7087},213,[532,7089,7090],{"class":1756},"  email_confirm",[532,7092,954],{"class":549},[532,7094,2922],{"class":1762},[532,7096,1653],{"class":549},[532,7098,7099],{"class":538},"          \u002F\u002F auto-confirm email\n",[532,7101,7103,7105,7107,7109,7111,7113],{"class":534,"line":7102},214,[532,7104,4659],{"class":1756},[532,7106,954],{"class":549},[532,7108,550],{"class":549},[532,7110,4666],{"class":553},[532,7112,557],{"class":549},[532,7114,1388],{"class":549},[532,7116,7118,7121,7123,7125,7127],{"class":534,"line":7117},215,[532,7119,7120],{"class":1756},"  phone_confirm",[532,7122,954],{"class":549},[532,7124,2922],{"class":1762},[532,7126,1653],{"class":549},[532,7128,7129],{"class":538},"          \u002F\u002F auto-confirm phone\n",[532,7131,7133,7136,7138,7140,7142,7144,7146,7149,7151],{"class":534,"line":7132},216,[532,7134,7135],{"class":1756},"  user_metadata",[532,7137,954],{"class":549},[532,7139,1339],{"class":549},[532,7141,4376],{"class":1756},[532,7143,954],{"class":549},[532,7145,550],{"class":549},[532,7147,7148],{"class":553},"Admin Created User",[532,7150,557],{"class":549},[532,7152,2437],{"class":549},[532,7154,7156,7159,7161,7163,7165,7167,7169,7171,7173],{"class":534,"line":7155},217,[532,7157,7158],{"class":1756},"  app_metadata",[532,7160,954],{"class":549},[532,7162,1339],{"class":549},[532,7164,4390],{"class":1756},[532,7166,954],{"class":549},[532,7168,550],{"class":549},[532,7170,7043],{"class":553},[532,7172,557],{"class":549},[532,7174,2437],{"class":549},[532,7176,7178,7180],{"class":534,"line":7177},218,[532,7179,1659],{"class":549},[532,7181,1203],{"class":560},[532,7183,7185],{"class":534,"line":7184},219,[532,7186,596],{"emptyLinePlaceholder":595},[532,7188,7190],{"class":534,"line":7189},220,[532,7191,7192],{"class":538},"\u002F\u002F Xóa user\n",[532,7194,7196,7198,7200,7202,7204,7206,7208,7210,7212,7214,7216,7218,7220,7222,7224,7227,7229,7231,7234,7236],{"class":534,"line":7195},221,[532,7197,1364],{"class":1363},[532,7199,1339],{"class":549},[532,7201,1650],{"class":560},[532,7203,1653],{"class":549},[532,7205,1656],{"class":560},[532,7207,1659],{"class":549},[532,7209,1662],{"class":549},[532,7211,1665],{"class":1335},[532,7213,7034],{"class":560},[532,7215,448],{"class":549},[532,7217,2278],{"class":560},[532,7219,448],{"class":549},[532,7221,7043],{"class":560},[532,7223,448],{"class":549},[532,7225,7226],{"class":1372},"deleteUser",[532,7228,1197],{"class":560},[532,7230,557],{"class":549},[532,7232,7233],{"class":553},"user-uuid",[532,7235,557],{"class":549},[532,7237,1203],{"class":560},[532,7239,7241],{"class":534,"line":7240},222,[532,7242,7243],{"class":538},"\u002F\u002F Xóa user + xóa luôn database identity\n",[532,7245,7247,7249,7251,7253,7255,7257,7259,7261,7263,7265,7267,7269,7271,7273,7275,7277,7279,7281,7283,7285,7287,7289],{"class":534,"line":7246},223,[532,7248,1364],{"class":1363},[532,7250,1339],{"class":549},[532,7252,1650],{"class":560},[532,7254,1653],{"class":549},[532,7256,1656],{"class":560},[532,7258,1659],{"class":549},[532,7260,1662],{"class":549},[532,7262,1665],{"class":1335},[532,7264,7034],{"class":560},[532,7266,448],{"class":549},[532,7268,2278],{"class":560},[532,7270,448],{"class":549},[532,7272,7043],{"class":560},[532,7274,448],{"class":549},[532,7276,7226],{"class":1372},[532,7278,1197],{"class":560},[532,7280,557],{"class":549},[532,7282,7233],{"class":553},[532,7284,557],{"class":549},[532,7286,1653],{"class":549},[532,7288,2922],{"class":1762},[532,7290,1203],{"class":560},[532,7292,7294],{"class":534,"line":7293},224,[532,7295,596],{"emptyLinePlaceholder":595},[532,7297,7299],{"class":534,"line":7298},225,[532,7300,7301],{"class":538},"\u002F\u002F Update user by ID\n",[532,7303,7305,7307,7309,7311,7313,7315,7317,7319,7321,7323,7325,7327,7329,7331,7333,7336],{"class":534,"line":7304},226,[532,7306,1364],{"class":1363},[532,7308,1339],{"class":549},[532,7310,1650],{"class":560},[532,7312,1653],{"class":549},[532,7314,1656],{"class":560},[532,7316,1659],{"class":549},[532,7318,1662],{"class":549},[532,7320,1665],{"class":1335},[532,7322,7034],{"class":560},[532,7324,448],{"class":549},[532,7326,2278],{"class":560},[532,7328,448],{"class":549},[532,7330,7043],{"class":560},[532,7332,448],{"class":549},[532,7334,7335],{"class":1372},"updateUserById",[532,7337,1375],{"class":560},[532,7339,7341,7343,7345,7347],{"class":534,"line":7340},227,[532,7342,1380],{"class":549},[532,7344,7233],{"class":553},[532,7346,557],{"class":549},[532,7348,1388],{"class":549},[532,7350,7352],{"class":534,"line":7351},228,[532,7353,7354],{"class":549},"  {\n",[532,7356,7358,7361,7363,7365,7368,7370],{"class":534,"line":7357},229,[532,7359,7360],{"class":1756},"    email",[532,7362,954],{"class":549},[532,7364,550],{"class":549},[532,7366,7367],{"class":553},"updated@example.com",[532,7369,557],{"class":549},[532,7371,1388],{"class":549},[532,7373,7375,7378,7380,7382,7384,7386],{"class":534,"line":7374},230,[532,7376,7377],{"class":1756},"    password",[532,7379,954],{"class":549},[532,7381,550],{"class":549},[532,7383,5850],{"class":553},[532,7385,557],{"class":549},[532,7387,1388],{"class":549},[532,7389,7391,7394,7396,7398],{"class":534,"line":7390},231,[532,7392,7393],{"class":1756},"    email_confirm",[532,7395,954],{"class":549},[532,7397,2922],{"class":1762},[532,7399,1388],{"class":549},[532,7401,7403,7406,7408,7410,7413,7415,7417],{"class":534,"line":7402},232,[532,7404,7405],{"class":1756},"    user_metadata",[532,7407,954],{"class":549},[532,7409,1339],{"class":549},[532,7411,7412],{"class":1756}," verified",[532,7414,954],{"class":549},[532,7416,2922],{"class":1762},[532,7418,2437],{"class":549},[532,7420,7422,7425,7427,7429,7432,7434,7436,7439,7441],{"class":534,"line":7421},233,[532,7423,7424],{"class":1756},"    app_metadata",[532,7426,954],{"class":549},[532,7428,1339],{"class":549},[532,7430,7431],{"class":1756}," plan",[532,7433,954],{"class":549},[532,7435,550],{"class":549},[532,7437,7438],{"class":553},"pro",[532,7440,557],{"class":549},[532,7442,2437],{"class":549},[532,7444,7446,7449,7451,7454],{"class":534,"line":7445},234,[532,7447,7448],{"class":1756},"    ban_duration",[532,7450,954],{"class":549},[532,7452,7453],{"class":549}," null,",[532,7455,7456],{"class":538},"          \u002F\u002F unban user: null = không ban\n",[532,7458,7460],{"class":534,"line":7459},235,[532,7461,7462],{"class":538},"                                 \u002F\u002F '24h' = ban 24 giờ\n",[532,7464,7466],{"class":534,"line":7465},236,[532,7467,7468],{"class":538},"                                 \u002F\u002F 'none' = ban vĩnh viễn\n",[532,7470,7472],{"class":534,"line":7471},237,[532,7473,4428],{"class":549},[532,7475,7477],{"class":534,"line":7476},238,[532,7478,1203],{"class":560},[532,7480,7482],{"class":534,"line":7481},239,[532,7483,596],{"emptyLinePlaceholder":595},[532,7485,7487],{"class":534,"line":7486},240,[532,7488,7489],{"class":538},"\u002F\u002F Get user by ID\n",[532,7491,7493,7495,7497,7499,7501,7503,7505,7507,7509,7511,7513,7515,7517,7519,7521,7524,7526,7528,7530,7532],{"class":534,"line":7492},241,[532,7494,1364],{"class":1363},[532,7496,1339],{"class":549},[532,7498,1650],{"class":560},[532,7500,1653],{"class":549},[532,7502,1656],{"class":560},[532,7504,1659],{"class":549},[532,7506,1662],{"class":549},[532,7508,1665],{"class":1335},[532,7510,7034],{"class":560},[532,7512,448],{"class":549},[532,7514,2278],{"class":560},[532,7516,448],{"class":549},[532,7518,7043],{"class":560},[532,7520,448],{"class":549},[532,7522,7523],{"class":1372},"getUserById",[532,7525,1197],{"class":560},[532,7527,557],{"class":549},[532,7529,7233],{"class":553},[532,7531,557],{"class":549},[532,7533,1203],{"class":560},[532,7535,7537],{"class":534,"line":7536},242,[532,7538,596],{"emptyLinePlaceholder":595},[532,7540,7542],{"class":534,"line":7541},243,[532,7543,7544],{"class":538},"\u002F\u002F List users (có phân trang)\n",[532,7546,7548,7550,7552,7554,7556,7558,7560,7562,7564,7566,7568,7570,7572,7574,7576,7579,7581],{"class":534,"line":7547},244,[532,7549,1364],{"class":1363},[532,7551,1339],{"class":549},[532,7553,1650],{"class":560},[532,7555,1653],{"class":549},[532,7557,1656],{"class":560},[532,7559,1659],{"class":549},[532,7561,1662],{"class":549},[532,7563,1665],{"class":1335},[532,7565,7034],{"class":560},[532,7567,448],{"class":549},[532,7569,2278],{"class":560},[532,7571,448],{"class":549},[532,7573,7043],{"class":560},[532,7575,448],{"class":549},[532,7577,7578],{"class":1372},"listUsers",[532,7580,1197],{"class":560},[532,7582,2288],{"class":549},[532,7584,7586,7589,7591,7593],{"class":534,"line":7585},245,[532,7587,7588],{"class":1756},"  page",[532,7590,954],{"class":549},[532,7592,1985],{"class":1782},[532,7594,1388],{"class":549},[532,7596,7598,7601,7603,7606],{"class":534,"line":7597},246,[532,7599,7600],{"class":1756},"  perPage",[532,7602,954],{"class":549},[532,7604,7605],{"class":1782}," 50",[532,7607,1388],{"class":549},[532,7609,7611,7613],{"class":534,"line":7610},247,[532,7612,1659],{"class":549},[532,7614,1203],{"class":560},[532,7616,7618],{"class":534,"line":7617},248,[532,7619,596],{"emptyLinePlaceholder":595},[532,7621,7623],{"class":534,"line":7622},249,[532,7624,7625],{"class":538},"\u002F\u002F Invite user by email\n",[532,7627,7629,7631,7633,7635,7637,7639,7641,7643,7645,7647,7649,7651,7653,7655,7657,7660],{"class":534,"line":7628},250,[532,7630,1364],{"class":1363},[532,7632,1339],{"class":549},[532,7634,1650],{"class":560},[532,7636,1653],{"class":549},[532,7638,1656],{"class":560},[532,7640,1659],{"class":549},[532,7642,1662],{"class":549},[532,7644,1665],{"class":1335},[532,7646,7034],{"class":560},[532,7648,448],{"class":549},[532,7650,2278],{"class":560},[532,7652,448],{"class":549},[532,7654,7043],{"class":560},[532,7656,448],{"class":549},[532,7658,7659],{"class":1372},"inviteUserByEmail",[532,7661,1375],{"class":560},[532,7663,7665,7667,7669,7671],{"class":534,"line":7664},251,[532,7666,1380],{"class":549},[532,7668,7064],{"class":553},[532,7670,557],{"class":549},[532,7672,1388],{"class":549},[532,7674,7676,7678,7680,7682,7684,7686,7688],{"class":534,"line":7675},252,[532,7677,5958],{"class":549},[532,7679,5961],{"class":1756},[532,7681,954],{"class":549},[532,7683,550],{"class":549},[532,7685,4416],{"class":553},[532,7687,557],{"class":549},[532,7689,2653],{"class":549},[532,7691,7693],{"class":534,"line":7692},253,[532,7694,1203],{"class":560},[532,7696,7698],{"class":534,"line":7697},254,[532,7699,596],{"emptyLinePlaceholder":595},[532,7701,7703],{"class":534,"line":7702},255,[532,7704,7705],{"class":538},"\u002F\u002F Generate link (signup confirmation, password reset, email change, magic link)\n",[532,7707,7709,7711,7713,7715,7717,7719,7721,7723,7725,7727,7729,7731,7733,7735,7737,7740,7742],{"class":534,"line":7708},256,[532,7710,1364],{"class":1363},[532,7712,1339],{"class":549},[532,7714,1650],{"class":560},[532,7716,1653],{"class":549},[532,7718,1656],{"class":560},[532,7720,1659],{"class":549},[532,7722,1662],{"class":549},[532,7724,1665],{"class":1335},[532,7726,7034],{"class":560},[532,7728,448],{"class":549},[532,7730,2278],{"class":560},[532,7732,448],{"class":549},[532,7734,7043],{"class":560},[532,7736,448],{"class":549},[532,7738,7739],{"class":1372},"generateLink",[532,7741,1197],{"class":560},[532,7743,2288],{"class":549},[532,7745,7747,7749,7751,7753,7755,7757,7759],{"class":534,"line":7746},257,[532,7748,6071],{"class":1756},[532,7750,954],{"class":549},[532,7752,550],{"class":549},[532,7754,6078],{"class":553},[532,7756,557],{"class":549},[532,7758,1653],{"class":549},[532,7760,7761],{"class":538},"              \u002F\u002F 'signup' | 'magiclink' | 'recovery' | 'email_change_current'\n",[532,7763,7765],{"class":534,"line":7764},258,[532,7766,7767],{"class":538},"                                \u002F\u002F | 'email_change_new' | 'invite'\n",[532,7769,7771,7773,7775,7777,7779,7781],{"class":534,"line":7770},259,[532,7772,2294],{"class":1756},[532,7774,954],{"class":549},[532,7776,550],{"class":549},[532,7778,2301],{"class":553},[532,7780,557],{"class":549},[532,7782,1388],{"class":549},[532,7784,7786,7788,7790,7792,7795,7797,7799],{"class":534,"line":7785},260,[532,7787,2311],{"class":1756},[532,7789,954],{"class":549},[532,7791,550],{"class":549},[532,7793,7794],{"class":553},"optional-password",[532,7796,557],{"class":549},[532,7798,1653],{"class":549},[532,7800,7801],{"class":538}," \u002F\u002F chỉ cần cho signup\n",[532,7803,7805,7808,7810,7812,7815,7817,7819],{"class":534,"line":7804},261,[532,7806,7807],{"class":1756},"  newEmail",[532,7809,954],{"class":549},[532,7811,550],{"class":549},[532,7813,7814],{"class":553},"new@example.com",[532,7816,557],{"class":549},[532,7818,1653],{"class":549},[532,7820,7821],{"class":538},"  \u002F\u002F chỉ cần cho email_change_new\n",[532,7823,7825,7828,7830,7832,7835,7837],{"class":534,"line":7824},262,[532,7826,7827],{"class":1756},"  redirectTo",[532,7829,954],{"class":549},[532,7831,550],{"class":549},[532,7833,7834],{"class":553},"https:\u002F\u002Fmyapp.com\u002Fcallback",[532,7836,557],{"class":549},[532,7838,1388],{"class":549},[532,7840,7842,7844,7846,7848,7851,7853,7855,7858,7860,7862],{"class":534,"line":7841},263,[532,7843,5860],{"class":1756},[532,7845,954],{"class":549},[532,7847,1339],{"class":549},[532,7849,7850],{"class":1756}," custom_key",[532,7852,954],{"class":549},[532,7854,550],{"class":549},[532,7856,7857],{"class":553},"value",[532,7859,557],{"class":549},[532,7861,2075],{"class":549},[532,7863,7864],{"class":538}," \u002F\u002F metadata\n",[532,7866,7868,7870],{"class":534,"line":7867},264,[532,7869,1659],{"class":549},[532,7871,1203],{"class":560},[532,7873,7875],{"class":534,"line":7874},265,[532,7876,596],{"emptyLinePlaceholder":595},[532,7878,7880],{"class":534,"line":7879},266,[532,7881,7882],{"class":538},"\u002F\u002F Delete factor (MFA) for a user\n",[532,7884,7886,7888,7890,7892,7894,7896,7898,7900,7902,7904,7906,7908,7910,7912,7914,7917],{"class":534,"line":7885},267,[532,7887,1364],{"class":1363},[532,7889,1339],{"class":549},[532,7891,1650],{"class":560},[532,7893,1653],{"class":549},[532,7895,1656],{"class":560},[532,7897,1659],{"class":549},[532,7899,1662],{"class":549},[532,7901,1665],{"class":1335},[532,7903,7034],{"class":560},[532,7905,448],{"class":549},[532,7907,2278],{"class":560},[532,7909,448],{"class":549},[532,7911,7043],{"class":560},[532,7913,448],{"class":549},[532,7915,7916],{"class":1372},"deleteFactor",[532,7918,1375],{"class":560},[532,7920,7922,7924,7926,7928],{"class":534,"line":7921},268,[532,7923,1380],{"class":549},[532,7925,7233],{"class":553},[532,7927,557],{"class":549},[532,7929,1388],{"class":549},[532,7931,7933,7935,7937],{"class":534,"line":7932},269,[532,7934,1380],{"class":549},[532,7936,6747],{"class":553},[532,7938,589],{"class":549},[532,7940,7942],{"class":534,"line":7941},270,[532,7943,1203],{"class":560},[532,7945,7947],{"class":534,"line":7946},271,[532,7948,596],{"emptyLinePlaceholder":595},[532,7950,7952],{"class":534,"line":7951},272,[532,7953,7954],{"class":538},"\u002F\u002F Get factors for a user\n",[532,7956,7958,7960,7962,7964,7966,7968,7970,7972,7974,7976,7978,7980,7982,7984,7986,7988,7990,7992,7994,7996],{"class":534,"line":7957},273,[532,7959,1364],{"class":1363},[532,7961,1339],{"class":549},[532,7963,1650],{"class":560},[532,7965,1653],{"class":549},[532,7967,1656],{"class":560},[532,7969,1659],{"class":549},[532,7971,1662],{"class":549},[532,7973,1665],{"class":1335},[532,7975,7034],{"class":560},[532,7977,448],{"class":549},[532,7979,2278],{"class":560},[532,7981,448],{"class":549},[532,7983,7043],{"class":560},[532,7985,448],{"class":549},[532,7987,6903],{"class":1372},[532,7989,1197],{"class":560},[532,7991,557],{"class":549},[532,7993,7233],{"class":553},[532,7995,557],{"class":549},[532,7997,1203],{"class":560},[532,7999,8001],{"class":534,"line":8000},274,[532,8002,596],{"emptyLinePlaceholder":595},[532,8004,8006],{"class":534,"line":8005},275,[532,8007,8008],{"class":538},"\u002F\u002F Send OTP code (SMS)\n",[532,8010,8012,8014,8016,8018,8020,8022,8024,8026,8028,8030,8032,8034,8036,8038,8040,8043,8045],{"class":534,"line":8011},276,[532,8013,1364],{"class":1363},[532,8015,1339],{"class":549},[532,8017,1650],{"class":560},[532,8019,1653],{"class":549},[532,8021,1656],{"class":560},[532,8023,1659],{"class":549},[532,8025,1662],{"class":549},[532,8027,1665],{"class":1335},[532,8029,7034],{"class":560},[532,8031,448],{"class":549},[532,8033,2278],{"class":560},[532,8035,448],{"class":549},[532,8037,7043],{"class":560},[532,8039,448],{"class":549},[532,8041,8042],{"class":1372},"sendOtpCode",[532,8044,1197],{"class":560},[532,8046,2288],{"class":549},[532,8048,8050,8052,8054,8056,8058,8060],{"class":534,"line":8049},277,[532,8051,4659],{"class":1756},[532,8053,954],{"class":549},[532,8055,550],{"class":549},[532,8057,4666],{"class":553},[532,8059,557],{"class":549},[532,8061,1388],{"class":549},[532,8063,8065,8067,8069,8071,8073],{"class":534,"line":8064},278,[532,8066,6071],{"class":1756},[532,8068,954],{"class":549},[532,8070,550],{"class":549},[532,8072,4688],{"class":553},[532,8074,589],{"class":549},[532,8076,8078,8080],{"class":534,"line":8077},279,[532,8079,1659],{"class":549},[532,8081,1203],{"class":560},[450,8083,8085],{"id":8084},"storage-methods-đầy-đủ","Storage Methods — đầy đủ",[523,8087,8089],{"className":1326,"code":8088,"language":1328,"meta":528,"style":528},"\u002F\u002F ============ BUCKET MANAGEMENT ============\nconst { data, error } = await supabase.storage.createBucket('avatars', {\n  public: true,                     \u002F\u002F bucket public\n  fileSizeLimit: 5242880,           \u002F\u002F 5MB limit\n  allowedMimeTypes: ['image\u002Fpng', 'image\u002Fjpeg'],\n})\nconst { data, error } = await supabase.storage.getBucket('avatars')\nconst { data, error } = await supabase.storage.listBuckets()\nconst { data, error } = await supabase.storage.updateBucket('avatars', {\n  public: false,                    \u002F\u002F chuyển sang private\n  fileSizeLimit: 10485760,          \u002F\u002F tăng lên 10MB\n})\nconst { data, error } = await supabase.storage.deleteBucket('avatars')\nconst { data, error } = await supabase.storage.emptyBucket('avatars') \u002F\u002F xóa tất cả files\n\n\u002F\u002F ============ FILE OPERATIONS (from bucket) ============\nconst bucket = supabase.storage.from('avatars')\n\n\u002F\u002F Upload file\nconst { data, error } = await bucket.upload('public\u002Fuser1.png', file, {\n  cacheControl: '3600',             \u002F\u002F Cache-Control header\n  contentType: 'image\u002Fpng',         \u002F\u002F Content-Type (auto-detect nếu không set)\n  upsert: true,                     \u002F\u002F overwrite nếu đã tồn tại\n  duplex: 'half',                   \u002F\u002F streaming upload\n})\n\n\u002F\u002F Upload với metadata\nconst { data, error } = await bucket.upload('public\u002Fuser1.png', file, {\n  metadata: {\n    owner: 'user-uuid',\n    uploadedAt: new Date().toISOString(),\n  }\n})\n\n\u002F\u002F Download file\nconst { data, error } = await bucket.download('public\u002Fuser1.png')\n\u002F\u002F data là Blob (browser) hoặc ArrayBuffer (Node.js)\n\n\u002F\u002F Get public URL (chỉ hoạt động nếu bucket public)\nconst { data } = bucket.getPublicUrl('public\u002Fuser1.png')\n\u002F\u002F data.publicUrl — https:\u002F\u002F[REF].supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Favatars\u002Fpublic\u002Fuser1.png\n\n\u002F\u002F Create signed URL (có thời hạn, dùng cho private bucket)\nconst { data, error } = await bucket.createSignedUrl('private\u002Fuser1.png', 60)\n\u002F\u002F data.signedUrl — link hết hạn sau 60 giây\n\n\u002F\u002F Create signed upload URL (cho phép upload trực tiếp từ client)\nconst { data, error } = await bucket.createSignedUploadUrl('uploads\u002Ffile.png')\n\n\u002F\u002F List files trong folder\nconst { data, error } = await bucket.list('public', {\n  limit: 100,\n  offset: 0,\n  sortBy: { column: 'name', order: 'asc' },\n})\n\n\u002F\u002F Move\u002Frename file\nconst { data, error } = await bucket.move('public\u002Fuser1.png', 'public\u002Frenamed.png')\n\n\u002F\u002F Copy file\nconst { data, error } = await bucket.copy('public\u002Fuser1.png', 'backup\u002Fuser1.png')\n\n\u002F\u002F Remove files (có thể xóa nhiều file cùng lúc)\nconst { data, error } = await bucket.remove(['public\u002Fuser1.png', 'public\u002Fuser2.png'])\n\n\u002F\u002F Update file (upsert = true để ghi đè, false để tạo mới)\nconst { data, error } = await bucket.update('public\u002Fuser1.png', newFile, {\n  upsert: true,\n})\n\n\u002F\u002F Create signed URLs (nhiều file)\nconst { data, error } = await bucket.createSignedUrls(\n  ['file1.png', 'file2.png'],\n  3600 \u002F\u002F 1 giờ\n)\n\n\u002F\u002F Get file info\nconst { data, error } = await bucket.info('public\u002Fuser1.png')\n\n\u002F\u002F Check file exists\nconst { data, error } = await bucket.exists('public\u002Fuser1.png')\n\n\u002F\u002F Upload file từ URL (server-side)\nconst { data, error } = await bucket.upload('public\u002Fremote.png',\n  await fetch('https:\u002F\u002Fexample.com\u002Fimage.png').then(r => r.blob())\n)\n",[445,8090,8091,8096,8138,8152,8167,8197,8203,8242,8273,8314,8327,8341,8347,8386,8428,8432,8437,8466,8470,8475,8518,8537,8555,8569,8588,8594,8598,8603,8643,8652,8667,8692,8696,8702,8706,8711,8746,8751,8755,8760,8789,8794,8798,8803,8844,8849,8853,8858,8894,8898,8903,8940,8952,8964,9000,9006,9010,9015,9059,9063,9068,9112,9116,9121,9167,9171,9176,9217,9227,9233,9237,9242,9269,9294,9302,9306,9310,9315,9350,9354,9359,9394,9398,9403,9438,9480],{"__ignoreMap":528},[532,8092,8093],{"class":534,"line":535},[532,8094,8095],{"class":538},"\u002F\u002F ============ BUCKET MANAGEMENT ============\n",[532,8097,8098,8100,8102,8104,8106,8108,8110,8112,8114,8116,8118,8121,8123,8126,8128,8130,8132,8134,8136],{"class":534,"line":542},[532,8099,1364],{"class":1363},[532,8101,1339],{"class":549},[532,8103,1650],{"class":560},[532,8105,1653],{"class":549},[532,8107,1656],{"class":560},[532,8109,1659],{"class":549},[532,8111,1662],{"class":549},[532,8113,1665],{"class":1335},[532,8115,2273],{"class":560},[532,8117,448],{"class":549},[532,8119,8120],{"class":560},"storage",[532,8122,448],{"class":549},[532,8124,8125],{"class":1372},"createBucket",[532,8127,1197],{"class":560},[532,8129,557],{"class":549},[532,8131,2546],{"class":553},[532,8133,557],{"class":549},[532,8135,1653],{"class":549},[532,8137,2628],{"class":549},[532,8139,8140,8143,8145,8147,8149],{"class":534,"line":564},[532,8141,8142],{"class":1756},"  public",[532,8144,954],{"class":549},[532,8146,2922],{"class":1762},[532,8148,1653],{"class":549},[532,8150,8151],{"class":538},"                     \u002F\u002F bucket public\n",[532,8153,8154,8157,8159,8162,8164],{"class":534,"line":579},[532,8155,8156],{"class":1756},"  fileSizeLimit",[532,8158,954],{"class":549},[532,8160,8161],{"class":1782}," 5242880",[532,8163,1653],{"class":549},[532,8165,8166],{"class":538},"           \u002F\u002F 5MB limit\n",[532,8168,8169,8172,8174,8176,8178,8181,8183,8185,8187,8190,8192,8195],{"class":534,"line":592},[532,8170,8171],{"class":1756},"  allowedMimeTypes",[532,8173,954],{"class":549},[532,8175,2979],{"class":560},[532,8177,557],{"class":549},[532,8179,8180],{"class":553},"image\u002Fpng",[532,8182,557],{"class":549},[532,8184,1653],{"class":549},[532,8186,550],{"class":549},[532,8188,8189],{"class":553},"image\u002Fjpeg",[532,8191,557],{"class":549},[532,8193,8194],{"class":560},"]",[532,8196,1388],{"class":549},[532,8198,8199,8201],{"class":534,"line":599},[532,8200,1659],{"class":549},[532,8202,1203],{"class":560},[532,8204,8205,8207,8209,8211,8213,8215,8217,8219,8221,8223,8225,8227,8229,8232,8234,8236,8238,8240],{"class":534,"line":605},[532,8206,1364],{"class":1363},[532,8208,1339],{"class":549},[532,8210,1650],{"class":560},[532,8212,1653],{"class":549},[532,8214,1656],{"class":560},[532,8216,1659],{"class":549},[532,8218,1662],{"class":549},[532,8220,1665],{"class":1335},[532,8222,2273],{"class":560},[532,8224,448],{"class":549},[532,8226,8120],{"class":560},[532,8228,448],{"class":549},[532,8230,8231],{"class":1372},"getBucket",[532,8233,1197],{"class":560},[532,8235,557],{"class":549},[532,8237,2546],{"class":553},[532,8239,557],{"class":549},[532,8241,1203],{"class":560},[532,8243,8244,8246,8248,8250,8252,8254,8256,8258,8260,8262,8264,8266,8268,8271],{"class":534,"line":619},[532,8245,1364],{"class":1363},[532,8247,1339],{"class":549},[532,8249,1650],{"class":560},[532,8251,1653],{"class":549},[532,8253,1656],{"class":560},[532,8255,1659],{"class":549},[532,8257,1662],{"class":549},[532,8259,1665],{"class":1335},[532,8261,2273],{"class":560},[532,8263,448],{"class":549},[532,8265,8120],{"class":560},[532,8267,448],{"class":549},[532,8269,8270],{"class":1372},"listBuckets",[532,8272,1996],{"class":560},[532,8274,8275,8277,8279,8281,8283,8285,8287,8289,8291,8293,8295,8297,8299,8302,8304,8306,8308,8310,8312],{"class":534,"line":630},[532,8276,1364],{"class":1363},[532,8278,1339],{"class":549},[532,8280,1650],{"class":560},[532,8282,1653],{"class":549},[532,8284,1656],{"class":560},[532,8286,1659],{"class":549},[532,8288,1662],{"class":549},[532,8290,1665],{"class":1335},[532,8292,2273],{"class":560},[532,8294,448],{"class":549},[532,8296,8120],{"class":560},[532,8298,448],{"class":549},[532,8300,8301],{"class":1372},"updateBucket",[532,8303,1197],{"class":560},[532,8305,557],{"class":549},[532,8307,2546],{"class":553},[532,8309,557],{"class":549},[532,8311,1653],{"class":549},[532,8313,2628],{"class":549},[532,8315,8316,8318,8320,8322,8324],{"class":534,"line":635},[532,8317,8142],{"class":1756},[532,8319,954],{"class":549},[532,8321,1763],{"class":1762},[532,8323,1653],{"class":549},[532,8325,8326],{"class":538},"                    \u002F\u002F chuyển sang private\n",[532,8328,8329,8331,8333,8336,8338],{"class":534,"line":641},[532,8330,8156],{"class":1756},[532,8332,954],{"class":549},[532,8334,8335],{"class":1782}," 10485760",[532,8337,1653],{"class":549},[532,8339,8340],{"class":538},"          \u002F\u002F tăng lên 10MB\n",[532,8342,8343,8345],{"class":534,"line":661},[532,8344,1659],{"class":549},[532,8346,1203],{"class":560},[532,8348,8349,8351,8353,8355,8357,8359,8361,8363,8365,8367,8369,8371,8373,8376,8378,8380,8382,8384],{"class":534,"line":674},[532,8350,1364],{"class":1363},[532,8352,1339],{"class":549},[532,8354,1650],{"class":560},[532,8356,1653],{"class":549},[532,8358,1656],{"class":560},[532,8360,1659],{"class":549},[532,8362,1662],{"class":549},[532,8364,1665],{"class":1335},[532,8366,2273],{"class":560},[532,8368,448],{"class":549},[532,8370,8120],{"class":560},[532,8372,448],{"class":549},[532,8374,8375],{"class":1372},"deleteBucket",[532,8377,1197],{"class":560},[532,8379,557],{"class":549},[532,8381,2546],{"class":553},[532,8383,557],{"class":549},[532,8385,1203],{"class":560},[532,8387,8388,8390,8392,8394,8396,8398,8400,8402,8404,8406,8408,8410,8412,8415,8417,8419,8421,8423,8425],{"class":534,"line":688},[532,8389,1364],{"class":1363},[532,8391,1339],{"class":549},[532,8393,1650],{"class":560},[532,8395,1653],{"class":549},[532,8397,1656],{"class":560},[532,8399,1659],{"class":549},[532,8401,1662],{"class":549},[532,8403,1665],{"class":1335},[532,8405,2273],{"class":560},[532,8407,448],{"class":549},[532,8409,8120],{"class":560},[532,8411,448],{"class":549},[532,8413,8414],{"class":1372},"emptyBucket",[532,8416,1197],{"class":560},[532,8418,557],{"class":549},[532,8420,2546],{"class":553},[532,8422,557],{"class":549},[532,8424,1768],{"class":560},[532,8426,8427],{"class":538},"\u002F\u002F xóa tất cả files\n",[532,8429,8430],{"class":534,"line":702},[532,8431,596],{"emptyLinePlaceholder":595},[532,8433,8434],{"class":534,"line":715},[532,8435,8436],{"class":538},"\u002F\u002F ============ FILE OPERATIONS (from bucket) ============\n",[532,8438,8439,8441,8444,8446,8448,8450,8452,8454,8456,8458,8460,8462,8464],{"class":534,"line":720},[532,8440,1364],{"class":1363},[532,8442,8443],{"class":560}," bucket ",[532,8445,982],{"class":549},[532,8447,2273],{"class":560},[532,8449,448],{"class":549},[532,8451,8120],{"class":560},[532,8453,448],{"class":549},[532,8455,1676],{"class":1372},[532,8457,1197],{"class":560},[532,8459,557],{"class":549},[532,8461,2546],{"class":553},[532,8463,557],{"class":549},[532,8465,1203],{"class":560},[532,8467,8468],{"class":534,"line":726},[532,8469,596],{"emptyLinePlaceholder":595},[532,8471,8472],{"class":534,"line":745},[532,8473,8474],{"class":538},"\u002F\u002F Upload file\n",[532,8476,8477,8479,8481,8483,8485,8487,8489,8491,8493,8496,8498,8500,8502,8504,8507,8509,8511,8514,8516],{"class":534,"line":758},[532,8478,1364],{"class":1363},[532,8480,1339],{"class":549},[532,8482,1650],{"class":560},[532,8484,1653],{"class":549},[532,8486,1656],{"class":560},[532,8488,1659],{"class":549},[532,8490,1662],{"class":549},[532,8492,1665],{"class":1335},[532,8494,8495],{"class":560}," bucket",[532,8497,448],{"class":549},[532,8499,2558],{"class":1372},[532,8501,1197],{"class":560},[532,8503,557],{"class":549},[532,8505,8506],{"class":553},"public\u002Fuser1.png",[532,8508,557],{"class":549},[532,8510,1653],{"class":549},[532,8512,8513],{"class":560}," file",[532,8515,1653],{"class":549},[532,8517,2628],{"class":549},[532,8519,8520,8523,8525,8527,8530,8532,8534],{"class":534,"line":771},[532,8521,8522],{"class":1756},"  cacheControl",[532,8524,954],{"class":549},[532,8526,550],{"class":549},[532,8528,8529],{"class":553},"3600",[532,8531,557],{"class":549},[532,8533,1653],{"class":549},[532,8535,8536],{"class":538},"             \u002F\u002F Cache-Control header\n",[532,8538,8539,8542,8544,8546,8548,8550,8552],{"class":534,"line":783},[532,8540,8541],{"class":1756},"  contentType",[532,8543,954],{"class":549},[532,8545,550],{"class":549},[532,8547,8180],{"class":553},[532,8549,557],{"class":549},[532,8551,1653],{"class":549},[532,8553,8554],{"class":538},"         \u002F\u002F Content-Type (auto-detect nếu không set)\n",[532,8556,8557,8560,8562,8564,8566],{"class":534,"line":788},[532,8558,8559],{"class":1756},"  upsert",[532,8561,954],{"class":549},[532,8563,2922],{"class":1762},[532,8565,1653],{"class":549},[532,8567,8568],{"class":538},"                     \u002F\u002F overwrite nếu đã tồn tại\n",[532,8570,8571,8574,8576,8578,8581,8583,8585],{"class":534,"line":794},[532,8572,8573],{"class":1756},"  duplex",[532,8575,954],{"class":549},[532,8577,550],{"class":549},[532,8579,8580],{"class":553},"half",[532,8582,557],{"class":549},[532,8584,1653],{"class":549},[532,8586,8587],{"class":538},"                   \u002F\u002F streaming upload\n",[532,8589,8590,8592],{"class":534,"line":812},[532,8591,1659],{"class":549},[532,8593,1203],{"class":560},[532,8595,8596],{"class":534,"line":825},[532,8597,596],{"emptyLinePlaceholder":595},[532,8599,8600],{"class":534,"line":2099},[532,8601,8602],{"class":538},"\u002F\u002F Upload với metadata\n",[532,8604,8605,8607,8609,8611,8613,8615,8617,8619,8621,8623,8625,8627,8629,8631,8633,8635,8637,8639,8641],{"class":534,"line":2105},[532,8606,1364],{"class":1363},[532,8608,1339],{"class":549},[532,8610,1650],{"class":560},[532,8612,1653],{"class":549},[532,8614,1656],{"class":560},[532,8616,1659],{"class":549},[532,8618,1662],{"class":549},[532,8620,1665],{"class":1335},[532,8622,8495],{"class":560},[532,8624,448],{"class":549},[532,8626,2558],{"class":1372},[532,8628,1197],{"class":560},[532,8630,557],{"class":549},[532,8632,8506],{"class":553},[532,8634,557],{"class":549},[532,8636,1653],{"class":549},[532,8638,8513],{"class":560},[532,8640,1653],{"class":549},[532,8642,2628],{"class":549},[532,8644,8645,8648,8650],{"class":534,"line":2126},[532,8646,8647],{"class":1756},"  metadata",[532,8649,954],{"class":549},[532,8651,2628],{"class":549},[532,8653,8654,8657,8659,8661,8663,8665],{"class":534,"line":2143},[532,8655,8656],{"class":1756},"    owner",[532,8658,954],{"class":549},[532,8660,550],{"class":549},[532,8662,7233],{"class":553},[532,8664,557],{"class":549},[532,8666,1388],{"class":549},[532,8668,8669,8672,8674,8677,8680,8683,8685,8688,8690],{"class":534,"line":2153},[532,8670,8671],{"class":1756},"    uploadedAt",[532,8673,954],{"class":549},[532,8675,8676],{"class":549}," new",[532,8678,8679],{"class":1372}," Date",[532,8681,8682],{"class":560},"()",[532,8684,448],{"class":549},[532,8686,8687],{"class":1372},"toISOString",[532,8689,8682],{"class":560},[532,8691,1388],{"class":549},[532,8693,8694],{"class":534,"line":2174},[532,8695,4428],{"class":549},[532,8697,8698,8700],{"class":534,"line":2179},[532,8699,1659],{"class":549},[532,8701,1203],{"class":560},[532,8703,8704],{"class":534,"line":2185},[532,8705,596],{"emptyLinePlaceholder":595},[532,8707,8708],{"class":534,"line":2206},[532,8709,8710],{"class":538},"\u002F\u002F Download file\n",[532,8712,8713,8715,8717,8719,8721,8723,8725,8727,8729,8731,8733,8736,8738,8740,8742,8744],{"class":534,"line":2243},[532,8714,1364],{"class":1363},[532,8716,1339],{"class":549},[532,8718,1650],{"class":560},[532,8720,1653],{"class":549},[532,8722,1656],{"class":560},[532,8724,1659],{"class":549},[532,8726,1662],{"class":549},[532,8728,1665],{"class":1335},[532,8730,8495],{"class":560},[532,8732,448],{"class":549},[532,8734,8735],{"class":1372},"download",[532,8737,1197],{"class":560},[532,8739,557],{"class":549},[532,8741,8506],{"class":553},[532,8743,557],{"class":549},[532,8745,1203],{"class":560},[532,8747,8748],{"class":534,"line":2248},[532,8749,8750],{"class":538},"\u002F\u002F data là Blob (browser) hoặc ArrayBuffer (Node.js)\n",[532,8752,8753],{"class":534,"line":2254},[532,8754,596],{"emptyLinePlaceholder":595},[532,8756,8757],{"class":534,"line":2291},[532,8758,8759],{"class":538},"\u002F\u002F Get public URL (chỉ hoạt động nếu bucket public)\n",[532,8761,8762,8764,8766,8768,8770,8772,8774,8776,8779,8781,8783,8785,8787],{"class":534,"line":2308},[532,8763,1364],{"class":1363},[532,8765,1339],{"class":549},[532,8767,6449],{"class":560},[532,8769,1659],{"class":549},[532,8771,1662],{"class":549},[532,8773,8495],{"class":560},[532,8775,448],{"class":549},[532,8777,8778],{"class":1372},"getPublicUrl",[532,8780,1197],{"class":560},[532,8782,557],{"class":549},[532,8784,8506],{"class":553},[532,8786,557],{"class":549},[532,8788,1203],{"class":560},[532,8790,8791],{"class":534,"line":2323},[532,8792,8793],{"class":538},"\u002F\u002F data.publicUrl — https:\u002F\u002F[REF].supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Favatars\u002Fpublic\u002Fuser1.png\n",[532,8795,8796],{"class":534,"line":2330},[532,8797,596],{"emptyLinePlaceholder":595},[532,8799,8800],{"class":534,"line":2335},[532,8801,8802],{"class":538},"\u002F\u002F Create signed URL (có thời hạn, dùng cho private bucket)\n",[532,8804,8805,8807,8809,8811,8813,8815,8817,8819,8821,8823,8825,8828,8830,8832,8835,8837,8839,8842],{"class":534,"line":2341},[532,8806,1364],{"class":1363},[532,8808,1339],{"class":549},[532,8810,1650],{"class":560},[532,8812,1653],{"class":549},[532,8814,1656],{"class":560},[532,8816,1659],{"class":549},[532,8818,1662],{"class":549},[532,8820,1665],{"class":1335},[532,8822,8495],{"class":560},[532,8824,448],{"class":549},[532,8826,8827],{"class":1372},"createSignedUrl",[532,8829,1197],{"class":560},[532,8831,557],{"class":549},[532,8833,8834],{"class":553},"private\u002Fuser1.png",[532,8836,557],{"class":549},[532,8838,1653],{"class":549},[532,8840,8841],{"class":1782}," 60",[532,8843,1203],{"class":560},[532,8845,8846],{"class":534,"line":2353},[532,8847,8848],{"class":538},"\u002F\u002F data.signedUrl — link hết hạn sau 60 giây\n",[532,8850,8851],{"class":534,"line":2372},[532,8852,596],{"emptyLinePlaceholder":595},[532,8854,8855],{"class":534,"line":2391},[532,8856,8857],{"class":538},"\u002F\u002F Create signed upload URL (cho phép upload trực tiếp từ client)\n",[532,8859,8860,8862,8864,8866,8868,8870,8872,8874,8876,8878,8880,8883,8885,8887,8890,8892],{"class":534,"line":2440},[532,8861,1364],{"class":1363},[532,8863,1339],{"class":549},[532,8865,1650],{"class":560},[532,8867,1653],{"class":549},[532,8869,1656],{"class":560},[532,8871,1659],{"class":549},[532,8873,1662],{"class":549},[532,8875,1665],{"class":1335},[532,8877,8495],{"class":560},[532,8879,448],{"class":549},[532,8881,8882],{"class":1372},"createSignedUploadUrl",[532,8884,1197],{"class":560},[532,8886,557],{"class":549},[532,8888,8889],{"class":553},"uploads\u002Ffile.png",[532,8891,557],{"class":549},[532,8893,1203],{"class":560},[532,8895,8896],{"class":534,"line":2482},[532,8897,596],{"emptyLinePlaceholder":595},[532,8899,8900],{"class":534,"line":2488},[532,8901,8902],{"class":538},"\u002F\u002F List files trong folder\n",[532,8904,8905,8907,8909,8911,8913,8915,8917,8919,8921,8923,8925,8928,8930,8932,8934,8936,8938],{"class":534,"line":2498},[532,8906,1364],{"class":1363},[532,8908,1339],{"class":549},[532,8910,1650],{"class":560},[532,8912,1653],{"class":549},[532,8914,1656],{"class":560},[532,8916,1659],{"class":549},[532,8918,1662],{"class":549},[532,8920,1665],{"class":1335},[532,8922,8495],{"class":560},[532,8924,448],{"class":549},[532,8926,8927],{"class":1372},"list",[532,8929,1197],{"class":560},[532,8931,557],{"class":549},[532,8933,2418],{"class":553},[532,8935,557],{"class":549},[532,8937,1653],{"class":549},[532,8939,2628],{"class":549},[532,8941,8942,8945,8947,8950],{"class":534,"line":2503},[532,8943,8944],{"class":1756},"  limit",[532,8946,954],{"class":549},[532,8948,8949],{"class":1782}," 100",[532,8951,1388],{"class":549},[532,8953,8954,8957,8959,8962],{"class":534,"line":2509},[532,8955,8956],{"class":1756},"  offset",[532,8958,954],{"class":549},[532,8960,8961],{"class":1782}," 0",[532,8963,1388],{"class":549},[532,8965,8966,8969,8971,8973,8976,8978,8980,8982,8984,8986,8989,8991,8993,8996,8998],{"class":534,"line":2535},[532,8967,8968],{"class":1756},"  sortBy",[532,8970,954],{"class":549},[532,8972,1339],{"class":549},[532,8974,8975],{"class":1756}," column",[532,8977,954],{"class":549},[532,8979,550],{"class":549},[532,8981,3824],{"class":553},[532,8983,557],{"class":549},[532,8985,1653],{"class":549},[532,8987,8988],{"class":1756}," order",[532,8990,954],{"class":549},[532,8992,550],{"class":549},[532,8994,8995],{"class":553},"asc",[532,8997,557],{"class":549},[532,8999,2437],{"class":549},[532,9001,9002,9004],{"class":534,"line":2553},[532,9003,1659],{"class":549},[532,9005,1203],{"class":560},[532,9007,9008],{"class":534,"line":2575},[532,9009,596],{"emptyLinePlaceholder":595},[532,9011,9012],{"class":534,"line":2580},[532,9013,9014],{"class":538},"\u002F\u002F Move\u002Frename file\n",[532,9016,9017,9019,9021,9023,9025,9027,9029,9031,9033,9035,9037,9040,9042,9044,9046,9048,9050,9052,9055,9057],{"class":534,"line":2586},[532,9018,1364],{"class":1363},[532,9020,1339],{"class":549},[532,9022,1650],{"class":560},[532,9024,1653],{"class":549},[532,9026,1656],{"class":560},[532,9028,1659],{"class":549},[532,9030,1662],{"class":549},[532,9032,1665],{"class":1335},[532,9034,8495],{"class":560},[532,9036,448],{"class":549},[532,9038,9039],{"class":1372},"move",[532,9041,1197],{"class":560},[532,9043,557],{"class":549},[532,9045,8506],{"class":553},[532,9047,557],{"class":549},[532,9049,1653],{"class":549},[532,9051,550],{"class":549},[532,9053,9054],{"class":553},"public\u002Frenamed.png",[532,9056,557],{"class":549},[532,9058,1203],{"class":560},[532,9060,9061],{"class":534,"line":2631},[532,9062,596],{"emptyLinePlaceholder":595},[532,9064,9065],{"class":534,"line":2656},[532,9066,9067],{"class":538},"\u002F\u002F Copy file\n",[532,9069,9070,9072,9074,9076,9078,9080,9082,9084,9086,9088,9090,9093,9095,9097,9099,9101,9103,9105,9108,9110],{"class":534,"line":3970},[532,9071,1364],{"class":1363},[532,9073,1339],{"class":549},[532,9075,1650],{"class":560},[532,9077,1653],{"class":549},[532,9079,1656],{"class":560},[532,9081,1659],{"class":549},[532,9083,1662],{"class":549},[532,9085,1665],{"class":1335},[532,9087,8495],{"class":560},[532,9089,448],{"class":549},[532,9091,9092],{"class":1372},"copy",[532,9094,1197],{"class":560},[532,9096,557],{"class":549},[532,9098,8506],{"class":553},[532,9100,557],{"class":549},[532,9102,1653],{"class":549},[532,9104,550],{"class":549},[532,9106,9107],{"class":553},"backup\u002Fuser1.png",[532,9109,557],{"class":549},[532,9111,1203],{"class":560},[532,9113,9114],{"class":534,"line":3991},[532,9115,596],{"emptyLinePlaceholder":595},[532,9117,9118],{"class":534,"line":3996},[532,9119,9120],{"class":538},"\u002F\u002F Remove files (có thể xóa nhiều file cùng lúc)\n",[532,9122,9123,9125,9127,9129,9131,9133,9135,9137,9139,9141,9143,9146,9149,9151,9153,9155,9157,9159,9162,9164],{"class":534,"line":4017},[532,9124,1364],{"class":1363},[532,9126,1339],{"class":549},[532,9128,1650],{"class":560},[532,9130,1653],{"class":549},[532,9132,1656],{"class":560},[532,9134,1659],{"class":549},[532,9136,1662],{"class":549},[532,9138,1665],{"class":1335},[532,9140,8495],{"class":560},[532,9142,448],{"class":549},[532,9144,9145],{"class":1372},"remove",[532,9147,9148],{"class":560},"([",[532,9150,557],{"class":549},[532,9152,8506],{"class":553},[532,9154,557],{"class":549},[532,9156,1653],{"class":549},[532,9158,550],{"class":549},[532,9160,9161],{"class":553},"public\u002Fuser2.png",[532,9163,557],{"class":549},[532,9165,9166],{"class":560},"])\n",[532,9168,9169],{"class":534,"line":4038},[532,9170,596],{"emptyLinePlaceholder":595},[532,9172,9173],{"class":534,"line":4059},[532,9174,9175],{"class":538},"\u002F\u002F Update file (upsert = true để ghi đè, false để tạo mới)\n",[532,9177,9178,9180,9182,9184,9186,9188,9190,9192,9194,9196,9198,9200,9202,9204,9206,9208,9210,9213,9215],{"class":534,"line":4064},[532,9179,1364],{"class":1363},[532,9181,1339],{"class":549},[532,9183,1650],{"class":560},[532,9185,1653],{"class":549},[532,9187,1656],{"class":560},[532,9189,1659],{"class":549},[532,9191,1662],{"class":549},[532,9193,1665],{"class":1335},[532,9195,8495],{"class":560},[532,9197,448],{"class":549},[532,9199,1945],{"class":1372},[532,9201,1197],{"class":560},[532,9203,557],{"class":549},[532,9205,8506],{"class":553},[532,9207,557],{"class":549},[532,9209,1653],{"class":549},[532,9211,9212],{"class":560}," newFile",[532,9214,1653],{"class":549},[532,9216,2628],{"class":549},[532,9218,9219,9221,9223,9225],{"class":534,"line":4077},[532,9220,8559],{"class":1756},[532,9222,954],{"class":549},[532,9224,2922],{"class":1762},[532,9226,1388],{"class":549},[532,9228,9229,9231],{"class":534,"line":4091},[532,9230,1659],{"class":549},[532,9232,1203],{"class":560},[532,9234,9235],{"class":534,"line":4112},[532,9236,596],{"emptyLinePlaceholder":595},[532,9238,9239],{"class":534,"line":4126},[532,9240,9241],{"class":538},"\u002F\u002F Create signed URLs (nhiều file)\n",[532,9243,9244,9246,9248,9250,9252,9254,9256,9258,9260,9262,9264,9267],{"class":534,"line":4131},[532,9245,1364],{"class":1363},[532,9247,1339],{"class":549},[532,9249,1650],{"class":560},[532,9251,1653],{"class":549},[532,9253,1656],{"class":560},[532,9255,1659],{"class":549},[532,9257,1662],{"class":549},[532,9259,1665],{"class":1335},[532,9261,8495],{"class":560},[532,9263,448],{"class":549},[532,9265,9266],{"class":1372},"createSignedUrls",[532,9268,1375],{"class":560},[532,9270,9271,9274,9276,9279,9281,9283,9285,9288,9290,9292],{"class":534,"line":4137},[532,9272,9273],{"class":560},"  [",[532,9275,557],{"class":549},[532,9277,9278],{"class":553},"file1.png",[532,9280,557],{"class":549},[532,9282,1653],{"class":549},[532,9284,550],{"class":549},[532,9286,9287],{"class":553},"file2.png",[532,9289,557],{"class":549},[532,9291,8194],{"class":560},[532,9293,1388],{"class":549},[532,9295,9296,9299],{"class":534,"line":4156},[532,9297,9298],{"class":1782},"  3600",[532,9300,9301],{"class":538}," \u002F\u002F 1 giờ\n",[532,9303,9304],{"class":534,"line":4170},[532,9305,1203],{"class":560},[532,9307,9308],{"class":534,"line":4195},[532,9309,596],{"emptyLinePlaceholder":595},[532,9311,9312],{"class":534,"line":4228},[532,9313,9314],{"class":538},"\u002F\u002F Get file info\n",[532,9316,9317,9319,9321,9323,9325,9327,9329,9331,9333,9335,9337,9340,9342,9344,9346,9348],{"class":534,"line":4241},[532,9318,1364],{"class":1363},[532,9320,1339],{"class":549},[532,9322,1650],{"class":560},[532,9324,1653],{"class":549},[532,9326,1656],{"class":560},[532,9328,1659],{"class":549},[532,9330,1662],{"class":549},[532,9332,1665],{"class":1335},[532,9334,8495],{"class":560},[532,9336,448],{"class":549},[532,9338,9339],{"class":1372},"info",[532,9341,1197],{"class":560},[532,9343,557],{"class":549},[532,9345,8506],{"class":553},[532,9347,557],{"class":549},[532,9349,1203],{"class":560},[532,9351,9352],{"class":534,"line":4255},[532,9353,596],{"emptyLinePlaceholder":595},[532,9355,9356],{"class":534,"line":5246},[532,9357,9358],{"class":538},"\u002F\u002F Check file exists\n",[532,9360,9361,9363,9365,9367,9369,9371,9373,9375,9377,9379,9381,9384,9386,9388,9390,9392],{"class":534,"line":5286},[532,9362,1364],{"class":1363},[532,9364,1339],{"class":549},[532,9366,1650],{"class":560},[532,9368,1653],{"class":549},[532,9370,1656],{"class":560},[532,9372,1659],{"class":549},[532,9374,1662],{"class":549},[532,9376,1665],{"class":1335},[532,9378,8495],{"class":560},[532,9380,448],{"class":549},[532,9382,9383],{"class":1372},"exists",[532,9385,1197],{"class":560},[532,9387,557],{"class":549},[532,9389,8506],{"class":553},[532,9391,557],{"class":549},[532,9393,1203],{"class":560},[532,9395,9396],{"class":534,"line":5291},[532,9397,596],{"emptyLinePlaceholder":595},[532,9399,9400],{"class":534,"line":5297},[532,9401,9402],{"class":538},"\u002F\u002F Upload file từ URL (server-side)\n",[532,9404,9405,9407,9409,9411,9413,9415,9417,9419,9421,9423,9425,9427,9429,9431,9434,9436],{"class":534,"line":5336},[532,9406,1364],{"class":1363},[532,9408,1339],{"class":549},[532,9410,1650],{"class":560},[532,9412,1653],{"class":549},[532,9414,1656],{"class":560},[532,9416,1659],{"class":549},[532,9418,1662],{"class":549},[532,9420,1665],{"class":1335},[532,9422,8495],{"class":560},[532,9424,448],{"class":549},[532,9426,2558],{"class":1372},[532,9428,1197],{"class":560},[532,9430,557],{"class":549},[532,9432,9433],{"class":553},"public\u002Fremote.png",[532,9435,557],{"class":549},[532,9437,1388],{"class":549},[532,9439,9440,9443,9446,9448,9450,9453,9455,9457,9459,9462,9464,9467,9469,9472,9474,9477],{"class":534,"line":5341},[532,9441,9442],{"class":1335},"  await",[532,9444,9445],{"class":1372}," fetch",[532,9447,1197],{"class":560},[532,9449,557],{"class":549},[532,9451,9452],{"class":553},"https:\u002F\u002Fexample.com\u002Fimage.png",[532,9454,557],{"class":549},[532,9456,1310],{"class":560},[532,9458,448],{"class":549},[532,9460,9461],{"class":1372},"then",[532,9463,1197],{"class":560},[532,9465,9466],{"class":2446},"r",[532,9468,2452],{"class":1363},[532,9470,9471],{"class":560}," r",[532,9473,448],{"class":549},[532,9475,9476],{"class":1372},"blob",[532,9478,9479],{"class":560},"())\n",[532,9481,9482],{"class":534,"line":5347},[532,9483,1203],{"class":560},[450,9485,9487],{"id":9486},"realtime-methods-đầy-đủ","Realtime Methods — đầy đủ",[523,9489,9491],{"className":1326,"code":9490,"language":1328,"meta":528,"style":528},"\u002F\u002F ============ CHANNEL MANAGEMENT ============\n\n\u002F\u002F Tạo channel với tất cả các loại subscription\nconst channel = supabase.channel('room-1', {\n  config: {\n    broadcast: { self: true },        \u002F\u002F nhận broadcast của chính mình\n    presence: { key: 'user-id-123' }, \u002F\u002F key để track presence\n    private: false,                   \u002F\u002F channel private (cần auth)\n  }\n})\n\n\u002F\u002F ============ POSTGRES CHANGES (Database CDC) ============\n\n\u002F\u002F Lắng nghe tất cả thay đổi trên bảng\nchannel.on('postgres_changes',\n  { event: '*', schema: 'public', table: 'posts' },\n  (payload) => {\n    console.log('Event type:', payload.eventType)  \u002F\u002F INSERT | UPDATE | DELETE\n    console.log('New data:', payload.new)           \u002F\u002F row mới (INSERT\u002FUPDATE)\n    console.log('Old data:', payload.old)           \u002F\u002F row cũ (UPDATE\u002FDELETE)\n    console.log('Table:', payload.table)\n    console.log('Schema:', payload.schema)\n    console.log('Commit timestamp:', payload.commit_timestamp)\n    console.log('Errors:', payload.errors)\n  }\n)\n\n\u002F\u002F Chỉ lắng nghe INSERT\nchannel.on('postgres_changes',\n  { event: 'INSERT', schema: 'public', table: 'posts' },\n  (payload) => { \u002F* ... *\u002F }\n)\n\n\u002F\u002F Filter theo điều kiện\nchannel.on('postgres_changes',\n  {\n    event: 'UPDATE',\n    schema: 'public',\n    table: 'posts',\n    filter: 'user_id=eq.123',         \u002F\u002F PostgREST filter syntax\n  },\n  (payload) => { \u002F* ... *\u002F }\n)\n\n\u002F\u002F ============ BROADCAST (Real-time messaging) ============\n\n\u002F\u002F Gửi broadcast message\nawait channel.send({\n  type: 'broadcast',\n  event: 'cursor-move',\n  payload: { x: 100, y: 200 },\n})\n\n\u002F\u002F Nhận broadcast\nchannel.on('broadcast',\n  { event: 'cursor-move' },\n  (payload) => {\n    console.log('Cursor at:', payload.x, payload.y)\n  }\n)\n\n\u002F\u002F Gửi broadcast với ack (đảm bảo server nhận được)\nconst resp = await channel.send({\n  type: 'broadcast',\n  event: 'message',\n  payload: { text: 'Hello' },\n})\n\u002F\u002F resp === 'ok'\n\n\u002F\u002F ============ PRESENCE (Online status \u002F Multiplayer state) ============\n\n\u002F\u002F Track presence state của user hiện tại\nawait channel.track({\n  user_id: 'user-123',\n  online_at: new Date().toISOString(),\n  status: 'online',\n  cursor: { x: 0, y: 0 },\n})\n\n\u002F\u002F Lắng nghe presence state của tất cả users\nchannel.on('presence',\n  { event: 'sync' },\n  () => {\n    const state = channel.presenceState()\n    \u002F\u002F state = {\n    \u002F\u002F   'user-123': [{ user_id: 'user-123', status: 'online', ... }],\n    \u002F\u002F   'user-456': [{ user_id: 'user-456', status: 'away', ... }],\n    \u002F\u002F }\n    console.log('Online users:', Object.keys(state))\n  }\n)\n\n\u002F\u002F Lắng nghe khi có user join\nchannel.on('presence',\n  { event: 'join' },\n  ({ key, newPresences }) => {\n    console.log('User joined:', key, newPresences)\n  }\n)\n\n\u002F\u002F Lắng nghe khi có user leave\nchannel.on('presence',\n  { event: 'leave' },\n  ({ key, leftPresences }) => {\n    console.log('User left:', key, leftPresences)\n  }\n)\n\n\u002F\u002F Untrack (remove presence)\nawait channel.untrack()\n\n\u002F\u002F ============ SUBSCRIBE & UNSUBSCRIBE ============\n\n\u002F\u002F Subscribe — bắt đầu nhận events\nchannel.subscribe(async (status, err) => {\n  if (status === 'SUBSCRIBED') {\n    console.log('Connected to channel:', channel.topic)\n  }\n  if (status === 'CHANNEL_ERROR') {\n    console.error('Channel error:', err)\n  }\n  if (status === 'TIMED_OUT') {\n    console.warn('Channel timed out — retrying...')\n  }\n  if (status === 'CLOSED') {\n    console.log('Channel closed')\n  }\n})\n\n\u002F\u002F Unsubscribe channel cụ thể\nawait supabase.removeChannel(channel)\n\n\u002F\u002F Unsubscribe tất cả channels\nawait supabase.removeAllChannels()\n\n\u002F\u002F Get tất cả channels đang active\nconst channels = supabase.getChannels()\n\n\u002F\u002F ============ CONNECTION STATUS ============\n\n\u002F\u002F Kiểm tra kết nối Realtime\nif (supabase.realtime.isConnected()) {\n  console.log('Realtime connected')\n}\n\n\u002F\u002F Manually connect (auto-connect khi có channel đầu tiên subscribe)\nsupabase.realtime.connect()\n\n\u002F\u002F Manually disconnect\nsupabase.realtime.disconnect()\n\n\u002F\u002F ============ REALTIME TOPICS ============\n\u002F\u002F Mỗi channel có một topic unique:\n\u002F\u002F 'realtime:public:posts' — dùng topic prefix của Supabase Realtime v2\n\n\u002F\u002F ============ FULL EXAMPLE: Real-time Chat Room ============\n\nasync function joinChatRoom(roomId, userId) {\n  const channel = supabase.channel(`room:${roomId}`)\n\n  \u002F\u002F Lắng nghe tin nhắn mới\n  channel.on('broadcast', { event: 'new-message' }, (payload) => {\n    addMessageToUI(payload)\n  })\n\n  \u002F\u002F Track presence (ai đang online)\n  channel.on('presence', { event: 'sync' }, () => {\n    updateOnlineUsersList(channel.presenceState())\n  })\n\n  channel.subscribe(async (status) => {\n    if (status === 'SUBSCRIBED') {\n      await channel.track({ user_id: userId, joined_at: new Date().toISOString() })\n    }\n  })\n\n  return channel\n}\n\nasync function sendMessage(channel, text) {\n  await channel.send({\n    type: 'broadcast',\n    event: 'new-message',\n    payload: { text, sender: userId, timestamp: new Date().toISOString() },\n  })\n}\n",[445,9492,9493,9498,9502,9507,9534,9543,9564,9589,9603,9607,9613,9617,9622,9626,9631,9649,9690,9702,9733,9765,9796,9823,9851,9879,9907,9911,9915,9919,9924,9942,9982,9999,10003,10007,10012,10030,10034,10050,10065,10080,10099,10104,10120,10124,10128,10133,10137,10142,10158,10173,10189,10217,10223,10227,10232,10250,10266,10278,10315,10319,10323,10327,10332,10353,10367,10382,10403,10409,10414,10418,10423,10427,10432,10447,10463,10484,10500,10525,10531,10535,10540,10559,10576,10585,10604,10609,10614,10619,10624,10659,10663,10667,10671,10676,10694,10711,10730,10757,10761,10765,10769,10774,10792,10809,10826,10853,10857,10861,10865,10870,10883,10887,10892,10896,10901,10930,10953,10981,10985,11006,11030,11034,11055,11075,11079,11100,11119,11123,11129,11133,11138,11152,11156,11161,11174,11178,11183,11201,11205,11210,11214,11219,11242,11262,11267,11271,11276,11292,11296,11301,11316,11320,11325,11330,11335,11339,11344,11348,11372,11405,11409,11414,11458,11469,11476,11480,11485,11524,11539,11545,11549,11571,11592,11637,11642,11648,11652,11660,11664,11668,11689,11703,11718,11732,11774,11780],{"__ignoreMap":528},[532,9494,9495],{"class":534,"line":535},[532,9496,9497],{"class":538},"\u002F\u002F ============ CHANNEL MANAGEMENT ============\n",[532,9499,9500],{"class":534,"line":542},[532,9501,596],{"emptyLinePlaceholder":595},[532,9503,9504],{"class":534,"line":564},[532,9505,9506],{"class":538},"\u002F\u002F Tạo channel với tất cả các loại subscription\n",[532,9508,9509,9511,9513,9515,9517,9519,9521,9523,9525,9528,9530,9532],{"class":534,"line":579},[532,9510,1364],{"class":1363},[532,9512,2346],{"class":560},[532,9514,982],{"class":549},[532,9516,2273],{"class":560},[532,9518,448],{"class":549},[532,9520,2358],{"class":1372},[532,9522,1197],{"class":560},[532,9524,557],{"class":549},[532,9526,9527],{"class":553},"room-1",[532,9529,557],{"class":549},[532,9531,1653],{"class":549},[532,9533,2628],{"class":549},[532,9535,9536,9539,9541],{"class":534,"line":592},[532,9537,9538],{"class":1756},"  config",[532,9540,954],{"class":549},[532,9542,2628],{"class":549},[532,9544,9545,9548,9550,9552,9555,9557,9559,9561],{"class":534,"line":599},[532,9546,9547],{"class":1756},"    broadcast",[532,9549,954],{"class":549},[532,9551,1339],{"class":549},[532,9553,9554],{"class":1756}," self",[532,9556,954],{"class":549},[532,9558,2922],{"class":1762},[532,9560,2075],{"class":549},[532,9562,9563],{"class":538},"        \u002F\u002F nhận broadcast của chính mình\n",[532,9565,9566,9569,9571,9573,9575,9577,9579,9582,9584,9586],{"class":534,"line":605},[532,9567,9568],{"class":1756},"    presence",[532,9570,954],{"class":549},[532,9572,1339],{"class":549},[532,9574,3048],{"class":1756},[532,9576,954],{"class":549},[532,9578,550],{"class":549},[532,9580,9581],{"class":553},"user-id-123",[532,9583,557],{"class":549},[532,9585,2075],{"class":549},[532,9587,9588],{"class":538}," \u002F\u002F key để track presence\n",[532,9590,9591,9594,9596,9598,9600],{"class":534,"line":619},[532,9592,9593],{"class":1756},"    private",[532,9595,954],{"class":549},[532,9597,1763],{"class":1762},[532,9599,1653],{"class":549},[532,9601,9602],{"class":538},"                   \u002F\u002F channel private (cần auth)\n",[532,9604,9605],{"class":534,"line":630},[532,9606,4428],{"class":549},[532,9608,9609,9611],{"class":534,"line":635},[532,9610,1659],{"class":549},[532,9612,1203],{"class":560},[532,9614,9615],{"class":534,"line":641},[532,9616,596],{"emptyLinePlaceholder":595},[532,9618,9619],{"class":534,"line":661},[532,9620,9621],{"class":538},"\u002F\u002F ============ POSTGRES CHANGES (Database CDC) ============\n",[532,9623,9624],{"class":534,"line":674},[532,9625,596],{"emptyLinePlaceholder":595},[532,9627,9628],{"class":534,"line":688},[532,9629,9630],{"class":538},"\u002F\u002F Lắng nghe tất cả thay đổi trên bảng\n",[532,9632,9633,9635,9637,9639,9641,9643,9645,9647],{"class":534,"line":702},[532,9634,2358],{"class":560},[532,9636,448],{"class":549},[532,9638,2377],{"class":1372},[532,9640,1197],{"class":560},[532,9642,557],{"class":549},[532,9644,2384],{"class":553},[532,9646,557],{"class":549},[532,9648,1388],{"class":549},[532,9650,9651,9653,9655,9657,9659,9662,9664,9666,9668,9670,9672,9674,9676,9678,9680,9682,9684,9686,9688],{"class":534,"line":715},[532,9652,5958],{"class":549},[532,9654,2397],{"class":1756},[532,9656,954],{"class":549},[532,9658,550],{"class":549},[532,9660,9661],{"class":553},"*",[532,9663,557],{"class":549},[532,9665,1653],{"class":549},[532,9667,2411],{"class":1756},[532,9669,954],{"class":549},[532,9671,550],{"class":549},[532,9673,2418],{"class":553},[532,9675,557],{"class":549},[532,9677,1653],{"class":549},[532,9679,2425],{"class":1756},[532,9681,954],{"class":549},[532,9683,550],{"class":549},[532,9685,1683],{"class":553},[532,9687,557],{"class":549},[532,9689,2437],{"class":549},[532,9691,9692,9694,9696,9698,9700],{"class":534,"line":720},[532,9693,5533],{"class":549},[532,9695,2447],{"class":2446},[532,9697,1310],{"class":549},[532,9699,2452],{"class":1363},[532,9701,2628],{"class":549},[532,9703,9704,9706,9708,9710,9712,9714,9717,9719,9721,9723,9725,9728,9730],{"class":534,"line":726},[532,9705,5552],{"class":560},[532,9707,448],{"class":549},[532,9709,2460],{"class":1372},[532,9711,1197],{"class":1756},[532,9713,557],{"class":549},[532,9715,9716],{"class":553},"Event type:",[532,9718,557],{"class":549},[532,9720,1653],{"class":549},[532,9722,2474],{"class":560},[532,9724,448],{"class":549},[532,9726,9727],{"class":560},"eventType",[532,9729,3062],{"class":1756},[532,9731,9732],{"class":538},"\u002F\u002F INSERT | UPDATE | DELETE\n",[532,9734,9735,9737,9739,9741,9743,9745,9748,9750,9752,9754,9756,9759,9762],{"class":534,"line":745},[532,9736,5552],{"class":560},[532,9738,448],{"class":549},[532,9740,2460],{"class":1372},[532,9742,1197],{"class":1756},[532,9744,557],{"class":549},[532,9746,9747],{"class":553},"New data:",[532,9749,557],{"class":549},[532,9751,1653],{"class":549},[532,9753,2474],{"class":560},[532,9755,448],{"class":549},[532,9757,9758],{"class":560},"new",[532,9760,9761],{"class":1756},")           ",[532,9763,9764],{"class":538},"\u002F\u002F row mới (INSERT\u002FUPDATE)\n",[532,9766,9767,9769,9771,9773,9775,9777,9780,9782,9784,9786,9788,9791,9793],{"class":534,"line":758},[532,9768,5552],{"class":560},[532,9770,448],{"class":549},[532,9772,2460],{"class":1372},[532,9774,1197],{"class":1756},[532,9776,557],{"class":549},[532,9778,9779],{"class":553},"Old data:",[532,9781,557],{"class":549},[532,9783,1653],{"class":549},[532,9785,2474],{"class":560},[532,9787,448],{"class":549},[532,9789,9790],{"class":560},"old",[532,9792,9761],{"class":1756},[532,9794,9795],{"class":538},"\u002F\u002F row cũ (UPDATE\u002FDELETE)\n",[532,9797,9798,9800,9802,9804,9806,9808,9811,9813,9815,9817,9819,9821],{"class":534,"line":771},[532,9799,5552],{"class":560},[532,9801,448],{"class":549},[532,9803,2460],{"class":1372},[532,9805,1197],{"class":1756},[532,9807,557],{"class":549},[532,9809,9810],{"class":553},"Table:",[532,9812,557],{"class":549},[532,9814,1653],{"class":549},[532,9816,2474],{"class":560},[532,9818,448],{"class":549},[532,9820,842],{"class":560},[532,9822,1203],{"class":1756},[532,9824,9825,9827,9829,9831,9833,9835,9838,9840,9842,9844,9846,9849],{"class":534,"line":783},[532,9826,5552],{"class":560},[532,9828,448],{"class":549},[532,9830,2460],{"class":1372},[532,9832,1197],{"class":1756},[532,9834,557],{"class":549},[532,9836,9837],{"class":553},"Schema:",[532,9839,557],{"class":549},[532,9841,1653],{"class":549},[532,9843,2474],{"class":560},[532,9845,448],{"class":549},[532,9847,9848],{"class":560},"schema",[532,9850,1203],{"class":1756},[532,9852,9853,9855,9857,9859,9861,9863,9866,9868,9870,9872,9874,9877],{"class":534,"line":788},[532,9854,5552],{"class":560},[532,9856,448],{"class":549},[532,9858,2460],{"class":1372},[532,9860,1197],{"class":1756},[532,9862,557],{"class":549},[532,9864,9865],{"class":553},"Commit timestamp:",[532,9867,557],{"class":549},[532,9869,1653],{"class":549},[532,9871,2474],{"class":560},[532,9873,448],{"class":549},[532,9875,9876],{"class":560},"commit_timestamp",[532,9878,1203],{"class":1756},[532,9880,9881,9883,9885,9887,9889,9891,9894,9896,9898,9900,9902,9905],{"class":534,"line":794},[532,9882,5552],{"class":560},[532,9884,448],{"class":549},[532,9886,2460],{"class":1372},[532,9888,1197],{"class":1756},[532,9890,557],{"class":549},[532,9892,9893],{"class":553},"Errors:",[532,9895,557],{"class":549},[532,9897,1653],{"class":549},[532,9899,2474],{"class":560},[532,9901,448],{"class":549},[532,9903,9904],{"class":560},"errors",[532,9906,1203],{"class":1756},[532,9908,9909],{"class":534,"line":812},[532,9910,4428],{"class":549},[532,9912,9913],{"class":534,"line":825},[532,9914,1203],{"class":560},[532,9916,9917],{"class":534,"line":2099},[532,9918,596],{"emptyLinePlaceholder":595},[532,9920,9921],{"class":534,"line":2105},[532,9922,9923],{"class":538},"\u002F\u002F Chỉ lắng nghe INSERT\n",[532,9925,9926,9928,9930,9932,9934,9936,9938,9940],{"class":534,"line":2126},[532,9927,2358],{"class":560},[532,9929,448],{"class":549},[532,9931,2377],{"class":1372},[532,9933,1197],{"class":560},[532,9935,557],{"class":549},[532,9937,2384],{"class":553},[532,9939,557],{"class":549},[532,9941,1388],{"class":549},[532,9943,9944,9946,9948,9950,9952,9954,9956,9958,9960,9962,9964,9966,9968,9970,9972,9974,9976,9978,9980],{"class":534,"line":2143},[532,9945,5958],{"class":549},[532,9947,2397],{"class":1756},[532,9949,954],{"class":549},[532,9951,550],{"class":549},[532,9953,2404],{"class":553},[532,9955,557],{"class":549},[532,9957,1653],{"class":549},[532,9959,2411],{"class":1756},[532,9961,954],{"class":549},[532,9963,550],{"class":549},[532,9965,2418],{"class":553},[532,9967,557],{"class":549},[532,9969,1653],{"class":549},[532,9971,2425],{"class":1756},[532,9973,954],{"class":549},[532,9975,550],{"class":549},[532,9977,1683],{"class":553},[532,9979,557],{"class":549},[532,9981,2437],{"class":549},[532,9983,9984,9986,9988,9990,9992,9994,9997],{"class":534,"line":2153},[532,9985,5533],{"class":549},[532,9987,2447],{"class":2446},[532,9989,1310],{"class":549},[532,9991,2452],{"class":1363},[532,9993,1339],{"class":549},[532,9995,9996],{"class":538}," \u002F* ... *\u002F",[532,9998,2653],{"class":549},[532,10000,10001],{"class":534,"line":2174},[532,10002,1203],{"class":560},[532,10004,10005],{"class":534,"line":2179},[532,10006,596],{"emptyLinePlaceholder":595},[532,10008,10009],{"class":534,"line":2185},[532,10010,10011],{"class":538},"\u002F\u002F Filter theo điều kiện\n",[532,10013,10014,10016,10018,10020,10022,10024,10026,10028],{"class":534,"line":2206},[532,10015,2358],{"class":560},[532,10017,448],{"class":549},[532,10019,2377],{"class":1372},[532,10021,1197],{"class":560},[532,10023,557],{"class":549},[532,10025,2384],{"class":553},[532,10027,557],{"class":549},[532,10029,1388],{"class":549},[532,10031,10032],{"class":534,"line":2243},[532,10033,7354],{"class":549},[532,10035,10036,10039,10041,10043,10046,10048],{"class":534,"line":2248},[532,10037,10038],{"class":1756},"    event",[532,10040,954],{"class":549},[532,10042,550],{"class":549},[532,10044,10045],{"class":553},"UPDATE",[532,10047,557],{"class":549},[532,10049,1388],{"class":549},[532,10051,10052,10055,10057,10059,10061,10063],{"class":534,"line":2254},[532,10053,10054],{"class":1756},"    schema",[532,10056,954],{"class":549},[532,10058,550],{"class":549},[532,10060,2418],{"class":553},[532,10062,557],{"class":549},[532,10064,1388],{"class":549},[532,10066,10067,10070,10072,10074,10076,10078],{"class":534,"line":2291},[532,10068,10069],{"class":1756},"    table",[532,10071,954],{"class":549},[532,10073,550],{"class":549},[532,10075,1683],{"class":553},[532,10077,557],{"class":549},[532,10079,1388],{"class":549},[532,10081,10082,10085,10087,10089,10092,10094,10096],{"class":534,"line":2308},[532,10083,10084],{"class":1756},"    filter",[532,10086,954],{"class":549},[532,10088,550],{"class":549},[532,10090,10091],{"class":553},"user_id=eq.123",[532,10093,557],{"class":549},[532,10095,1653],{"class":549},[532,10097,10098],{"class":538},"         \u002F\u002F PostgREST filter syntax\n",[532,10100,10101],{"class":534,"line":2323},[532,10102,10103],{"class":549},"  },\n",[532,10105,10106,10108,10110,10112,10114,10116,10118],{"class":534,"line":2330},[532,10107,5533],{"class":549},[532,10109,2447],{"class":2446},[532,10111,1310],{"class":549},[532,10113,2452],{"class":1363},[532,10115,1339],{"class":549},[532,10117,9996],{"class":538},[532,10119,2653],{"class":549},[532,10121,10122],{"class":534,"line":2335},[532,10123,1203],{"class":560},[532,10125,10126],{"class":534,"line":2341},[532,10127,596],{"emptyLinePlaceholder":595},[532,10129,10130],{"class":534,"line":2353},[532,10131,10132],{"class":538},"\u002F\u002F ============ BROADCAST (Real-time messaging) ============\n",[532,10134,10135],{"class":534,"line":2372},[532,10136,596],{"emptyLinePlaceholder":595},[532,10138,10139],{"class":534,"line":2391},[532,10140,10141],{"class":538},"\u002F\u002F Gửi broadcast message\n",[532,10143,10144,10147,10149,10151,10154,10156],{"class":534,"line":2440},[532,10145,10146],{"class":1335},"await",[532,10148,4681],{"class":560},[532,10150,448],{"class":549},[532,10152,10153],{"class":1372},"send",[532,10155,1197],{"class":560},[532,10157,2288],{"class":549},[532,10159,10160,10162,10164,10166,10169,10171],{"class":534,"line":2482},[532,10161,6071],{"class":1756},[532,10163,954],{"class":549},[532,10165,550],{"class":549},[532,10167,10168],{"class":553},"broadcast",[532,10170,557],{"class":549},[532,10172,1388],{"class":549},[532,10174,10175,10178,10180,10182,10185,10187],{"class":534,"line":2488},[532,10176,10177],{"class":1756},"  event",[532,10179,954],{"class":549},[532,10181,550],{"class":549},[532,10183,10184],{"class":553},"cursor-move",[532,10186,557],{"class":549},[532,10188,1388],{"class":549},[532,10190,10191,10194,10196,10198,10201,10203,10205,10207,10210,10212,10215],{"class":534,"line":2498},[532,10192,10193],{"class":1756},"  payload",[532,10195,954],{"class":549},[532,10197,1339],{"class":549},[532,10199,10200],{"class":1756}," x",[532,10202,954],{"class":549},[532,10204,8949],{"class":1782},[532,10206,1653],{"class":549},[532,10208,10209],{"class":1756}," y",[532,10211,954],{"class":549},[532,10213,10214],{"class":1782}," 200",[532,10216,2437],{"class":549},[532,10218,10219,10221],{"class":534,"line":2503},[532,10220,1659],{"class":549},[532,10222,1203],{"class":560},[532,10224,10225],{"class":534,"line":2509},[532,10226,596],{"emptyLinePlaceholder":595},[532,10228,10229],{"class":534,"line":2535},[532,10230,10231],{"class":538},"\u002F\u002F Nhận broadcast\n",[532,10233,10234,10236,10238,10240,10242,10244,10246,10248],{"class":534,"line":2553},[532,10235,2358],{"class":560},[532,10237,448],{"class":549},[532,10239,2377],{"class":1372},[532,10241,1197],{"class":560},[532,10243,557],{"class":549},[532,10245,10168],{"class":553},[532,10247,557],{"class":549},[532,10249,1388],{"class":549},[532,10251,10252,10254,10256,10258,10260,10262,10264],{"class":534,"line":2575},[532,10253,5958],{"class":549},[532,10255,2397],{"class":1756},[532,10257,954],{"class":549},[532,10259,550],{"class":549},[532,10261,10184],{"class":553},[532,10263,557],{"class":549},[532,10265,2437],{"class":549},[532,10267,10268,10270,10272,10274,10276],{"class":534,"line":2580},[532,10269,5533],{"class":549},[532,10271,2447],{"class":2446},[532,10273,1310],{"class":549},[532,10275,2452],{"class":1363},[532,10277,2628],{"class":549},[532,10279,10280,10282,10284,10286,10288,10290,10293,10295,10297,10299,10301,10304,10306,10308,10310,10313],{"class":534,"line":2586},[532,10281,5552],{"class":560},[532,10283,448],{"class":549},[532,10285,2460],{"class":1372},[532,10287,1197],{"class":1756},[532,10289,557],{"class":549},[532,10291,10292],{"class":553},"Cursor at:",[532,10294,557],{"class":549},[532,10296,1653],{"class":549},[532,10298,2474],{"class":560},[532,10300,448],{"class":549},[532,10302,10303],{"class":560},"x",[532,10305,1653],{"class":549},[532,10307,2474],{"class":560},[532,10309,448],{"class":549},[532,10311,10312],{"class":560},"y",[532,10314,1203],{"class":1756},[532,10316,10317],{"class":534,"line":2631},[532,10318,4428],{"class":549},[532,10320,10321],{"class":534,"line":2656},[532,10322,1203],{"class":560},[532,10324,10325],{"class":534,"line":3970},[532,10326,596],{"emptyLinePlaceholder":595},[532,10328,10329],{"class":534,"line":3991},[532,10330,10331],{"class":538},"\u002F\u002F Gửi broadcast với ack (đảm bảo server nhận được)\n",[532,10333,10334,10336,10339,10341,10343,10345,10347,10349,10351],{"class":534,"line":3996},[532,10335,1364],{"class":1363},[532,10337,10338],{"class":560}," resp ",[532,10340,982],{"class":549},[532,10342,1665],{"class":1335},[532,10344,4681],{"class":560},[532,10346,448],{"class":549},[532,10348,10153],{"class":1372},[532,10350,1197],{"class":560},[532,10352,2288],{"class":549},[532,10354,10355,10357,10359,10361,10363,10365],{"class":534,"line":4017},[532,10356,6071],{"class":1756},[532,10358,954],{"class":549},[532,10360,550],{"class":549},[532,10362,10168],{"class":553},[532,10364,557],{"class":549},[532,10366,1388],{"class":549},[532,10368,10369,10371,10373,10375,10378,10380],{"class":534,"line":4038},[532,10370,10177],{"class":1756},[532,10372,954],{"class":549},[532,10374,550],{"class":549},[532,10376,10377],{"class":553},"message",[532,10379,557],{"class":549},[532,10381,1388],{"class":549},[532,10383,10384,10386,10388,10390,10393,10395,10397,10399,10401],{"class":534,"line":4059},[532,10385,10193],{"class":1756},[532,10387,954],{"class":549},[532,10389,1339],{"class":549},[532,10391,10392],{"class":1756}," text",[532,10394,954],{"class":549},[532,10396,550],{"class":549},[532,10398,1861],{"class":553},[532,10400,557],{"class":549},[532,10402,2437],{"class":549},[532,10404,10405,10407],{"class":534,"line":4064},[532,10406,1659],{"class":549},[532,10408,1203],{"class":560},[532,10410,10411],{"class":534,"line":4077},[532,10412,10413],{"class":538},"\u002F\u002F resp === 'ok'\n",[532,10415,10416],{"class":534,"line":4091},[532,10417,596],{"emptyLinePlaceholder":595},[532,10419,10420],{"class":534,"line":4112},[532,10421,10422],{"class":538},"\u002F\u002F ============ PRESENCE (Online status \u002F Multiplayer state) ============\n",[532,10424,10425],{"class":534,"line":4126},[532,10426,596],{"emptyLinePlaceholder":595},[532,10428,10429],{"class":534,"line":4131},[532,10430,10431],{"class":538},"\u002F\u002F Track presence state của user hiện tại\n",[532,10433,10434,10436,10438,10440,10443,10445],{"class":534,"line":4137},[532,10435,10146],{"class":1335},[532,10437,4681],{"class":560},[532,10439,448],{"class":549},[532,10441,10442],{"class":1372},"track",[532,10444,1197],{"class":560},[532,10446,2288],{"class":549},[532,10448,10449,10452,10454,10456,10459,10461],{"class":534,"line":4156},[532,10450,10451],{"class":1756},"  user_id",[532,10453,954],{"class":549},[532,10455,550],{"class":549},[532,10457,10458],{"class":553},"user-123",[532,10460,557],{"class":549},[532,10462,1388],{"class":549},[532,10464,10465,10468,10470,10472,10474,10476,10478,10480,10482],{"class":534,"line":4170},[532,10466,10467],{"class":1756},"  online_at",[532,10469,954],{"class":549},[532,10471,8676],{"class":549},[532,10473,8679],{"class":1372},[532,10475,8682],{"class":560},[532,10477,448],{"class":549},[532,10479,8687],{"class":1372},[532,10481,8682],{"class":560},[532,10483,1388],{"class":549},[532,10485,10486,10489,10491,10493,10496,10498],{"class":534,"line":4195},[532,10487,10488],{"class":1756},"  status",[532,10490,954],{"class":549},[532,10492,550],{"class":549},[532,10494,10495],{"class":553},"online",[532,10497,557],{"class":549},[532,10499,1388],{"class":549},[532,10501,10502,10505,10507,10509,10511,10513,10515,10517,10519,10521,10523],{"class":534,"line":4228},[532,10503,10504],{"class":1756},"  cursor",[532,10506,954],{"class":549},[532,10508,1339],{"class":549},[532,10510,10200],{"class":1756},[532,10512,954],{"class":549},[532,10514,8961],{"class":1782},[532,10516,1653],{"class":549},[532,10518,10209],{"class":1756},[532,10520,954],{"class":549},[532,10522,8961],{"class":1782},[532,10524,2437],{"class":549},[532,10526,10527,10529],{"class":534,"line":4241},[532,10528,1659],{"class":549},[532,10530,1203],{"class":560},[532,10532,10533],{"class":534,"line":4255},[532,10534,596],{"emptyLinePlaceholder":595},[532,10536,10537],{"class":534,"line":5246},[532,10538,10539],{"class":538},"\u002F\u002F Lắng nghe presence state của tất cả users\n",[532,10541,10542,10544,10546,10548,10550,10552,10555,10557],{"class":534,"line":5286},[532,10543,2358],{"class":560},[532,10545,448],{"class":549},[532,10547,2377],{"class":1372},[532,10549,1197],{"class":560},[532,10551,557],{"class":549},[532,10553,10554],{"class":553},"presence",[532,10556,557],{"class":549},[532,10558,1388],{"class":549},[532,10560,10561,10563,10565,10567,10569,10572,10574],{"class":534,"line":5291},[532,10562,5958],{"class":549},[532,10564,2397],{"class":1756},[532,10566,954],{"class":549},[532,10568,550],{"class":549},[532,10570,10571],{"class":553},"sync",[532,10573,557],{"class":549},[532,10575,2437],{"class":549},[532,10577,10578,10581,10583],{"class":534,"line":5297},[532,10579,10580],{"class":549},"  ()",[532,10582,2452],{"class":1363},[532,10584,2628],{"class":549},[532,10586,10587,10590,10593,10595,10597,10599,10602],{"class":534,"line":5336},[532,10588,10589],{"class":1363},"    const",[532,10591,10592],{"class":560}," state",[532,10594,1662],{"class":549},[532,10596,4681],{"class":560},[532,10598,448],{"class":549},[532,10600,10601],{"class":1372},"presenceState",[532,10603,1996],{"class":1756},[532,10605,10606],{"class":534,"line":5341},[532,10607,10608],{"class":538},"    \u002F\u002F state = {\n",[532,10610,10611],{"class":534,"line":5347},[532,10612,10613],{"class":538},"    \u002F\u002F   'user-123': [{ user_id: 'user-123', status: 'online', ... }],\n",[532,10615,10616],{"class":534,"line":5379},[532,10617,10618],{"class":538},"    \u002F\u002F   'user-456': [{ user_id: 'user-456', status: 'away', ... }],\n",[532,10620,10621],{"class":534,"line":5400},[532,10622,10623],{"class":538},"    \u002F\u002F }\n",[532,10625,10626,10628,10630,10632,10634,10636,10639,10641,10643,10646,10648,10651,10653,10656],{"class":534,"line":5405},[532,10627,5552],{"class":560},[532,10629,448],{"class":549},[532,10631,2460],{"class":1372},[532,10633,1197],{"class":1756},[532,10635,557],{"class":549},[532,10637,10638],{"class":553},"Online users:",[532,10640,557],{"class":549},[532,10642,1653],{"class":549},[532,10644,10645],{"class":560}," Object",[532,10647,448],{"class":549},[532,10649,10650],{"class":1372},"keys",[532,10652,1197],{"class":1756},[532,10654,10655],{"class":560},"state",[532,10657,10658],{"class":1756},"))\n",[532,10660,10661],{"class":534,"line":5411},[532,10662,4428],{"class":549},[532,10664,10665],{"class":534,"line":5445},[532,10666,1203],{"class":560},[532,10668,10669],{"class":534,"line":5461},[532,10670,596],{"emptyLinePlaceholder":595},[532,10672,10673],{"class":534,"line":5477},[532,10674,10675],{"class":538},"\u002F\u002F Lắng nghe khi có user join\n",[532,10677,10678,10680,10682,10684,10686,10688,10690,10692],{"class":534,"line":5484},[532,10679,2358],{"class":560},[532,10681,448],{"class":549},[532,10683,2377],{"class":1372},[532,10685,1197],{"class":560},[532,10687,557],{"class":549},[532,10689,10554],{"class":553},[532,10691,557],{"class":549},[532,10693,1388],{"class":549},[532,10695,10696,10698,10700,10702,10704,10707,10709],{"class":534,"line":5489},[532,10697,5958],{"class":549},[532,10699,2397],{"class":1756},[532,10701,954],{"class":549},[532,10703,550],{"class":549},[532,10705,10706],{"class":553},"join",[532,10708,557],{"class":549},[532,10710,2437],{"class":549},[532,10712,10713,10716,10718,10720,10723,10726,10728],{"class":534,"line":5495},[532,10714,10715],{"class":549},"  ({",[532,10717,3048],{"class":2446},[532,10719,1653],{"class":549},[532,10721,10722],{"class":2446}," newPresences",[532,10724,10725],{"class":549}," })",[532,10727,2452],{"class":1363},[532,10729,2628],{"class":549},[532,10731,10732,10734,10736,10738,10740,10742,10745,10747,10749,10751,10753,10755],{"class":534,"line":5530},[532,10733,5552],{"class":560},[532,10735,448],{"class":549},[532,10737,2460],{"class":1372},[532,10739,1197],{"class":1756},[532,10741,557],{"class":549},[532,10743,10744],{"class":553},"User joined:",[532,10746,557],{"class":549},[532,10748,1653],{"class":549},[532,10750,3048],{"class":560},[532,10752,1653],{"class":549},[532,10754,10722],{"class":560},[532,10756,1203],{"class":1756},[532,10758,10759],{"class":534,"line":5549},[532,10760,4428],{"class":549},[532,10762,10763],{"class":534,"line":5577},[532,10764,1203],{"class":560},[532,10766,10767],{"class":534,"line":5583},[532,10768,596],{"emptyLinePlaceholder":595},[532,10770,10771],{"class":534,"line":5589},[532,10772,10773],{"class":538},"\u002F\u002F Lắng nghe khi có user leave\n",[532,10775,10776,10778,10780,10782,10784,10786,10788,10790],{"class":534,"line":5613},[532,10777,2358],{"class":560},[532,10779,448],{"class":549},[532,10781,2377],{"class":1372},[532,10783,1197],{"class":560},[532,10785,557],{"class":549},[532,10787,10554],{"class":553},[532,10789,557],{"class":549},[532,10791,1388],{"class":549},[532,10793,10794,10796,10798,10800,10802,10805,10807],{"class":534,"line":5618},[532,10795,5958],{"class":549},[532,10797,2397],{"class":1756},[532,10799,954],{"class":549},[532,10801,550],{"class":549},[532,10803,10804],{"class":553},"leave",[532,10806,557],{"class":549},[532,10808,2437],{"class":549},[532,10810,10811,10813,10815,10817,10820,10822,10824],{"class":534,"line":5623},[532,10812,10715],{"class":549},[532,10814,3048],{"class":2446},[532,10816,1653],{"class":549},[532,10818,10819],{"class":2446}," leftPresences",[532,10821,10725],{"class":549},[532,10823,2452],{"class":1363},[532,10825,2628],{"class":549},[532,10827,10828,10830,10832,10834,10836,10838,10841,10843,10845,10847,10849,10851],{"class":534,"line":5629},[532,10829,5552],{"class":560},[532,10831,448],{"class":549},[532,10833,2460],{"class":1372},[532,10835,1197],{"class":1756},[532,10837,557],{"class":549},[532,10839,10840],{"class":553},"User left:",[532,10842,557],{"class":549},[532,10844,1653],{"class":549},[532,10846,3048],{"class":560},[532,10848,1653],{"class":549},[532,10850,10819],{"class":560},[532,10852,1203],{"class":1756},[532,10854,10855],{"class":534,"line":5634},[532,10856,4428],{"class":549},[532,10858,10859],{"class":534,"line":5640},[532,10860,1203],{"class":560},[532,10862,10863],{"class":534,"line":5668},[532,10864,596],{"emptyLinePlaceholder":595},[532,10866,10867],{"class":534,"line":5674},[532,10868,10869],{"class":538},"\u002F\u002F Untrack (remove presence)\n",[532,10871,10872,10874,10876,10878,10881],{"class":534,"line":5719},[532,10873,10146],{"class":1335},[532,10875,4681],{"class":560},[532,10877,448],{"class":549},[532,10879,10880],{"class":1372},"untrack",[532,10882,1996],{"class":560},[532,10884,10885],{"class":534,"line":5725},[532,10886,596],{"emptyLinePlaceholder":595},[532,10888,10889],{"class":534,"line":5769},[532,10890,10891],{"class":538},"\u002F\u002F ============ SUBSCRIBE & UNSUBSCRIBE ============\n",[532,10893,10894],{"class":534,"line":5774},[532,10895,596],{"emptyLinePlaceholder":595},[532,10897,10898],{"class":534,"line":5780},[532,10899,10900],{"class":538},"\u002F\u002F Subscribe — bắt đầu nhận events\n",[532,10902,10903,10905,10907,10909,10911,10914,10917,10919,10921,10924,10926,10928],{"class":534,"line":5785},[532,10904,2358],{"class":560},[532,10906,448],{"class":549},[532,10908,2493],{"class":1372},[532,10910,1197],{"class":560},[532,10912,10913],{"class":1363},"async",[532,10915,10916],{"class":549}," (",[532,10918,1717],{"class":2446},[532,10920,1653],{"class":549},[532,10922,10923],{"class":2446}," err",[532,10925,1310],{"class":549},[532,10927,2452],{"class":1363},[532,10929,2628],{"class":549},[532,10931,10932,10935,10937,10939,10942,10944,10947,10949,10951],{"class":534,"line":5791},[532,10933,10934],{"class":1335},"  if",[532,10936,10916],{"class":1756},[532,10938,1717],{"class":560},[532,10940,10941],{"class":549}," ===",[532,10943,550],{"class":549},[532,10945,10946],{"class":553},"SUBSCRIBED",[532,10948,557],{"class":549},[532,10950,1768],{"class":1756},[532,10952,2288],{"class":549},[532,10954,10955,10957,10959,10961,10963,10965,10968,10970,10972,10974,10976,10979],{"class":534,"line":5825},[532,10956,5552],{"class":560},[532,10958,448],{"class":549},[532,10960,2460],{"class":1372},[532,10962,1197],{"class":1756},[532,10964,557],{"class":549},[532,10966,10967],{"class":553},"Connected to channel:",[532,10969,557],{"class":549},[532,10971,1653],{"class":549},[532,10973,4681],{"class":560},[532,10975,448],{"class":549},[532,10977,10978],{"class":560},"topic",[532,10980,1203],{"class":1756},[532,10982,10983],{"class":534,"line":5841},[532,10984,4428],{"class":549},[532,10986,10987,10989,10991,10993,10995,10997,11000,11002,11004],{"class":534,"line":5857},[532,10988,10934],{"class":1335},[532,10990,10916],{"class":1756},[532,10992,1717],{"class":560},[532,10994,10941],{"class":549},[532,10996,550],{"class":549},[532,10998,10999],{"class":553},"CHANNEL_ERROR",[532,11001,557],{"class":549},[532,11003,1768],{"class":1756},[532,11005,2288],{"class":549},[532,11007,11008,11010,11012,11015,11017,11019,11022,11024,11026,11028],{"class":534,"line":5894},[532,11009,5552],{"class":560},[532,11011,448],{"class":549},[532,11013,11014],{"class":1372},"error",[532,11016,1197],{"class":1756},[532,11018,557],{"class":549},[532,11020,11021],{"class":553},"Channel error:",[532,11023,557],{"class":549},[532,11025,1653],{"class":549},[532,11027,10923],{"class":560},[532,11029,1203],{"class":1756},[532,11031,11032],{"class":534,"line":5901},[532,11033,4428],{"class":549},[532,11035,11036,11038,11040,11042,11044,11046,11049,11051,11053],{"class":534,"line":5906},[532,11037,10934],{"class":1335},[532,11039,10916],{"class":1756},[532,11041,1717],{"class":560},[532,11043,10941],{"class":549},[532,11045,550],{"class":549},[532,11047,11048],{"class":553},"TIMED_OUT",[532,11050,557],{"class":549},[532,11052,1768],{"class":1756},[532,11054,2288],{"class":549},[532,11056,11057,11059,11061,11064,11066,11068,11071,11073],{"class":534,"line":5912},[532,11058,5552],{"class":560},[532,11060,448],{"class":549},[532,11062,11063],{"class":1372},"warn",[532,11065,1197],{"class":1756},[532,11067,557],{"class":549},[532,11069,11070],{"class":553},"Channel timed out — retrying...",[532,11072,557],{"class":549},[532,11074,1203],{"class":1756},[532,11076,11077],{"class":534,"line":5944},[532,11078,4428],{"class":549},[532,11080,11081,11083,11085,11087,11089,11091,11094,11096,11098],{"class":534,"line":5955},[532,11082,10934],{"class":1335},[532,11084,10916],{"class":1756},[532,11086,1717],{"class":560},[532,11088,10941],{"class":549},[532,11090,550],{"class":549},[532,11092,11093],{"class":553},"CLOSED",[532,11095,557],{"class":549},[532,11097,1768],{"class":1756},[532,11099,2288],{"class":549},[532,11101,11102,11104,11106,11108,11110,11112,11115,11117],{"class":534,"line":5975},[532,11103,5552],{"class":560},[532,11105,448],{"class":549},[532,11107,2460],{"class":1372},[532,11109,1197],{"class":1756},[532,11111,557],{"class":549},[532,11113,11114],{"class":553},"Channel closed",[532,11116,557],{"class":549},[532,11118,1203],{"class":1756},[532,11120,11121],{"class":534,"line":5980},[532,11122,4428],{"class":549},[532,11124,11125,11127],{"class":534,"line":5985},[532,11126,1659],{"class":549},[532,11128,1203],{"class":560},[532,11130,11131],{"class":534,"line":5991},[532,11132,596],{"emptyLinePlaceholder":595},[532,11134,11135],{"class":534,"line":6023},[532,11136,11137],{"class":538},"\u002F\u002F Unsubscribe channel cụ thể\n",[532,11139,11140,11142,11144,11146,11149],{"class":534,"line":6028},[532,11141,10146],{"class":1335},[532,11143,2273],{"class":560},[532,11145,448],{"class":549},[532,11147,11148],{"class":1372},"removeChannel",[532,11150,11151],{"class":560},"(channel)\n",[532,11153,11154],{"class":534,"line":6034},[532,11155,596],{"emptyLinePlaceholder":595},[532,11157,11158],{"class":534,"line":6068},[532,11159,11160],{"class":538},"\u002F\u002F Unsubscribe tất cả channels\n",[532,11162,11163,11165,11167,11169,11172],{"class":534,"line":6088},[532,11164,10146],{"class":1335},[532,11166,2273],{"class":560},[532,11168,448],{"class":549},[532,11170,11171],{"class":1372},"removeAllChannels",[532,11173,1996],{"class":560},[532,11175,11176],{"class":534,"line":6103},[532,11177,596],{"emptyLinePlaceholder":595},[532,11179,11180],{"class":534,"line":6112},[532,11181,11182],{"class":538},"\u002F\u002F Get tất cả channels đang active\n",[532,11184,11185,11187,11190,11192,11194,11196,11199],{"class":534,"line":6126},[532,11186,1364],{"class":1363},[532,11188,11189],{"class":560}," channels ",[532,11191,982],{"class":549},[532,11193,2273],{"class":560},[532,11195,448],{"class":549},[532,11197,11198],{"class":1372},"getChannels",[532,11200,1996],{"class":560},[532,11202,11203],{"class":534,"line":6131},[532,11204,596],{"emptyLinePlaceholder":595},[532,11206,11207],{"class":534,"line":6138},[532,11208,11209],{"class":538},"\u002F\u002F ============ CONNECTION STATUS ============\n",[532,11211,11212],{"class":534,"line":6143},[532,11213,596],{"emptyLinePlaceholder":595},[532,11215,11216],{"class":534,"line":6149},[532,11217,11218],{"class":538},"\u002F\u002F Kiểm tra kết nối Realtime\n",[532,11220,11221,11224,11227,11229,11232,11234,11237,11240],{"class":534,"line":6183},[532,11222,11223],{"class":1335},"if",[532,11225,11226],{"class":560}," (supabase",[532,11228,448],{"class":549},[532,11230,11231],{"class":560},"realtime",[532,11233,448],{"class":549},[532,11235,11236],{"class":1372},"isConnected",[532,11238,11239],{"class":560},"()) ",[532,11241,2288],{"class":549},[532,11243,11244,11247,11249,11251,11253,11255,11258,11260],{"class":534,"line":6198},[532,11245,11246],{"class":560},"  console",[532,11248,448],{"class":549},[532,11250,2460],{"class":1372},[532,11252,1197],{"class":1756},[532,11254,557],{"class":549},[532,11256,11257],{"class":553},"Realtime connected",[532,11259,557],{"class":549},[532,11261,1203],{"class":1756},[532,11263,11264],{"class":534,"line":6214},[532,11265,11266],{"class":549},"}\n",[532,11268,11269],{"class":534,"line":6232},[532,11270,596],{"emptyLinePlaceholder":595},[532,11272,11273],{"class":534,"line":6238},[532,11274,11275],{"class":538},"\u002F\u002F Manually connect (auto-connect khi có channel đầu tiên subscribe)\n",[532,11277,11278,11281,11283,11285,11287,11290],{"class":534,"line":6245},[532,11279,11280],{"class":560},"supabase",[532,11282,448],{"class":549},[532,11284,11231],{"class":560},[532,11286,448],{"class":549},[532,11288,11289],{"class":1372},"connect",[532,11291,1996],{"class":560},[532,11293,11294],{"class":534,"line":6250},[532,11295,596],{"emptyLinePlaceholder":595},[532,11297,11298],{"class":534,"line":6256},[532,11299,11300],{"class":538},"\u002F\u002F Manually disconnect\n",[532,11302,11303,11305,11307,11309,11311,11314],{"class":534,"line":6297},[532,11304,11280],{"class":560},[532,11306,448],{"class":549},[532,11308,11231],{"class":560},[532,11310,448],{"class":549},[532,11312,11313],{"class":1372},"disconnect",[532,11315,1996],{"class":560},[532,11317,11318],{"class":534,"line":6302},[532,11319,596],{"emptyLinePlaceholder":595},[532,11321,11322],{"class":534,"line":6308},[532,11323,11324],{"class":538},"\u002F\u002F ============ REALTIME TOPICS ============\n",[532,11326,11327],{"class":534,"line":6342},[532,11328,11329],{"class":538},"\u002F\u002F Mỗi channel có một topic unique:\n",[532,11331,11332],{"class":534,"line":6357},[532,11333,11334],{"class":538},"\u002F\u002F 'realtime:public:posts' — dùng topic prefix của Supabase Realtime v2\n",[532,11336,11337],{"class":534,"line":6364},[532,11338,596],{"emptyLinePlaceholder":595},[532,11340,11341],{"class":534,"line":6369},[532,11342,11343],{"class":538},"\u002F\u002F ============ FULL EXAMPLE: Real-time Chat Room ============\n",[532,11345,11346],{"class":534,"line":6375},[532,11347,596],{"emptyLinePlaceholder":595},[532,11349,11350,11352,11355,11358,11360,11363,11365,11368,11370],{"class":534,"line":6409},[532,11351,10913],{"class":1363},[532,11353,11354],{"class":1363}," function",[532,11356,11357],{"class":1372}," joinChatRoom",[532,11359,1197],{"class":549},[532,11361,11362],{"class":2446},"roomId",[532,11364,1653],{"class":549},[532,11366,11367],{"class":2446}," userId",[532,11369,1310],{"class":549},[532,11371,2628],{"class":549},[532,11373,11374,11377,11379,11381,11383,11385,11387,11389,11392,11395,11398,11400,11403],{"class":534,"line":6424},[532,11375,11376],{"class":1363},"  const",[532,11378,4681],{"class":560},[532,11380,1662],{"class":549},[532,11382,2273],{"class":560},[532,11384,448],{"class":549},[532,11386,2358],{"class":1372},[532,11388,1197],{"class":1756},[532,11390,11391],{"class":549},"`",[532,11393,11394],{"class":553},"room:",[532,11396,11397],{"class":549},"${",[532,11399,11362],{"class":560},[532,11401,11402],{"class":549},"}`",[532,11404,1203],{"class":1756},[532,11406,11407],{"class":534,"line":6431},[532,11408,596],{"emptyLinePlaceholder":595},[532,11410,11411],{"class":534,"line":6436},[532,11412,11413],{"class":538},"  \u002F\u002F Lắng nghe tin nhắn mới\n",[532,11415,11416,11419,11421,11423,11425,11427,11429,11431,11433,11435,11437,11439,11441,11444,11446,11448,11450,11452,11454,11456],{"class":534,"line":6442},[532,11417,11418],{"class":560},"  channel",[532,11420,448],{"class":549},[532,11422,2377],{"class":1372},[532,11424,1197],{"class":1756},[532,11426,557],{"class":549},[532,11428,10168],{"class":553},[532,11430,557],{"class":549},[532,11432,1653],{"class":549},[532,11434,1339],{"class":549},[532,11436,2397],{"class":1756},[532,11438,954],{"class":549},[532,11440,550],{"class":549},[532,11442,11443],{"class":553},"new-message",[532,11445,557],{"class":549},[532,11447,2075],{"class":549},[532,11449,10916],{"class":549},[532,11451,2447],{"class":2446},[532,11453,1310],{"class":549},[532,11455,2452],{"class":1363},[532,11457,2628],{"class":549},[532,11459,11460,11463,11465,11467],{"class":534,"line":6471},[532,11461,11462],{"class":1372},"    addMessageToUI",[532,11464,1197],{"class":1756},[532,11466,2447],{"class":560},[532,11468,1203],{"class":1756},[532,11470,11471,11474],{"class":534,"line":6476},[532,11472,11473],{"class":549},"  }",[532,11475,1203],{"class":1756},[532,11477,11478],{"class":534,"line":6482},[532,11479,596],{"emptyLinePlaceholder":595},[532,11481,11482],{"class":534,"line":6487},[532,11483,11484],{"class":538},"  \u002F\u002F Track presence (ai đang online)\n",[532,11486,11487,11489,11491,11493,11495,11497,11499,11501,11503,11505,11507,11509,11511,11513,11515,11517,11520,11522],{"class":534,"line":6493},[532,11488,11418],{"class":560},[532,11490,448],{"class":549},[532,11492,2377],{"class":1372},[532,11494,1197],{"class":1756},[532,11496,557],{"class":549},[532,11498,10554],{"class":553},[532,11500,557],{"class":549},[532,11502,1653],{"class":549},[532,11504,1339],{"class":549},[532,11506,2397],{"class":1756},[532,11508,954],{"class":549},[532,11510,550],{"class":549},[532,11512,10571],{"class":553},[532,11514,557],{"class":549},[532,11516,2075],{"class":549},[532,11518,11519],{"class":549}," ()",[532,11521,2452],{"class":1363},[532,11523,2628],{"class":549},[532,11525,11526,11529,11531,11533,11535,11537],{"class":534,"line":6532},[532,11527,11528],{"class":1372},"    updateOnlineUsersList",[532,11530,1197],{"class":1756},[532,11532,2358],{"class":560},[532,11534,448],{"class":549},[532,11536,10601],{"class":1372},[532,11538,9479],{"class":1756},[532,11540,11541,11543],{"class":534,"line":6549},[532,11542,11473],{"class":549},[532,11544,1203],{"class":1756},[532,11546,11547],{"class":534,"line":6569},[532,11548,596],{"emptyLinePlaceholder":595},[532,11550,11551,11553,11555,11557,11559,11561,11563,11565,11567,11569],{"class":534,"line":6585},[532,11552,11418],{"class":560},[532,11554,448],{"class":549},[532,11556,2493],{"class":1372},[532,11558,1197],{"class":1756},[532,11560,10913],{"class":1363},[532,11562,10916],{"class":549},[532,11564,1717],{"class":2446},[532,11566,1310],{"class":549},[532,11568,2452],{"class":1363},[532,11570,2628],{"class":549},[532,11572,11573,11576,11578,11580,11582,11584,11586,11588,11590],{"class":534,"line":6592},[532,11574,11575],{"class":1335},"    if",[532,11577,10916],{"class":1756},[532,11579,1717],{"class":560},[532,11581,10941],{"class":549},[532,11583,550],{"class":549},[532,11585,10946],{"class":553},[532,11587,557],{"class":549},[532,11589,1768],{"class":1756},[532,11591,2288],{"class":549},[532,11593,11594,11597,11599,11601,11603,11605,11607,11609,11611,11613,11615,11618,11620,11622,11624,11626,11628,11630,11633,11635],{"class":534,"line":6598},[532,11595,11596],{"class":1335},"      await",[532,11598,4681],{"class":560},[532,11600,448],{"class":549},[532,11602,10442],{"class":1372},[532,11604,1197],{"class":1756},[532,11606,1851],{"class":549},[532,11608,2227],{"class":1756},[532,11610,954],{"class":549},[532,11612,11367],{"class":560},[532,11614,1653],{"class":549},[532,11616,11617],{"class":1756}," joined_at",[532,11619,954],{"class":549},[532,11621,8676],{"class":549},[532,11623,8679],{"class":1372},[532,11625,8682],{"class":1756},[532,11627,448],{"class":549},[532,11629,8687],{"class":1372},[532,11631,11632],{"class":1756},"() ",[532,11634,1659],{"class":549},[532,11636,1203],{"class":1756},[532,11638,11639],{"class":534,"line":6604},[532,11640,11641],{"class":549},"    }\n",[532,11643,11644,11646],{"class":534,"line":6610},[532,11645,11473],{"class":549},[532,11647,1203],{"class":1756},[532,11649,11650],{"class":534,"line":6615},[532,11651,596],{"emptyLinePlaceholder":595},[532,11653,11654,11657],{"class":534,"line":6621},[532,11655,11656],{"class":1335},"  return",[532,11658,11659],{"class":560}," channel\n",[532,11661,11662],{"class":534,"line":6659},[532,11663,11266],{"class":549},[532,11665,11666],{"class":534,"line":6676},[532,11667,596],{"emptyLinePlaceholder":595},[532,11669,11670,11672,11674,11677,11679,11681,11683,11685,11687],{"class":534,"line":6683},[532,11671,10913],{"class":1363},[532,11673,11354],{"class":1363},[532,11675,11676],{"class":1372}," sendMessage",[532,11678,1197],{"class":549},[532,11680,2358],{"class":2446},[532,11682,1653],{"class":549},[532,11684,10392],{"class":2446},[532,11686,1310],{"class":549},[532,11688,2628],{"class":549},[532,11690,11691,11693,11695,11697,11699,11701],{"class":534,"line":6689},[532,11692,9442],{"class":1335},[532,11694,4681],{"class":560},[532,11696,448],{"class":549},[532,11698,10153],{"class":1372},[532,11700,1197],{"class":1756},[532,11702,2288],{"class":549},[532,11704,11705,11708,11710,11712,11714,11716],{"class":534,"line":6694},[532,11706,11707],{"class":1756},"    type",[532,11709,954],{"class":549},[532,11711,550],{"class":549},[532,11713,10168],{"class":553},[532,11715,557],{"class":549},[532,11717,1388],{"class":549},[532,11719,11720,11722,11724,11726,11728,11730],{"class":534,"line":6700},[532,11721,10038],{"class":1756},[532,11723,954],{"class":549},[532,11725,550],{"class":549},[532,11727,11443],{"class":553},[532,11729,557],{"class":549},[532,11731,1388],{"class":549},[532,11733,11734,11737,11739,11741,11743,11745,11748,11750,11752,11754,11757,11759,11761,11763,11765,11767,11769,11771],{"class":534,"line":6738},[532,11735,11736],{"class":1756},"    payload",[532,11738,954],{"class":549},[532,11740,1339],{"class":549},[532,11742,10392],{"class":560},[532,11744,1653],{"class":549},[532,11746,11747],{"class":1756}," sender",[532,11749,954],{"class":549},[532,11751,11367],{"class":560},[532,11753,1653],{"class":549},[532,11755,11756],{"class":1756}," timestamp",[532,11758,954],{"class":549},[532,11760,8676],{"class":549},[532,11762,8679],{"class":1372},[532,11764,8682],{"class":1756},[532,11766,448],{"class":549},[532,11768,8687],{"class":1372},[532,11770,11632],{"class":1756},[532,11772,11773],{"class":549},"},\n",[532,11775,11776,11778],{"class":534,"line":6754},[532,11777,11473],{"class":549},[532,11779,1203],{"class":1756},[532,11781,11782],{"class":534,"line":6771},[532,11783,11266],{"class":549},[450,11785,11787],{"id":11786},"type-generation-type-safe-queries","Type Generation -- Type-safe Queries",[432,11789,11790],{},"Supabase hỗ trợ generate TypeScript types từ database schema:",[523,11792,11794],{"className":525,"code":11793,"language":527,"meta":528,"style":528},"# Generate types từ local database\nsupabase gen types typescript --local > types\u002Fsupabase.ts\n\n# Generate types từ linked remote project\nsupabase gen types typescript --linked > types\u002Fsupabase.ts\n",[445,11795,11796,11801,11823,11827,11832],{"__ignoreMap":528},[532,11797,11798],{"class":534,"line":535},[532,11799,11800],{"class":538},"# Generate types từ local database\n",[532,11802,11803,11805,11808,11811,11814,11817,11820],{"class":534,"line":542},[532,11804,11280],{"class":545},[532,11806,11807],{"class":553}," gen",[532,11809,11810],{"class":553}," types",[532,11812,11813],{"class":553}," typescript",[532,11815,11816],{"class":553}," --local",[532,11818,11819],{"class":549}," >",[532,11821,11822],{"class":553}," types\u002Fsupabase.ts\n",[532,11824,11825],{"class":534,"line":564},[532,11826,596],{"emptyLinePlaceholder":595},[532,11828,11829],{"class":534,"line":579},[532,11830,11831],{"class":538},"# Generate types từ linked remote project\n",[532,11833,11834,11836,11838,11840,11842,11845,11847],{"class":534,"line":592},[532,11835,11280],{"class":545},[532,11837,11807],{"class":553},[532,11839,11810],{"class":553},[532,11841,11813],{"class":553},[532,11843,11844],{"class":553}," --linked",[532,11846,11819],{"class":549},[532,11848,11822],{"class":553},[432,11850,11851],{},"Sau khi generate, bạn có type-safe queries:",[523,11853,11857],{"className":11854,"code":11855,"language":11856,"meta":528,"style":528},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Database } from '@\u002Ftypes\u002Fsupabase'\n\nconst supabase = createClient\u003CDatabase>(url, key)\n\n\u002F\u002F TypeScript sẽ báo lỗi nếu bạn query sai tên bảng hoặc cột\nconst { data } = await supabase\n  .from('posts')            \u002F\u002F ✅ auto-complete: 'posts'\n  .select('id, title')      \u002F\u002F ✅ auto-complete: 'id' | 'title' | 'content' | ...\n  .eq('status', 'published') \u002F\u002F ✅ auto-complete: 'draft' | 'published' | 'archived'\n","typescript",[445,11858,11859,11879,11883,11907,11911,11916,11932,11951,11971],{"__ignoreMap":528},[532,11860,11861,11863,11865,11868,11870,11872,11874,11877],{"class":534,"line":535},[532,11862,1336],{"class":1335},[532,11864,1339],{"class":549},[532,11866,11867],{"class":560}," Database",[532,11869,1345],{"class":549},[532,11871,1348],{"class":1335},[532,11873,550],{"class":549},[532,11875,11876],{"class":553},"@\u002Ftypes\u002Fsupabase",[532,11878,589],{"class":549},[532,11880,11881],{"class":534,"line":542},[532,11882,596],{"emptyLinePlaceholder":595},[532,11884,11885,11887,11889,11891,11893,11895,11897,11899,11902,11904],{"class":534,"line":564},[532,11886,1364],{"class":1363},[532,11888,1367],{"class":560},[532,11890,982],{"class":549},[532,11892,1342],{"class":1372},[532,11894,1042],{"class":549},[532,11896,162],{"class":545},[532,11898,1012],{"class":549},[532,11900,11901],{"class":560},"(url",[532,11903,1653],{"class":549},[532,11905,11906],{"class":560}," key)\n",[532,11908,11909],{"class":534,"line":579},[532,11910,596],{"emptyLinePlaceholder":595},[532,11912,11913],{"class":534,"line":592},[532,11914,11915],{"class":538},"\u002F\u002F TypeScript sẽ báo lỗi nếu bạn query sai tên bảng hoặc cột\n",[532,11917,11918,11920,11922,11924,11926,11928,11930],{"class":534,"line":599},[532,11919,1364],{"class":1363},[532,11921,1339],{"class":549},[532,11923,6449],{"class":560},[532,11925,1659],{"class":549},[532,11927,1662],{"class":549},[532,11929,1665],{"class":1335},[532,11931,1668],{"class":560},[532,11933,11934,11936,11938,11940,11942,11944,11946,11948],{"class":534,"line":605},[532,11935,1673],{"class":549},[532,11937,1676],{"class":1372},[532,11939,1197],{"class":560},[532,11941,557],{"class":549},[532,11943,1683],{"class":553},[532,11945,557],{"class":549},[532,11947,2948],{"class":560},[532,11949,11950],{"class":538},"\u002F\u002F ✅ auto-complete: 'posts'\n",[532,11952,11953,11955,11957,11959,11961,11964,11966,11968],{"class":534,"line":619},[532,11954,1673],{"class":549},[532,11956,870],{"class":1372},[532,11958,1197],{"class":560},[532,11960,557],{"class":549},[532,11962,11963],{"class":553},"id, title",[532,11965,557],{"class":549},[532,11967,3024],{"class":560},[532,11969,11970],{"class":538},"\u002F\u002F ✅ auto-complete: 'id' | 'title' | 'content' | ...\n",[532,11972,11973,11975,11977,11979,11981,11983,11985,11987,11989,11991,11993,11995],{"class":534,"line":630},[532,11974,1673],{"class":549},[532,11976,977],{"class":1372},[532,11978,1197],{"class":560},[532,11980,557],{"class":549},[532,11982,1717],{"class":553},[532,11984,557],{"class":549},[532,11986,1653],{"class":549},[532,11988,550],{"class":549},[532,11990,1726],{"class":553},[532,11992,557],{"class":549},[532,11994,1768],{"class":560},[532,11996,11997],{"class":538},"\u002F\u002F ✅ auto-complete: 'draft' | 'published' | 'archived'\n",[496,11999,12000,12003],{"color":498,"icon":499},[436,12001,12002],{},"Type generation là best practice"," khi làm việc với Supabase + TypeScript. Nó giúp phát hiện lỗi schema mismatch ngay khi compile, auto-complete column names, và đảm bảo type safety cho toàn bộ data layer.",[496,12005,12006,12009,12010,12013],{"color":498,"icon":499},[436,12007,12008],{},"Interview tip — supabase-js:"," SDK supabase-js là isomorphic (chạy được cả browser và Node.js). Filter chain dùng builder pattern (",[445,12011,12012],{},"supabase.from('table').select().eq().order()","). Auth module tích hợp sẵn OAuth, MFA, session management không cần cấu hình thêm. Realtime module dựa trên WebSocket, hỗ trợ 3 pattern: Postgres Changes (CDC), Broadcast (messaging), Presence (online tracking).",[1301,12015],{},[427,12017,12019],{"id":12018},"graphql-api-pg_graphql","GraphQL API (pg_graphql)",[432,12021,12022,12023],{},"GraphQL endpoint: ",[445,12024,12025],{},"https:\u002F\u002F[PROJECT_REF].supabase.co\u002Fgraphql\u002Fv1",[523,12027,12031],{"className":12028,"code":12029,"language":12030,"meta":528,"style":528},"language-graphql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Query GraphQL -- lấy 10 posts mới nhất kèm thông tin author\nquery {\n  postsCollection(first: 10, orderBy: [{ created_at: DescNullsLast }]) {\n    edges {\n      node {\n        id\n        title\n        created_at\n        author {\n          name\n          avatar\n        }\n      }\n    }\n  }\n}\n","graphql",[445,12032,12033,12038,12043,12048,12053,12058,12063,12068,12073,12078,12083,12088,12093,12098,12102,12106],{"__ignoreMap":528},[532,12034,12035],{"class":534,"line":535},[532,12036,12037],{},"# Query GraphQL -- lấy 10 posts mới nhất kèm thông tin author\n",[532,12039,12040],{"class":534,"line":542},[532,12041,12042],{},"query {\n",[532,12044,12045],{"class":534,"line":564},[532,12046,12047],{},"  postsCollection(first: 10, orderBy: [{ created_at: DescNullsLast }]) {\n",[532,12049,12050],{"class":534,"line":579},[532,12051,12052],{},"    edges {\n",[532,12054,12055],{"class":534,"line":592},[532,12056,12057],{},"      node {\n",[532,12059,12060],{"class":534,"line":599},[532,12061,12062],{},"        id\n",[532,12064,12065],{"class":534,"line":605},[532,12066,12067],{},"        title\n",[532,12069,12070],{"class":534,"line":619},[532,12071,12072],{},"        created_at\n",[532,12074,12075],{"class":534,"line":630},[532,12076,12077],{},"        author {\n",[532,12079,12080],{"class":534,"line":635},[532,12081,12082],{},"          name\n",[532,12084,12085],{"class":534,"line":641},[532,12086,12087],{},"          avatar\n",[532,12089,12090],{"class":534,"line":661},[532,12091,12092],{},"        }\n",[532,12094,12095],{"class":534,"line":674},[532,12096,12097],{},"      }\n",[532,12099,12100],{"class":534,"line":688},[532,12101,11641],{},[532,12103,12104],{"class":534,"line":702},[532,12105,4428],{},[532,12107,12108],{"class":534,"line":715},[532,12109,11266],{},[523,12111,12113],{"className":525,"code":12112,"language":527,"meta":528,"style":528},"# Gọi GraphQL API qua curl\ncurl -X POST 'https:\u002F\u002F[REF].supabase.co\u002Fgraphql\u002Fv1' \\\n  -H 'apikey: [ANON_KEY]' \\\n  -H 'Authorization: Bearer [ANON_KEY]' \\\n  -H 'Content-Type: application\u002Fjson' \\\n  --data-raw '{\"query\": \"{ postsCollection(first: 5) { edges { node { id title } } } }\", \"variables\": {}}'\n",[445,12114,12115,12120,12137,12149,12161,12173],{"__ignoreMap":528},[532,12116,12117],{"class":534,"line":535},[532,12118,12119],{"class":538},"# Gọi GraphQL API qua curl\n",[532,12121,12122,12124,12126,12128,12130,12133,12135],{"class":534,"line":542},[532,12123,546],{"class":545},[532,12125,646],{"class":553},[532,12127,649],{"class":553},[532,12129,550],{"class":549},[532,12131,12132],{"class":553},"https:\u002F\u002F[REF].supabase.co\u002Fgraphql\u002Fv1",[532,12134,557],{"class":549},[532,12136,561],{"class":560},[532,12138,12139,12141,12143,12145,12147],{"class":534,"line":564},[532,12140,567],{"class":553},[532,12142,550],{"class":549},[532,12144,572],{"class":553},[532,12146,557],{"class":549},[532,12148,561],{"class":560},[532,12150,12151,12153,12155,12157,12159],{"class":534,"line":579},[532,12152,567],{"class":553},[532,12154,550],{"class":549},[532,12156,586],{"class":553},[532,12158,557],{"class":549},[532,12160,561],{"class":560},[532,12162,12163,12165,12167,12169,12171],{"class":534,"line":592},[532,12164,567],{"class":553},[532,12166,550],{"class":549},[532,12168,695],{"class":553},[532,12170,557],{"class":549},[532,12172,561],{"class":560},[532,12174,12175,12178,12180,12183],{"class":534,"line":599},[532,12176,12177],{"class":553},"  --data-raw",[532,12179,550],{"class":549},[532,12181,12182],{"class":553},"{\"query\": \"{ postsCollection(first: 5) { edges { node { id title } } } }\", \"variables\": {}}",[532,12184,589],{"class":549},[432,12186,12187,12188,12191],{},"Supabase Studio có built-in ",[436,12189,12190],{},"GraphiQL IDE"," để khám phá và test GraphQL API.",[450,12193,12195],{"id":12194},"rest-vs-graphql","REST vs GraphQL",[842,12197,12198,12211],{},[845,12199,12200],{},[848,12201,12202,12205,12208],{},[851,12203,12204],{},"Tiêu chí",[851,12206,12207],{},"REST (PostgREST)",[851,12209,12210],{},"GraphQL (pg_graphql)",[861,12212,12213,12226,12239,12252,12265,12278],{},[848,12214,12215,12220,12223],{},[866,12216,12217],{},[436,12218,12219],{},"Learning curve",[866,12221,12222],{},"Thấp -- query params đơn giản",[866,12224,12225],{},"Trung bình -- cần học GraphQL syntax",[848,12227,12228,12233,12236],{},[866,12229,12230],{},[436,12231,12232],{},"Over-fetching",[866,12234,12235],{},"Có thể xảy ra",[866,12237,12238],{},"Chỉ lấy đúng field cần",[848,12240,12241,12246,12249],{},[866,12242,12243],{},[436,12244,12245],{},"Nested data",[866,12247,12248],{},"Dùng embedded resources (select)",[866,12250,12251],{},"Tự nhiên với nested queries",[848,12253,12254,12259,12262],{},[866,12255,12256],{},[436,12257,12258],{},"Tooling",[866,12260,12261],{},"Postman, curl, browser",[866,12263,12264],{},"GraphiQL IDE built-in",[848,12266,12267,12272,12275],{},[866,12268,12269],{},[436,12270,12271],{},"Performance",[866,12273,12274],{},"Nhanh hơn cho query đơn giản",[866,12276,12277],{},"Tốt hơn cho query phức tạp nhiều JOIN",[848,12279,12280,12285,12288],{},[866,12281,12282],{},[436,12283,12284],{},"Best for",[866,12286,12287],{},"CRUD đơn giản, mobile apps",[866,12289,12290],{},"Complex data fetching, nhiều relationships",[496,12292,12295,12296,1320,12299,12302],{"color":12293,"icon":12294},"warning","i-lucide-lightbulb","Cả REST và GraphQL đều ",[436,12297,12298],{},"auto-generated từ schema",[436,12300,12301],{},"tích hợp RLS",". Bạn có thể dùng cả hai trong cùng một dự án -- không cần chọn một.",[1301,12304],{},[427,12306,12308],{"id":12307},"supabase-cli-reference-đầy-đủ","Supabase CLI — Reference đầy đủ",[450,12310,12312],{"id":12311},"cài-đặt","Cài đặt",[523,12314,12316],{"className":525,"code":12315,"language":527,"meta":528,"style":528},"# npm (toàn cầu)\nnpm install -g supabase\n\n# macOS Homebrew\nbrew install supabase\u002Ftap\u002Fsupabase\n\n# Windows Scoop\nscoop bucket add supabase https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fscoop-bucket.git\nscoop install supabase\n\n# macOS \u002F Linux (curl)\ncurl -fsSL https:\u002F\u002Fcli.supabase.com\u002Finstall.sh | sh\n\n# Kiểm tra version\nsupabase --version\n",[445,12317,12318,12323,12336,12340,12345,12355,12359,12364,12379,12387,12391,12396,12412,12416,12421],{"__ignoreMap":528},[532,12319,12320],{"class":534,"line":535},[532,12321,12322],{"class":538},"# npm (toàn cầu)\n",[532,12324,12325,12328,12331,12334],{"class":534,"line":542},[532,12326,12327],{"class":545},"npm",[532,12329,12330],{"class":553}," install",[532,12332,12333],{"class":553}," -g",[532,12335,1668],{"class":553},[532,12337,12338],{"class":534,"line":564},[532,12339,596],{"emptyLinePlaceholder":595},[532,12341,12342],{"class":534,"line":579},[532,12343,12344],{"class":538},"# macOS Homebrew\n",[532,12346,12347,12350,12352],{"class":534,"line":592},[532,12348,12349],{"class":545},"brew",[532,12351,12330],{"class":553},[532,12353,12354],{"class":553}," supabase\u002Ftap\u002Fsupabase\n",[532,12356,12357],{"class":534,"line":599},[532,12358,596],{"emptyLinePlaceholder":595},[532,12360,12361],{"class":534,"line":605},[532,12362,12363],{"class":538},"# Windows Scoop\n",[532,12365,12366,12369,12371,12374,12376],{"class":534,"line":619},[532,12367,12368],{"class":545},"scoop",[532,12370,8495],{"class":553},[532,12372,12373],{"class":553}," add",[532,12375,2273],{"class":553},[532,12377,12378],{"class":553}," https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fscoop-bucket.git\n",[532,12380,12381,12383,12385],{"class":534,"line":630},[532,12382,12368],{"class":545},[532,12384,12330],{"class":553},[532,12386,1668],{"class":553},[532,12388,12389],{"class":534,"line":635},[532,12390,596],{"emptyLinePlaceholder":595},[532,12392,12393],{"class":534,"line":641},[532,12394,12395],{"class":538},"# macOS \u002F Linux (curl)\n",[532,12397,12398,12400,12403,12406,12409],{"class":534,"line":661},[532,12399,546],{"class":545},[532,12401,12402],{"class":553}," -fsSL",[532,12404,12405],{"class":553}," https:\u002F\u002Fcli.supabase.com\u002Finstall.sh",[532,12407,12408],{"class":549}," |",[532,12410,12411],{"class":545}," sh\n",[532,12413,12414],{"class":534,"line":674},[532,12415,596],{"emptyLinePlaceholder":595},[532,12417,12418],{"class":534,"line":688},[532,12419,12420],{"class":538},"# Kiểm tra version\n",[532,12422,12423,12425],{"class":534,"line":702},[532,12424,11280],{"class":545},[532,12426,12427],{"class":553}," --version\n",[450,12429,12431],{"id":12430},"local-development","Local Development",[523,12433,12435],{"className":525,"code":12434,"language":527,"meta":528,"style":528},"# ============ LOCAL DEVELOPMENT ============\n\nsupabase init                          # Khởi tạo project Supabase local (tạo thư mục supabase\u002F)\n                                       # Output: config.toml, thư mục migrations\u002F, functions\u002F, seeds\u002F\n\nsupabase start                         # Start tất cả services (Docker containers):\n                                       # - Postgres (port 54322)\n                                       # - Studio (port 54323)\n                                       # - Inbucket (mail testing, port 54324)\n                                       # - Kong API Gateway\n                                       # - GoTrue (Auth)\n                                       # - PostgREST\n                                       # - Realtime\n                                       # - Storage API\n                                       # - Edge Functions (Deno)\n\nsupabase start --exclude realtime      # Start trừ Realtime service\n\nsupabase stop                          # Stop tất cả services — giữ nguyên data\nsupabase stop --no-backup              # Stop và không backup data\n\nsupabase status                        # Xem trạng thái tất cả containers\n                                       # Output: tên service, status (running\u002Fstopped),\n                                       # ports, health check\n",[445,12436,12437,12442,12446,12456,12461,12465,12475,12480,12485,12490,12495,12500,12505,12510,12515,12520,12524,12539,12543,12553,12565,12569,12578,12583],{"__ignoreMap":528},[532,12438,12439],{"class":534,"line":535},[532,12440,12441],{"class":538},"# ============ LOCAL DEVELOPMENT ============\n",[532,12443,12444],{"class":534,"line":542},[532,12445,596],{"emptyLinePlaceholder":595},[532,12447,12448,12450,12453],{"class":534,"line":564},[532,12449,11280],{"class":545},[532,12451,12452],{"class":553}," init",[532,12454,12455],{"class":538},"                          # Khởi tạo project Supabase local (tạo thư mục supabase\u002F)\n",[532,12457,12458],{"class":534,"line":579},[532,12459,12460],{"class":538},"                                       # Output: config.toml, thư mục migrations\u002F, functions\u002F, seeds\u002F\n",[532,12462,12463],{"class":534,"line":592},[532,12464,596],{"emptyLinePlaceholder":595},[532,12466,12467,12469,12472],{"class":534,"line":599},[532,12468,11280],{"class":545},[532,12470,12471],{"class":553}," start",[532,12473,12474],{"class":538},"                         # Start tất cả services (Docker containers):\n",[532,12476,12477],{"class":534,"line":605},[532,12478,12479],{"class":538},"                                       # - Postgres (port 54322)\n",[532,12481,12482],{"class":534,"line":619},[532,12483,12484],{"class":538},"                                       # - Studio (port 54323)\n",[532,12486,12487],{"class":534,"line":630},[532,12488,12489],{"class":538},"                                       # - Inbucket (mail testing, port 54324)\n",[532,12491,12492],{"class":534,"line":635},[532,12493,12494],{"class":538},"                                       # - Kong API Gateway\n",[532,12496,12497],{"class":534,"line":641},[532,12498,12499],{"class":538},"                                       # - GoTrue (Auth)\n",[532,12501,12502],{"class":534,"line":661},[532,12503,12504],{"class":538},"                                       # - PostgREST\n",[532,12506,12507],{"class":534,"line":674},[532,12508,12509],{"class":538},"                                       # - Realtime\n",[532,12511,12512],{"class":534,"line":688},[532,12513,12514],{"class":538},"                                       # - Storage API\n",[532,12516,12517],{"class":534,"line":702},[532,12518,12519],{"class":538},"                                       # - Edge Functions (Deno)\n",[532,12521,12522],{"class":534,"line":715},[532,12523,596],{"emptyLinePlaceholder":595},[532,12525,12526,12528,12530,12533,12536],{"class":534,"line":720},[532,12527,11280],{"class":545},[532,12529,12471],{"class":553},[532,12531,12532],{"class":553}," --exclude",[532,12534,12535],{"class":553}," realtime",[532,12537,12538],{"class":538},"      # Start trừ Realtime service\n",[532,12540,12541],{"class":534,"line":726},[532,12542,596],{"emptyLinePlaceholder":595},[532,12544,12545,12547,12550],{"class":534,"line":745},[532,12546,11280],{"class":545},[532,12548,12549],{"class":553}," stop",[532,12551,12552],{"class":538},"                          # Stop tất cả services — giữ nguyên data\n",[532,12554,12555,12557,12559,12562],{"class":534,"line":758},[532,12556,11280],{"class":545},[532,12558,12549],{"class":553},[532,12560,12561],{"class":553}," --no-backup",[532,12563,12564],{"class":538},"              # Stop và không backup data\n",[532,12566,12567],{"class":534,"line":771},[532,12568,596],{"emptyLinePlaceholder":595},[532,12570,12571,12573,12575],{"class":534,"line":783},[532,12572,11280],{"class":545},[532,12574,1952],{"class":553},[532,12576,12577],{"class":538},"                        # Xem trạng thái tất cả containers\n",[532,12579,12580],{"class":534,"line":788},[532,12581,12582],{"class":538},"                                       # Output: tên service, status (running\u002Fstopped),\n",[532,12584,12585],{"class":534,"line":794},[532,12586,12587],{"class":538},"                                       # ports, health check\n",[450,12589,12591],{"id":12590},"database-commands","Database Commands",[523,12593,12595],{"className":525,"code":12594,"language":527,"meta":528,"style":528},"# ============ DATABASE ============\n\nsupabase db pull                       # Pull schema từ remote về local migration file\n                                       # Tạo 1 migration file mới chứa toàn bộ schema remote\n\nsupabase db push                       # Push migration lên remote database\n                                       # Chạy tất cả migration files chưa apply\n                                       # Tương đương: supabase migration up + db push\n\nsupabase db reset                      # Reset local database (xóa data, chạy lại migrations + seeds)\n                                       # Dùng khi: schema thay đổi lớn, test lại từ đầu\n\nsupabase db dump                       # Dump schema + data từ remote database\n                                       # Options:\n                                       #   --data-only       chỉ dump data\n                                       #   --schema-only     chỉ dump schema\n                                       #   --file output.sql lưu vào file\n                                       #   supabase db dump -f seed.sql --data-only\n\nsupabase db diff                       # Diff local schema vs remote schema\n                                       # Options:\n                                       #   --linked        diff với linked project\n                                       #   --file diff.sql lưu diff vào file\n                                       #   --schema public chỉ diff schema public\n\nsupabase db diff --use-migra           # Dùng migra tool để diff (chi tiết hơn)\n\nsupabase db lint                       # Lint database schema\n                                       # Kiểm tra: RLS policies, unused indexes,\n                                       # security vulnerabilities, naming conventions\n",[445,12596,12597,12602,12606,12619,12624,12628,12640,12645,12650,12654,12666,12671,12675,12687,12692,12697,12702,12707,12712,12716,12728,12732,12737,12742,12747,12751,12765,12769,12781,12786],{"__ignoreMap":528},[532,12598,12599],{"class":534,"line":535},[532,12600,12601],{"class":538},"# ============ DATABASE ============\n",[532,12603,12604],{"class":534,"line":542},[532,12605,596],{"emptyLinePlaceholder":595},[532,12607,12608,12610,12613,12616],{"class":534,"line":564},[532,12609,11280],{"class":545},[532,12611,12612],{"class":553}," db",[532,12614,12615],{"class":553}," pull",[532,12617,12618],{"class":538},"                       # Pull schema từ remote về local migration file\n",[532,12620,12621],{"class":534,"line":579},[532,12622,12623],{"class":538},"                                       # Tạo 1 migration file mới chứa toàn bộ schema remote\n",[532,12625,12626],{"class":534,"line":592},[532,12627,596],{"emptyLinePlaceholder":595},[532,12629,12630,12632,12634,12637],{"class":534,"line":599},[532,12631,11280],{"class":545},[532,12633,12612],{"class":553},[532,12635,12636],{"class":553}," push",[532,12638,12639],{"class":538},"                       # Push migration lên remote database\n",[532,12641,12642],{"class":534,"line":605},[532,12643,12644],{"class":538},"                                       # Chạy tất cả migration files chưa apply\n",[532,12646,12647],{"class":534,"line":619},[532,12648,12649],{"class":538},"                                       # Tương đương: supabase migration up + db push\n",[532,12651,12652],{"class":534,"line":630},[532,12653,596],{"emptyLinePlaceholder":595},[532,12655,12656,12658,12660,12663],{"class":534,"line":635},[532,12657,11280],{"class":545},[532,12659,12612],{"class":553},[532,12661,12662],{"class":553}," reset",[532,12664,12665],{"class":538},"                      # Reset local database (xóa data, chạy lại migrations + seeds)\n",[532,12667,12668],{"class":534,"line":641},[532,12669,12670],{"class":538},"                                       # Dùng khi: schema thay đổi lớn, test lại từ đầu\n",[532,12672,12673],{"class":534,"line":661},[532,12674,596],{"emptyLinePlaceholder":595},[532,12676,12677,12679,12681,12684],{"class":534,"line":674},[532,12678,11280],{"class":545},[532,12680,12612],{"class":553},[532,12682,12683],{"class":553}," dump",[532,12685,12686],{"class":538},"                       # Dump schema + data từ remote database\n",[532,12688,12689],{"class":534,"line":688},[532,12690,12691],{"class":538},"                                       # Options:\n",[532,12693,12694],{"class":534,"line":702},[532,12695,12696],{"class":538},"                                       #   --data-only       chỉ dump data\n",[532,12698,12699],{"class":534,"line":715},[532,12700,12701],{"class":538},"                                       #   --schema-only     chỉ dump schema\n",[532,12703,12704],{"class":534,"line":720},[532,12705,12706],{"class":538},"                                       #   --file output.sql lưu vào file\n",[532,12708,12709],{"class":534,"line":726},[532,12710,12711],{"class":538},"                                       #   supabase db dump -f seed.sql --data-only\n",[532,12713,12714],{"class":534,"line":745},[532,12715,596],{"emptyLinePlaceholder":595},[532,12717,12718,12720,12722,12725],{"class":534,"line":758},[532,12719,11280],{"class":545},[532,12721,12612],{"class":553},[532,12723,12724],{"class":553}," diff",[532,12726,12727],{"class":538},"                       # Diff local schema vs remote schema\n",[532,12729,12730],{"class":534,"line":771},[532,12731,12691],{"class":538},[532,12733,12734],{"class":534,"line":783},[532,12735,12736],{"class":538},"                                       #   --linked        diff với linked project\n",[532,12738,12739],{"class":534,"line":788},[532,12740,12741],{"class":538},"                                       #   --file diff.sql lưu diff vào file\n",[532,12743,12744],{"class":534,"line":794},[532,12745,12746],{"class":538},"                                       #   --schema public chỉ diff schema public\n",[532,12748,12749],{"class":534,"line":812},[532,12750,596],{"emptyLinePlaceholder":595},[532,12752,12753,12755,12757,12759,12762],{"class":534,"line":825},[532,12754,11280],{"class":545},[532,12756,12612],{"class":553},[532,12758,12724],{"class":553},[532,12760,12761],{"class":553}," --use-migra",[532,12763,12764],{"class":538},"           # Dùng migra tool để diff (chi tiết hơn)\n",[532,12766,12767],{"class":534,"line":2099},[532,12768,596],{"emptyLinePlaceholder":595},[532,12770,12771,12773,12775,12778],{"class":534,"line":2105},[532,12772,11280],{"class":545},[532,12774,12612],{"class":553},[532,12776,12777],{"class":553}," lint",[532,12779,12780],{"class":538},"                       # Lint database schema\n",[532,12782,12783],{"class":534,"line":2126},[532,12784,12785],{"class":538},"                                       # Kiểm tra: RLS policies, unused indexes,\n",[532,12787,12788],{"class":534,"line":2143},[532,12789,12790],{"class":538},"                                       # security vulnerabilities, naming conventions\n",[450,12792,12794],{"id":12793},"migrations","Migrations",[523,12796,12798],{"className":525,"code":12797,"language":527,"meta":528,"style":528},"# ============ MIGRATIONS ============\n\nsupabase migration new \u003Cname>          # Tạo migration file mới\n                                       # File: supabase\u002Fmigrations\u002F\u003Ctimestamp>_\u003Cname>.sql\n                                       # Ví dụ: supabase migration new add_posts_table\n                                       # → supabase\u002Fmigrations\u002F20240101000000_add_posts_table.sql\n\nsupabase migration list                # List tất cả migrations (local + remote + status)\n                                       # Output: version, name, applied_at (local\u002Fremote)\n\nsupabase migration up                  # Apply tất cả pending migrations lên database\n                                       # Options:\n                                       #   --local    apply lên local DB\n                                       #   --linked   apply lên linked remote DB\n                                       #   --db-url   apply lên database URL cụ thể\n\nsupabase migration repair \u003Cversion>    # Repair migration history (không chạy SQL)\n                                       # Đánh dấu migration là đã applied mà không chạy\n                                       # Dùng khi: migration đã chạy thủ công, cần sync lịch sử\n                                       # Ví dụ: supabase migration repair 20240101000000 --status applied\n\nsupabase migration squash              # Gộp tất cả migrations thành 1 file duy nhất\n                                       # Hữu ích khi có quá nhiều migration files\n                                       # Tạo 1 migration mới chứa toàn bộ schema final\n                                       # Các migration cũ được xóa khỏi danh sách\n",[445,12799,12800,12805,12809,12832,12837,12842,12847,12851,12863,12868,12872,12884,12888,12893,12898,12903,12907,12929,12934,12939,12944,12948,12960,12965,12970],{"__ignoreMap":528},[532,12801,12802],{"class":534,"line":535},[532,12803,12804],{"class":538},"# ============ MIGRATIONS ============\n",[532,12806,12807],{"class":534,"line":542},[532,12808,596],{"emptyLinePlaceholder":595},[532,12810,12811,12813,12816,12818,12821,12824,12827,12829],{"class":534,"line":564},[532,12812,11280],{"class":545},[532,12814,12815],{"class":553}," migration",[532,12817,8676],{"class":553},[532,12819,12820],{"class":549}," \u003C",[532,12822,12823],{"class":553},"nam",[532,12825,12826],{"class":560},"e",[532,12828,1012],{"class":549},[532,12830,12831],{"class":538},"          # Tạo migration file mới\n",[532,12833,12834],{"class":534,"line":579},[532,12835,12836],{"class":538},"                                       # File: supabase\u002Fmigrations\u002F\u003Ctimestamp>_\u003Cname>.sql\n",[532,12838,12839],{"class":534,"line":592},[532,12840,12841],{"class":538},"                                       # Ví dụ: supabase migration new add_posts_table\n",[532,12843,12844],{"class":534,"line":599},[532,12845,12846],{"class":538},"                                       # → supabase\u002Fmigrations\u002F20240101000000_add_posts_table.sql\n",[532,12848,12849],{"class":534,"line":605},[532,12850,596],{"emptyLinePlaceholder":595},[532,12852,12853,12855,12857,12860],{"class":534,"line":619},[532,12854,11280],{"class":545},[532,12856,12815],{"class":553},[532,12858,12859],{"class":553}," list",[532,12861,12862],{"class":538},"                # List tất cả migrations (local + remote + status)\n",[532,12864,12865],{"class":534,"line":630},[532,12866,12867],{"class":538},"                                       # Output: version, name, applied_at (local\u002Fremote)\n",[532,12869,12870],{"class":534,"line":635},[532,12871,596],{"emptyLinePlaceholder":595},[532,12873,12874,12876,12878,12881],{"class":534,"line":641},[532,12875,11280],{"class":545},[532,12877,12815],{"class":553},[532,12879,12880],{"class":553}," up",[532,12882,12883],{"class":538},"                  # Apply tất cả pending migrations lên database\n",[532,12885,12886],{"class":534,"line":661},[532,12887,12691],{"class":538},[532,12889,12890],{"class":534,"line":674},[532,12891,12892],{"class":538},"                                       #   --local    apply lên local DB\n",[532,12894,12895],{"class":534,"line":688},[532,12896,12897],{"class":538},"                                       #   --linked   apply lên linked remote DB\n",[532,12899,12900],{"class":534,"line":702},[532,12901,12902],{"class":538},"                                       #   --db-url   apply lên database URL cụ thể\n",[532,12904,12905],{"class":534,"line":715},[532,12906,596],{"emptyLinePlaceholder":595},[532,12908,12909,12911,12913,12916,12918,12921,12924,12926],{"class":534,"line":720},[532,12910,11280],{"class":545},[532,12912,12815],{"class":553},[532,12914,12915],{"class":553}," repair",[532,12917,12820],{"class":549},[532,12919,12920],{"class":553},"versio",[532,12922,12923],{"class":560},"n",[532,12925,1012],{"class":549},[532,12927,12928],{"class":538},"    # Repair migration history (không chạy SQL)\n",[532,12930,12931],{"class":534,"line":726},[532,12932,12933],{"class":538},"                                       # Đánh dấu migration là đã applied mà không chạy\n",[532,12935,12936],{"class":534,"line":745},[532,12937,12938],{"class":538},"                                       # Dùng khi: migration đã chạy thủ công, cần sync lịch sử\n",[532,12940,12941],{"class":534,"line":758},[532,12942,12943],{"class":538},"                                       # Ví dụ: supabase migration repair 20240101000000 --status applied\n",[532,12945,12946],{"class":534,"line":771},[532,12947,596],{"emptyLinePlaceholder":595},[532,12949,12950,12952,12954,12957],{"class":534,"line":783},[532,12951,11280],{"class":545},[532,12953,12815],{"class":553},[532,12955,12956],{"class":553}," squash",[532,12958,12959],{"class":538},"              # Gộp tất cả migrations thành 1 file duy nhất\n",[532,12961,12962],{"class":534,"line":788},[532,12963,12964],{"class":538},"                                       # Hữu ích khi có quá nhiều migration files\n",[532,12966,12967],{"class":534,"line":794},[532,12968,12969],{"class":538},"                                       # Tạo 1 migration mới chứa toàn bộ schema final\n",[532,12971,12972],{"class":534,"line":812},[532,12973,12974],{"class":538},"                                       # Các migration cũ được xóa khỏi danh sách\n",[450,12976,12978],{"id":12977},"generate-types","Generate Types",[523,12980,12982],{"className":525,"code":12981,"language":527,"meta":528,"style":528},"# ============ GENERATE TYPES ============\n\nsupabase gen types typescript          # Generate TypeScript types từ DB schema\n                                       # Output: type definitions cho tất cả tables, views\n\nsupabase gen types typescript --local  # Từ local development database\n                                       # supabase gen types typescript --local > src\u002Ftypes\u002Fsupabase.ts\n\nsupabase gen types typescript --linked # Từ linked remote project\n                                       # supabase gen types typescript --linked > types\u002Fdatabase.ts\n\nsupabase gen types typescript --db-url postgresql:\u002F\u002F... # Từ database URL cụ thể\n\nsupabase gen types typescript --schemas public,private  # Chỉ generate các schema cụ thể\n",[445,12983,12984,12989,12993,13006,13011,13015,13030,13035,13039,13054,13059,13063,13082,13086],{"__ignoreMap":528},[532,12985,12986],{"class":534,"line":535},[532,12987,12988],{"class":538},"# ============ GENERATE TYPES ============\n",[532,12990,12991],{"class":534,"line":542},[532,12992,596],{"emptyLinePlaceholder":595},[532,12994,12995,12997,12999,13001,13003],{"class":534,"line":564},[532,12996,11280],{"class":545},[532,12998,11807],{"class":553},[532,13000,11810],{"class":553},[532,13002,11813],{"class":553},[532,13004,13005],{"class":538},"          # Generate TypeScript types từ DB schema\n",[532,13007,13008],{"class":534,"line":579},[532,13009,13010],{"class":538},"                                       # Output: type definitions cho tất cả tables, views\n",[532,13012,13013],{"class":534,"line":592},[532,13014,596],{"emptyLinePlaceholder":595},[532,13016,13017,13019,13021,13023,13025,13027],{"class":534,"line":599},[532,13018,11280],{"class":545},[532,13020,11807],{"class":553},[532,13022,11810],{"class":553},[532,13024,11813],{"class":553},[532,13026,11816],{"class":553},[532,13028,13029],{"class":538},"  # Từ local development database\n",[532,13031,13032],{"class":534,"line":605},[532,13033,13034],{"class":538},"                                       # supabase gen types typescript --local > src\u002Ftypes\u002Fsupabase.ts\n",[532,13036,13037],{"class":534,"line":619},[532,13038,596],{"emptyLinePlaceholder":595},[532,13040,13041,13043,13045,13047,13049,13051],{"class":534,"line":630},[532,13042,11280],{"class":545},[532,13044,11807],{"class":553},[532,13046,11810],{"class":553},[532,13048,11813],{"class":553},[532,13050,11844],{"class":553},[532,13052,13053],{"class":538}," # Từ linked remote project\n",[532,13055,13056],{"class":534,"line":635},[532,13057,13058],{"class":538},"                                       # supabase gen types typescript --linked > types\u002Fdatabase.ts\n",[532,13060,13061],{"class":534,"line":641},[532,13062,596],{"emptyLinePlaceholder":595},[532,13064,13065,13067,13069,13071,13073,13076,13079],{"class":534,"line":661},[532,13066,11280],{"class":545},[532,13068,11807],{"class":553},[532,13070,11810],{"class":553},[532,13072,11813],{"class":553},[532,13074,13075],{"class":553}," --db-url",[532,13077,13078],{"class":553}," postgresql:\u002F\u002F...",[532,13080,13081],{"class":538}," # Từ database URL cụ thể\n",[532,13083,13084],{"class":534,"line":674},[532,13085,596],{"emptyLinePlaceholder":595},[532,13087,13088,13090,13092,13094,13096,13099,13102],{"class":534,"line":688},[532,13089,11280],{"class":545},[532,13091,11807],{"class":553},[532,13093,11810],{"class":553},[532,13095,11813],{"class":553},[532,13097,13098],{"class":553}," --schemas",[532,13100,13101],{"class":553}," public,private",[532,13103,13104],{"class":538},"  # Chỉ generate các schema cụ thể\n",[450,13106,13108],{"id":13107},"edge-functions-deno","Edge Functions (Deno)",[523,13110,13112],{"className":525,"code":13111,"language":527,"meta":528,"style":528},"# ============ EDGE FUNCTIONS ============\n\nsupabase functions new \u003Cname>          # Tạo Edge Function mới (Deno)\n                                       # File: supabase\u002Ffunctions\u002F\u003Cname>\u002Findex.ts\n                                       # Có template mặc định\n                                       # supabase functions new send-email\n\nsupabase functions serve               # Serve functions locally (hot reload)\n                                       # Options:\n                                       #   --env-file .env.development\n\nsupabase functions deploy \u003Cname>       # Deploy function lên production\n                                       # supabase functions deploy send-email\n                                       # deploy tất cả: supabase functions deploy (không truyền name)\n\nsupabase functions deploy \u003Cname> --no-verify-jwt  # Deploy không verify JWT (public function)\n\nsupabase functions delete \u003Cname>       # Xóa function khỏi production\n                                       # supabase functions delete send-email\n\nsupabase functions list                # List tất cả deployed Edge Functions\n                                       # Output: name, version, status, created_at\n\nsupabase functions download \u003Cname>     # Tải function code về local\n                                       # Khi function đã được deploy từ máy khác\n                                       # supabase functions download send-email --output-dir .\u002Fdownloads\n\nsupabase functions logs \u003Cname>         # Xem logs của function\n                                       # Options:\n                                       #   --limit 100\n                                       #   --follow \u002F -f     tail mode (real-time)\n",[445,13113,13114,13119,13123,13143,13148,13153,13158,13162,13174,13178,13183,13187,13207,13212,13217,13221,13243,13247,13267,13272,13276,13287,13292,13296,13316,13321,13326,13330,13350,13354,13359],{"__ignoreMap":528},[532,13115,13116],{"class":534,"line":535},[532,13117,13118],{"class":538},"# ============ EDGE FUNCTIONS ============\n",[532,13120,13121],{"class":534,"line":542},[532,13122,596],{"emptyLinePlaceholder":595},[532,13124,13125,13127,13130,13132,13134,13136,13138,13140],{"class":534,"line":564},[532,13126,11280],{"class":545},[532,13128,13129],{"class":553}," functions",[532,13131,8676],{"class":553},[532,13133,12820],{"class":549},[532,13135,12823],{"class":553},[532,13137,12826],{"class":560},[532,13139,1012],{"class":549},[532,13141,13142],{"class":538},"          # Tạo Edge Function mới (Deno)\n",[532,13144,13145],{"class":534,"line":579},[532,13146,13147],{"class":538},"                                       # File: supabase\u002Ffunctions\u002F\u003Cname>\u002Findex.ts\n",[532,13149,13150],{"class":534,"line":592},[532,13151,13152],{"class":538},"                                       # Có template mặc định\n",[532,13154,13155],{"class":534,"line":599},[532,13156,13157],{"class":538},"                                       # supabase functions new send-email\n",[532,13159,13160],{"class":534,"line":605},[532,13161,596],{"emptyLinePlaceholder":595},[532,13163,13164,13166,13168,13171],{"class":534,"line":619},[532,13165,11280],{"class":545},[532,13167,13129],{"class":553},[532,13169,13170],{"class":553}," serve",[532,13172,13173],{"class":538},"               # Serve functions locally (hot reload)\n",[532,13175,13176],{"class":534,"line":630},[532,13177,12691],{"class":538},[532,13179,13180],{"class":534,"line":635},[532,13181,13182],{"class":538},"                                       #   --env-file .env.development\n",[532,13184,13185],{"class":534,"line":641},[532,13186,596],{"emptyLinePlaceholder":595},[532,13188,13189,13191,13193,13196,13198,13200,13202,13204],{"class":534,"line":661},[532,13190,11280],{"class":545},[532,13192,13129],{"class":553},[532,13194,13195],{"class":553}," deploy",[532,13197,12820],{"class":549},[532,13199,12823],{"class":553},[532,13201,12826],{"class":560},[532,13203,1012],{"class":549},[532,13205,13206],{"class":538},"       # Deploy function lên production\n",[532,13208,13209],{"class":534,"line":674},[532,13210,13211],{"class":538},"                                       # supabase functions deploy send-email\n",[532,13213,13214],{"class":534,"line":688},[532,13215,13216],{"class":538},"                                       # deploy tất cả: supabase functions deploy (không truyền name)\n",[532,13218,13219],{"class":534,"line":702},[532,13220,596],{"emptyLinePlaceholder":595},[532,13222,13223,13225,13227,13229,13231,13233,13235,13237,13240],{"class":534,"line":715},[532,13224,11280],{"class":545},[532,13226,13129],{"class":553},[532,13228,13195],{"class":553},[532,13230,12820],{"class":549},[532,13232,12823],{"class":553},[532,13234,12826],{"class":560},[532,13236,1012],{"class":549},[532,13238,13239],{"class":553}," --no-verify-jwt",[532,13241,13242],{"class":538},"  # Deploy không verify JWT (public function)\n",[532,13244,13245],{"class":534,"line":720},[532,13246,596],{"emptyLinePlaceholder":595},[532,13248,13249,13251,13253,13256,13258,13260,13262,13264],{"class":534,"line":726},[532,13250,11280],{"class":545},[532,13252,13129],{"class":553},[532,13254,13255],{"class":553}," delete",[532,13257,12820],{"class":549},[532,13259,12823],{"class":553},[532,13261,12826],{"class":560},[532,13263,1012],{"class":549},[532,13265,13266],{"class":538},"       # Xóa function khỏi production\n",[532,13268,13269],{"class":534,"line":745},[532,13270,13271],{"class":538},"                                       # supabase functions delete send-email\n",[532,13273,13274],{"class":534,"line":758},[532,13275,596],{"emptyLinePlaceholder":595},[532,13277,13278,13280,13282,13284],{"class":534,"line":771},[532,13279,11280],{"class":545},[532,13281,13129],{"class":553},[532,13283,12859],{"class":553},[532,13285,13286],{"class":538},"                # List tất cả deployed Edge Functions\n",[532,13288,13289],{"class":534,"line":783},[532,13290,13291],{"class":538},"                                       # Output: name, version, status, created_at\n",[532,13293,13294],{"class":534,"line":788},[532,13295,596],{"emptyLinePlaceholder":595},[532,13297,13298,13300,13302,13305,13307,13309,13311,13313],{"class":534,"line":794},[532,13299,11280],{"class":545},[532,13301,13129],{"class":553},[532,13303,13304],{"class":553}," download",[532,13306,12820],{"class":549},[532,13308,12823],{"class":553},[532,13310,12826],{"class":560},[532,13312,1012],{"class":549},[532,13314,13315],{"class":538},"     # Tải function code về local\n",[532,13317,13318],{"class":534,"line":812},[532,13319,13320],{"class":538},"                                       # Khi function đã được deploy từ máy khác\n",[532,13322,13323],{"class":534,"line":825},[532,13324,13325],{"class":538},"                                       # supabase functions download send-email --output-dir .\u002Fdownloads\n",[532,13327,13328],{"class":534,"line":2099},[532,13329,596],{"emptyLinePlaceholder":595},[532,13331,13332,13334,13336,13339,13341,13343,13345,13347],{"class":534,"line":2105},[532,13333,11280],{"class":545},[532,13335,13129],{"class":553},[532,13337,13338],{"class":553}," logs",[532,13340,12820],{"class":549},[532,13342,12823],{"class":553},[532,13344,12826],{"class":560},[532,13346,1012],{"class":549},[532,13348,13349],{"class":538},"         # Xem logs của function\n",[532,13351,13352],{"class":534,"line":2126},[532,13353,12691],{"class":538},[532,13355,13356],{"class":534,"line":2143},[532,13357,13358],{"class":538},"                                       #   --limit 100\n",[532,13360,13361],{"class":534,"line":2153},[532,13362,13363],{"class":538},"                                       #   --follow \u002F -f     tail mode (real-time)\n",[450,13365,13367],{"id":13366},"secrets-management","Secrets Management",[523,13369,13371],{"className":525,"code":13370,"language":527,"meta":528,"style":528},"# ============ SECRETS (cho Edge Functions) ============\n\nsupabase secrets set \u003Ckey>=\u003Cvalue>     # Set secret cho Edge Functions\n                                       # supabase secrets set STRIPE_API_KEY=sk_live_xxx\n                                       # Có thể set nhiều secrets cùng lúc:\n                                       # supabase secrets set KEY1=val1 KEY2=val2\n\nsupabase secrets set --env-file .env   # Set tất cả biến từ .env file\n\nsupabase secrets list                  # List tất cả secrets\n                                       # Chỉ hiển thị key names, KHÔNG hiển thị values\n                                       # Output: name, created_at\n\nsupabase secrets unset \u003Ckey>           # Xóa secret\n                                       # supabase secrets unset STRIPE_API_KEY\n",[445,13372,13373,13378,13382,13415,13420,13425,13430,13434,13451,13455,13466,13471,13476,13480,13500],{"__ignoreMap":528},[532,13374,13375],{"class":534,"line":535},[532,13376,13377],{"class":538},"# ============ SECRETS (cho Edge Functions) ============\n",[532,13379,13380],{"class":534,"line":542},[532,13381,596],{"emptyLinePlaceholder":595},[532,13383,13384,13386,13389,13392,13394,13397,13399,13401,13403,13405,13408,13410,13412],{"class":534,"line":564},[532,13385,11280],{"class":545},[532,13387,13388],{"class":553}," secrets",[532,13390,13391],{"class":553}," set",[532,13393,12820],{"class":549},[532,13395,13396],{"class":553},"ke",[532,13398,10312],{"class":560},[532,13400,1012],{"class":549},[532,13402,982],{"class":553},[532,13404,1042],{"class":549},[532,13406,13407],{"class":553},"valu",[532,13409,12826],{"class":560},[532,13411,1012],{"class":549},[532,13413,13414],{"class":538},"     # Set secret cho Edge Functions\n",[532,13416,13417],{"class":534,"line":579},[532,13418,13419],{"class":538},"                                       # supabase secrets set STRIPE_API_KEY=sk_live_xxx\n",[532,13421,13422],{"class":534,"line":592},[532,13423,13424],{"class":538},"                                       # Có thể set nhiều secrets cùng lúc:\n",[532,13426,13427],{"class":534,"line":599},[532,13428,13429],{"class":538},"                                       # supabase secrets set KEY1=val1 KEY2=val2\n",[532,13431,13432],{"class":534,"line":605},[532,13433,596],{"emptyLinePlaceholder":595},[532,13435,13436,13438,13440,13442,13445,13448],{"class":534,"line":619},[532,13437,11280],{"class":545},[532,13439,13388],{"class":553},[532,13441,13391],{"class":553},[532,13443,13444],{"class":553}," --env-file",[532,13446,13447],{"class":553}," .env",[532,13449,13450],{"class":538},"   # Set tất cả biến từ .env file\n",[532,13452,13453],{"class":534,"line":630},[532,13454,596],{"emptyLinePlaceholder":595},[532,13456,13457,13459,13461,13463],{"class":534,"line":635},[532,13458,11280],{"class":545},[532,13460,13388],{"class":553},[532,13462,12859],{"class":553},[532,13464,13465],{"class":538},"                  # List tất cả secrets\n",[532,13467,13468],{"class":534,"line":641},[532,13469,13470],{"class":538},"                                       # Chỉ hiển thị key names, KHÔNG hiển thị values\n",[532,13472,13473],{"class":534,"line":661},[532,13474,13475],{"class":538},"                                       # Output: name, created_at\n",[532,13477,13478],{"class":534,"line":674},[532,13479,596],{"emptyLinePlaceholder":595},[532,13481,13482,13484,13486,13489,13491,13493,13495,13497],{"class":534,"line":688},[532,13483,11280],{"class":545},[532,13485,13388],{"class":553},[532,13487,13488],{"class":553}," unset",[532,13490,12820],{"class":549},[532,13492,13396],{"class":553},[532,13494,10312],{"class":560},[532,13496,1012],{"class":549},[532,13498,13499],{"class":538},"           # Xóa secret\n",[532,13501,13502],{"class":534,"line":702},[532,13503,13504],{"class":538},"                                       # supabase secrets unset STRIPE_API_KEY\n",[450,13506,13508],{"id":13507},"projects-management","Projects Management",[523,13510,13512],{"className":525,"code":13511,"language":527,"meta":528,"style":528},"# ============ PROJECTS ============\n\nsupabase projects create \u003Cname>        # Tạo project mới trên Supabase Platform\n                                       # Options:\n                                       #   --org-id \u003Cid>         organization ID\n                                       #   --db-password \u003Cpass>  database password\n                                       #   --region \u003Cregion>     region (ap-southeast-1, us-east-1, etc.)\n                                       #   --plan free|pro|team   plan type\n\nsupabase projects list                 # List tất cả projects của bạn\n                                       # Output: id, name, organization, region, created_at\n\nsupabase projects delete \u003Cid>          # Xóa project (không thể undo!)\n                                       # supabase projects delete abcdefghijklmnop\n\nsupabase projects api-keys             # Hiển thị API keys của project\n                                       # Output: name, type (anon\u002Fservice_role\u002Fpublishable), api_key\n\nsupabase link --project-ref \u003Cref>      # Link local project với remote project\n                                       # supabase link --project-ref abcdefghijklmnop\n                                       # Options:\n                                       #   --password \u003Cpass>    database password\n\nsupabase unlink                        # Bỏ link local với remote\n\nsupabase login                         # Đăng nhập vào Supabase (tạo access token)\n                                       # Mở browser để authorize\n\nsupabase logout                        # Đăng xuất\n",[445,13513,13514,13519,13523,13544,13548,13553,13558,13563,13568,13572,13583,13588,13592,13613,13618,13622,13634,13639,13643,13666,13671,13675,13680,13684,13694,13698,13708,13713,13717],{"__ignoreMap":528},[532,13515,13516],{"class":534,"line":535},[532,13517,13518],{"class":538},"# ============ PROJECTS ============\n",[532,13520,13521],{"class":534,"line":542},[532,13522,596],{"emptyLinePlaceholder":595},[532,13524,13525,13527,13530,13533,13535,13537,13539,13541],{"class":534,"line":564},[532,13526,11280],{"class":545},[532,13528,13529],{"class":553}," projects",[532,13531,13532],{"class":553}," create",[532,13534,12820],{"class":549},[532,13536,12823],{"class":553},[532,13538,12826],{"class":560},[532,13540,1012],{"class":549},[532,13542,13543],{"class":538},"        # Tạo project mới trên Supabase Platform\n",[532,13545,13546],{"class":534,"line":579},[532,13547,12691],{"class":538},[532,13549,13550],{"class":534,"line":592},[532,13551,13552],{"class":538},"                                       #   --org-id \u003Cid>         organization ID\n",[532,13554,13555],{"class":534,"line":599},[532,13556,13557],{"class":538},"                                       #   --db-password \u003Cpass>  database password\n",[532,13559,13560],{"class":534,"line":605},[532,13561,13562],{"class":538},"                                       #   --region \u003Cregion>     region (ap-southeast-1, us-east-1, etc.)\n",[532,13564,13565],{"class":534,"line":619},[532,13566,13567],{"class":538},"                                       #   --plan free|pro|team   plan type\n",[532,13569,13570],{"class":534,"line":630},[532,13571,596],{"emptyLinePlaceholder":595},[532,13573,13574,13576,13578,13580],{"class":534,"line":635},[532,13575,11280],{"class":545},[532,13577,13529],{"class":553},[532,13579,12859],{"class":553},[532,13581,13582],{"class":538},"                 # List tất cả projects của bạn\n",[532,13584,13585],{"class":534,"line":641},[532,13586,13587],{"class":538},"                                       # Output: id, name, organization, region, created_at\n",[532,13589,13590],{"class":534,"line":661},[532,13591,596],{"emptyLinePlaceholder":595},[532,13593,13594,13596,13598,13600,13602,13605,13608,13610],{"class":534,"line":674},[532,13595,11280],{"class":545},[532,13597,13529],{"class":553},[532,13599,13255],{"class":553},[532,13601,12820],{"class":549},[532,13603,13604],{"class":553},"i",[532,13606,13607],{"class":560},"d",[532,13609,1012],{"class":549},[532,13611,13612],{"class":538},"          # Xóa project (không thể undo!)\n",[532,13614,13615],{"class":534,"line":688},[532,13616,13617],{"class":538},"                                       # supabase projects delete abcdefghijklmnop\n",[532,13619,13620],{"class":534,"line":702},[532,13621,596],{"emptyLinePlaceholder":595},[532,13623,13624,13626,13628,13631],{"class":534,"line":715},[532,13625,11280],{"class":545},[532,13627,13529],{"class":553},[532,13629,13630],{"class":553}," api-keys",[532,13632,13633],{"class":538},"             # Hiển thị API keys của project\n",[532,13635,13636],{"class":534,"line":720},[532,13637,13638],{"class":538},"                                       # Output: name, type (anon\u002Fservice_role\u002Fpublishable), api_key\n",[532,13640,13641],{"class":534,"line":726},[532,13642,596],{"emptyLinePlaceholder":595},[532,13644,13645,13647,13650,13653,13655,13658,13661,13663],{"class":534,"line":745},[532,13646,11280],{"class":545},[532,13648,13649],{"class":553}," link",[532,13651,13652],{"class":553}," --project-ref",[532,13654,12820],{"class":549},[532,13656,13657],{"class":553},"re",[532,13659,13660],{"class":560},"f",[532,13662,1012],{"class":549},[532,13664,13665],{"class":538},"      # Link local project với remote project\n",[532,13667,13668],{"class":534,"line":758},[532,13669,13670],{"class":538},"                                       # supabase link --project-ref abcdefghijklmnop\n",[532,13672,13673],{"class":534,"line":771},[532,13674,12691],{"class":538},[532,13676,13677],{"class":534,"line":783},[532,13678,13679],{"class":538},"                                       #   --password \u003Cpass>    database password\n",[532,13681,13682],{"class":534,"line":788},[532,13683,596],{"emptyLinePlaceholder":595},[532,13685,13686,13688,13691],{"class":534,"line":794},[532,13687,11280],{"class":545},[532,13689,13690],{"class":553}," unlink",[532,13692,13693],{"class":538},"                        # Bỏ link local với remote\n",[532,13695,13696],{"class":534,"line":812},[532,13697,596],{"emptyLinePlaceholder":595},[532,13699,13700,13702,13705],{"class":534,"line":825},[532,13701,11280],{"class":545},[532,13703,13704],{"class":553}," login",[532,13706,13707],{"class":538},"                         # Đăng nhập vào Supabase (tạo access token)\n",[532,13709,13710],{"class":534,"line":2099},[532,13711,13712],{"class":538},"                                       # Mở browser để authorize\n",[532,13714,13715],{"class":534,"line":2105},[532,13716,596],{"emptyLinePlaceholder":595},[532,13718,13719,13721,13724],{"class":534,"line":2126},[532,13720,11280],{"class":545},[532,13722,13723],{"class":553}," logout",[532,13725,13726],{"class":538},"                        # Đăng xuất\n",[450,13728,13730],{"id":13729},"organizations","Organizations",[523,13732,13734],{"className":525,"code":13733,"language":527,"meta":528,"style":528},"# ============ ORGANIZATIONS ============\n\nsupabase orgs create \u003Cname>            # Tạo organization mới\n                                       # supabase orgs create \"My Team\"\n\nsupabase orgs list                     # List tất cả organizations của bạn\n                                       # Output: id, name\n",[445,13735,13736,13741,13745,13765,13770,13774,13785],{"__ignoreMap":528},[532,13737,13738],{"class":534,"line":535},[532,13739,13740],{"class":538},"# ============ ORGANIZATIONS ============\n",[532,13742,13743],{"class":534,"line":542},[532,13744,596],{"emptyLinePlaceholder":595},[532,13746,13747,13749,13752,13754,13756,13758,13760,13762],{"class":534,"line":564},[532,13748,11280],{"class":545},[532,13750,13751],{"class":553}," orgs",[532,13753,13532],{"class":553},[532,13755,12820],{"class":549},[532,13757,12823],{"class":553},[532,13759,12826],{"class":560},[532,13761,1012],{"class":549},[532,13763,13764],{"class":538},"            # Tạo organization mới\n",[532,13766,13767],{"class":534,"line":579},[532,13768,13769],{"class":538},"                                       # supabase orgs create \"My Team\"\n",[532,13771,13772],{"class":534,"line":592},[532,13773,596],{"emptyLinePlaceholder":595},[532,13775,13776,13778,13780,13782],{"class":534,"line":599},[532,13777,11280],{"class":545},[532,13779,13751],{"class":553},[532,13781,12859],{"class":553},[532,13783,13784],{"class":538},"                     # List tất cả organizations của bạn\n",[532,13786,13787],{"class":534,"line":605},[532,13788,13789],{"class":538},"                                       # Output: id, name\n",[450,13791,13793],{"id":13792},"branches-preview-environments","Branches (Preview Environments)",[523,13795,13797],{"className":525,"code":13796,"language":527,"meta":528,"style":528},"# ============ BRANCHES ============\n\nsupabase branches create \u003Cname>        # Tạo preview branch\n                                       # Branch là 1 database instance độc lập\n                                       # Dùng để test migrations trước khi merge\n                                       # supabase branches create feat-new-schema\n\nsupabase branches list                 # List tất cả branches\n                                       # Output: name, status, created_at, database_url\n\nsupabase branches delete \u003Cname>        # Xóa branch\n\nsupabase branches update \u003Cname>        # Cập nhật branch config\n",[445,13798,13799,13804,13808,13828,13833,13838,13843,13847,13858,13863,13867,13886,13890],{"__ignoreMap":528},[532,13800,13801],{"class":534,"line":535},[532,13802,13803],{"class":538},"# ============ BRANCHES ============\n",[532,13805,13806],{"class":534,"line":542},[532,13807,596],{"emptyLinePlaceholder":595},[532,13809,13810,13812,13815,13817,13819,13821,13823,13825],{"class":534,"line":564},[532,13811,11280],{"class":545},[532,13813,13814],{"class":553}," branches",[532,13816,13532],{"class":553},[532,13818,12820],{"class":549},[532,13820,12823],{"class":553},[532,13822,12826],{"class":560},[532,13824,1012],{"class":549},[532,13826,13827],{"class":538},"        # Tạo preview branch\n",[532,13829,13830],{"class":534,"line":579},[532,13831,13832],{"class":538},"                                       # Branch là 1 database instance độc lập\n",[532,13834,13835],{"class":534,"line":592},[532,13836,13837],{"class":538},"                                       # Dùng để test migrations trước khi merge\n",[532,13839,13840],{"class":534,"line":599},[532,13841,13842],{"class":538},"                                       # supabase branches create feat-new-schema\n",[532,13844,13845],{"class":534,"line":605},[532,13846,596],{"emptyLinePlaceholder":595},[532,13848,13849,13851,13853,13855],{"class":534,"line":619},[532,13850,11280],{"class":545},[532,13852,13814],{"class":553},[532,13854,12859],{"class":553},[532,13856,13857],{"class":538},"                 # List tất cả branches\n",[532,13859,13860],{"class":534,"line":630},[532,13861,13862],{"class":538},"                                       # Output: name, status, created_at, database_url\n",[532,13864,13865],{"class":534,"line":635},[532,13866,596],{"emptyLinePlaceholder":595},[532,13868,13869,13871,13873,13875,13877,13879,13881,13883],{"class":534,"line":641},[532,13870,11280],{"class":545},[532,13872,13814],{"class":553},[532,13874,13255],{"class":553},[532,13876,12820],{"class":549},[532,13878,12823],{"class":553},[532,13880,12826],{"class":560},[532,13882,1012],{"class":549},[532,13884,13885],{"class":538},"        # Xóa branch\n",[532,13887,13888],{"class":534,"line":661},[532,13889,596],{"emptyLinePlaceholder":595},[532,13891,13892,13894,13896,13899,13901,13903,13905,13907],{"class":534,"line":674},[532,13893,11280],{"class":545},[532,13895,13814],{"class":553},[532,13897,13898],{"class":553}," update",[532,13900,12820],{"class":549},[532,13902,12823],{"class":553},[532,13904,12826],{"class":560},[532,13906,1012],{"class":549},[532,13908,13909],{"class":538},"        # Cập nhật branch config\n",[450,13911,13913],{"id":13912},"config","Config",[523,13915,13917],{"className":525,"code":13916,"language":527,"meta":528,"style":528},"# ============ CONFIG ============\n\nsupabase config push                   # Push config từ config.toml lên remote project\n                                       # Các settings: auth, db, storage, realtime, edge_functions\n",[445,13918,13919,13924,13928,13939],{"__ignoreMap":528},[532,13920,13921],{"class":534,"line":535},[532,13922,13923],{"class":538},"# ============ CONFIG ============\n",[532,13925,13926],{"class":534,"line":542},[532,13927,596],{"emptyLinePlaceholder":595},[532,13929,13930,13932,13934,13936],{"class":534,"line":564},[532,13931,11280],{"class":545},[532,13933,3423],{"class":553},[532,13935,12636],{"class":553},[532,13937,13938],{"class":538},"                   # Push config từ config.toml lên remote project\n",[532,13940,13941],{"class":534,"line":579},[532,13942,13943],{"class":538},"                                       # Các settings: auth, db, storage, realtime, edge_functions\n",[450,13945,13947],{"id":13946},"auth-sso","Auth \u002F SSO",[523,13949,13951],{"className":525,"code":13950,"language":527,"meta":528,"style":528},"# ============ AUTH \u002F SSO ============\n\nsupabase sso add \u003Ctype>                # Thêm identity provider (SSO\u002FSAML)\n                                       # supabase sso add saml\n                                       # Options:\n                                       #   --metadata-url \u003Curl>          SAML metadata URL\n                                       #   --metadata-file \u003Cfile>        SAML metadata XML file\n                                       #   --domains \u003Cdomain1,domain2>   email domains\n                                       #   --attribute-mapping-file \u003Cfile>  custom attribute mapping\n\nsupabase sso list                      # List tất cả SSO providers\n                                       # Output: id, type, domains, created_at\n\nsupabase sso show \u003Cid>                 # Xem thông tin chi tiết của 1 provider\n                                       # Output: full config, domains, attribute mapping\n\nsupabase sso update \u003Cid>               # Update provider config\n                                       # supabase sso update \u003Cid> --domains newdomain.com\n\nsupabase sso remove \u003Cid>               # Xóa SSO provider\n",[445,13952,13953,13958,13962,13983,13988,13992,13997,14002,14007,14012,14016,14027,14032,14036,14056,14061,14065,14084,14089,14093],{"__ignoreMap":528},[532,13954,13955],{"class":534,"line":535},[532,13956,13957],{"class":538},"# ============ AUTH \u002F SSO ============\n",[532,13959,13960],{"class":534,"line":542},[532,13961,596],{"emptyLinePlaceholder":595},[532,13963,13964,13966,13969,13971,13973,13976,13978,13980],{"class":534,"line":564},[532,13965,11280],{"class":545},[532,13967,13968],{"class":553}," sso",[532,13970,12373],{"class":553},[532,13972,12820],{"class":549},[532,13974,13975],{"class":553},"typ",[532,13977,12826],{"class":560},[532,13979,1012],{"class":549},[532,13981,13982],{"class":538},"                # Thêm identity provider (SSO\u002FSAML)\n",[532,13984,13985],{"class":534,"line":579},[532,13986,13987],{"class":538},"                                       # supabase sso add saml\n",[532,13989,13990],{"class":534,"line":592},[532,13991,12691],{"class":538},[532,13993,13994],{"class":534,"line":599},[532,13995,13996],{"class":538},"                                       #   --metadata-url \u003Curl>          SAML metadata URL\n",[532,13998,13999],{"class":534,"line":605},[532,14000,14001],{"class":538},"                                       #   --metadata-file \u003Cfile>        SAML metadata XML file\n",[532,14003,14004],{"class":534,"line":619},[532,14005,14006],{"class":538},"                                       #   --domains \u003Cdomain1,domain2>   email domains\n",[532,14008,14009],{"class":534,"line":630},[532,14010,14011],{"class":538},"                                       #   --attribute-mapping-file \u003Cfile>  custom attribute mapping\n",[532,14013,14014],{"class":534,"line":635},[532,14015,596],{"emptyLinePlaceholder":595},[532,14017,14018,14020,14022,14024],{"class":534,"line":641},[532,14019,11280],{"class":545},[532,14021,13968],{"class":553},[532,14023,12859],{"class":553},[532,14025,14026],{"class":538},"                      # List tất cả SSO providers\n",[532,14028,14029],{"class":534,"line":661},[532,14030,14031],{"class":538},"                                       # Output: id, type, domains, created_at\n",[532,14033,14034],{"class":534,"line":674},[532,14035,596],{"emptyLinePlaceholder":595},[532,14037,14038,14040,14042,14045,14047,14049,14051,14053],{"class":534,"line":688},[532,14039,11280],{"class":545},[532,14041,13968],{"class":553},[532,14043,14044],{"class":553}," show",[532,14046,12820],{"class":549},[532,14048,13604],{"class":553},[532,14050,13607],{"class":560},[532,14052,1012],{"class":549},[532,14054,14055],{"class":538},"                 # Xem thông tin chi tiết của 1 provider\n",[532,14057,14058],{"class":534,"line":702},[532,14059,14060],{"class":538},"                                       # Output: full config, domains, attribute mapping\n",[532,14062,14063],{"class":534,"line":715},[532,14064,596],{"emptyLinePlaceholder":595},[532,14066,14067,14069,14071,14073,14075,14077,14079,14081],{"class":534,"line":720},[532,14068,11280],{"class":545},[532,14070,13968],{"class":553},[532,14072,13898],{"class":553},[532,14074,12820],{"class":549},[532,14076,13604],{"class":553},[532,14078,13607],{"class":560},[532,14080,1012],{"class":549},[532,14082,14083],{"class":538},"               # Update provider config\n",[532,14085,14086],{"class":534,"line":726},[532,14087,14088],{"class":538},"                                       # supabase sso update \u003Cid> --domains newdomain.com\n",[532,14090,14091],{"class":534,"line":745},[532,14092,596],{"emptyLinePlaceholder":595},[532,14094,14095,14097,14099,14102,14104,14106,14108,14110],{"class":534,"line":758},[532,14096,11280],{"class":545},[532,14098,13968],{"class":553},[532,14100,14101],{"class":553}," remove",[532,14103,12820],{"class":549},[532,14105,13604],{"class":553},[532,14107,13607],{"class":560},[532,14109,1012],{"class":549},[532,14111,14112],{"class":538},"               # Xóa SSO provider\n",[450,14114,1592],{"id":8120},[523,14116,14118],{"className":525,"code":14117,"language":527,"meta":528,"style":528},"# ============ STORAGE ============\n\nsupabase storage ls                    # List tất cả storage buckets\nsupabase storage ls \u003Cbucket>           # List files trong bucket\n                                       # supabase storage ls avatars --prefix public\u002F\n\nsupabase storage cp \u003Csrc> \u003Cdest>       # Upload\u002Fdownload files\n                                       # Upload local → remote:\n                                       #   supabase storage cp .\u002Fimage.png ss:\u002F\u002Fmy-bucket\u002Fpath\u002Fimage.png\n                                       # Download remote → local:\n                                       #   supabase storage cp ss:\u002F\u002Fmy-bucket\u002Fpath\u002Fimage.png .\u002Fdownloads\u002F\n                                       # Copy giữa các buckets:\n                                       #   supabase storage cp ss:\u002F\u002Fbucket1\u002Ffile.png ss:\u002F\u002Fbucket2\u002Ffile.png\n\nsupabase storage rm \u003Cpath>             # Delete storage objects\n                                       # supabase storage rm ss:\u002F\u002Fmy-bucket\u002Fpath\u002Fimage.png\n",[445,14119,14120,14125,14129,14142,14163,14168,14172,14203,14208,14213,14218,14223,14228,14233,14237,14259],{"__ignoreMap":528},[532,14121,14122],{"class":534,"line":535},[532,14123,14124],{"class":538},"# ============ STORAGE ============\n",[532,14126,14127],{"class":534,"line":542},[532,14128,596],{"emptyLinePlaceholder":595},[532,14130,14131,14133,14136,14139],{"class":534,"line":564},[532,14132,11280],{"class":545},[532,14134,14135],{"class":553}," storage",[532,14137,14138],{"class":553}," ls",[532,14140,14141],{"class":538},"                    # List tất cả storage buckets\n",[532,14143,14144,14146,14148,14150,14152,14155,14158,14160],{"class":534,"line":579},[532,14145,11280],{"class":545},[532,14147,14135],{"class":553},[532,14149,14138],{"class":553},[532,14151,12820],{"class":549},[532,14153,14154],{"class":553},"bucke",[532,14156,14157],{"class":560},"t",[532,14159,1012],{"class":549},[532,14161,14162],{"class":538},"           # List files trong bucket\n",[532,14164,14165],{"class":534,"line":592},[532,14166,14167],{"class":538},"                                       # supabase storage ls avatars --prefix public\u002F\n",[532,14169,14170],{"class":534,"line":599},[532,14171,596],{"emptyLinePlaceholder":595},[532,14173,14174,14176,14178,14181,14183,14186,14189,14191,14193,14196,14198,14200],{"class":534,"line":605},[532,14175,11280],{"class":545},[532,14177,14135],{"class":553},[532,14179,14180],{"class":553}," cp",[532,14182,12820],{"class":549},[532,14184,14185],{"class":553},"sr",[532,14187,14188],{"class":560},"c",[532,14190,1012],{"class":549},[532,14192,12820],{"class":549},[532,14194,14195],{"class":553},"des",[532,14197,14157],{"class":560},[532,14199,1012],{"class":549},[532,14201,14202],{"class":538},"       # Upload\u002Fdownload files\n",[532,14204,14205],{"class":534,"line":619},[532,14206,14207],{"class":538},"                                       # Upload local → remote:\n",[532,14209,14210],{"class":534,"line":630},[532,14211,14212],{"class":538},"                                       #   supabase storage cp .\u002Fimage.png ss:\u002F\u002Fmy-bucket\u002Fpath\u002Fimage.png\n",[532,14214,14215],{"class":534,"line":635},[532,14216,14217],{"class":538},"                                       # Download remote → local:\n",[532,14219,14220],{"class":534,"line":641},[532,14221,14222],{"class":538},"                                       #   supabase storage cp ss:\u002F\u002Fmy-bucket\u002Fpath\u002Fimage.png .\u002Fdownloads\u002F\n",[532,14224,14225],{"class":534,"line":661},[532,14226,14227],{"class":538},"                                       # Copy giữa các buckets:\n",[532,14229,14230],{"class":534,"line":674},[532,14231,14232],{"class":538},"                                       #   supabase storage cp ss:\u002F\u002Fbucket1\u002Ffile.png ss:\u002F\u002Fbucket2\u002Ffile.png\n",[532,14234,14235],{"class":534,"line":688},[532,14236,596],{"emptyLinePlaceholder":595},[532,14238,14239,14241,14243,14246,14248,14251,14254,14256],{"class":534,"line":702},[532,14240,11280],{"class":545},[532,14242,14135],{"class":553},[532,14244,14245],{"class":553}," rm",[532,14247,12820],{"class":549},[532,14249,14250],{"class":553},"pat",[532,14252,14253],{"class":560},"h",[532,14255,1012],{"class":549},[532,14257,14258],{"class":538},"             # Delete storage objects\n",[532,14260,14261],{"class":534,"line":715},[532,14262,14263],{"class":538},"                                       # supabase storage rm ss:\u002F\u002Fmy-bucket\u002Fpath\u002Fimage.png\n",[450,14265,14267],{"id":14266},"network-management","Network Management",[523,14269,14271],{"className":525,"code":14270,"language":527,"meta":528,"style":528},"# ============ NETWORK ============\n\nsupabase bans list                     # List network bans (IP\u002Frange bị chặn)\nsupabase network-restrictions          # Manage network restrictions (allowlist\u002Fblocklist)\n",[445,14272,14273,14278,14282,14294],{"__ignoreMap":528},[532,14274,14275],{"class":534,"line":535},[532,14276,14277],{"class":538},"# ============ NETWORK ============\n",[532,14279,14280],{"class":534,"line":542},[532,14281,596],{"emptyLinePlaceholder":595},[532,14283,14284,14286,14289,14291],{"class":534,"line":564},[532,14285,11280],{"class":545},[532,14287,14288],{"class":553}," bans",[532,14290,12859],{"class":553},[532,14292,14293],{"class":538},"                     # List network bans (IP\u002Frange bị chặn)\n",[532,14295,14296,14298,14301],{"class":534,"line":579},[532,14297,11280],{"class":545},[532,14299,14300],{"class":553}," network-restrictions",[532,14302,14303],{"class":538},"          # Manage network restrictions (allowlist\u002Fblocklist)\n",[450,14305,14307],{"id":14306},"testing","Testing",[523,14309,14311],{"className":525,"code":14310,"language":527,"meta":528,"style":528},"# ============ TESTING (pgTAP) ============\n\nsupabase test new \u003Cname>               # Tạo test file mới\n                                       # File: supabase\u002Ftests\u002F\u003Cname>.sql\n                                       # Template sẵn với pgTAP assertions\n\nsupabase test db                       # Chạy tất cả database tests\n                                       # Dùng pgTAP framework\n",[445,14312,14313,14318,14322,14342,14347,14352,14356,14367],{"__ignoreMap":528},[532,14314,14315],{"class":534,"line":535},[532,14316,14317],{"class":538},"# ============ TESTING (pgTAP) ============\n",[532,14319,14320],{"class":534,"line":542},[532,14321,596],{"emptyLinePlaceholder":595},[532,14323,14324,14326,14329,14331,14333,14335,14337,14339],{"class":534,"line":564},[532,14325,11280],{"class":545},[532,14327,14328],{"class":553}," test",[532,14330,8676],{"class":553},[532,14332,12820],{"class":549},[532,14334,12823],{"class":553},[532,14336,12826],{"class":560},[532,14338,1012],{"class":549},[532,14340,14341],{"class":538},"               # Tạo test file mới\n",[532,14343,14344],{"class":534,"line":579},[532,14345,14346],{"class":538},"                                       # File: supabase\u002Ftests\u002F\u003Cname>.sql\n",[532,14348,14349],{"class":534,"line":592},[532,14350,14351],{"class":538},"                                       # Template sẵn với pgTAP assertions\n",[532,14353,14354],{"class":534,"line":599},[532,14355,596],{"emptyLinePlaceholder":595},[532,14357,14358,14360,14362,14364],{"class":534,"line":605},[532,14359,11280],{"class":545},[532,14361,14328],{"class":553},[532,14363,12612],{"class":553},[532,14365,14366],{"class":538},"                       # Chạy tất cả database tests\n",[532,14368,14369],{"class":534,"line":619},[532,14370,14371],{"class":538},"                                       # Dùng pgTAP framework\n",[450,14373,14375],{"id":14374},"autocomplete-shell-completion","Autocomplete \u002F Shell Completion",[523,14377,14379],{"className":525,"code":14378,"language":527,"meta":528,"style":528},"# ============ COMPLETION ============\n\nsupabase completion bash               # Generate bash autocomplete script\n                                       # Dùng: source \u003C(supabase completion bash)\n                                       # Hoặc thêm vào ~\u002F.bashrc\n\nsupabase completion zsh                # Generate zsh autocomplete script\n                                       # Dùng: source \u003C(supabase completion zsh)\n                                       # Hoặc thêm vào ~\u002F.zshrc\n\nsupabase completion powershell         # Generate PowerShell autocomplete script\n\nsupabase completion fish               # Generate Fish shell autocomplete script\n",[445,14380,14381,14386,14390,14403,14408,14413,14417,14429,14434,14439,14443,14455,14459],{"__ignoreMap":528},[532,14382,14383],{"class":534,"line":535},[532,14384,14385],{"class":538},"# ============ COMPLETION ============\n",[532,14387,14388],{"class":534,"line":542},[532,14389,596],{"emptyLinePlaceholder":595},[532,14391,14392,14394,14397,14400],{"class":534,"line":564},[532,14393,11280],{"class":545},[532,14395,14396],{"class":553}," completion",[532,14398,14399],{"class":553}," bash",[532,14401,14402],{"class":538},"               # Generate bash autocomplete script\n",[532,14404,14405],{"class":534,"line":579},[532,14406,14407],{"class":538},"                                       # Dùng: source \u003C(supabase completion bash)\n",[532,14409,14410],{"class":534,"line":592},[532,14411,14412],{"class":538},"                                       # Hoặc thêm vào ~\u002F.bashrc\n",[532,14414,14415],{"class":534,"line":599},[532,14416,596],{"emptyLinePlaceholder":595},[532,14418,14419,14421,14423,14426],{"class":534,"line":605},[532,14420,11280],{"class":545},[532,14422,14396],{"class":553},[532,14424,14425],{"class":553}," zsh",[532,14427,14428],{"class":538},"                # Generate zsh autocomplete script\n",[532,14430,14431],{"class":534,"line":619},[532,14432,14433],{"class":538},"                                       # Dùng: source \u003C(supabase completion zsh)\n",[532,14435,14436],{"class":534,"line":630},[532,14437,14438],{"class":538},"                                       # Hoặc thêm vào ~\u002F.zshrc\n",[532,14440,14441],{"class":534,"line":635},[532,14442,596],{"emptyLinePlaceholder":595},[532,14444,14445,14447,14449,14452],{"class":534,"line":641},[532,14446,11280],{"class":545},[532,14448,14396],{"class":553},[532,14450,14451],{"class":553}," powershell",[532,14453,14454],{"class":538},"         # Generate PowerShell autocomplete script\n",[532,14456,14457],{"class":534,"line":661},[532,14458,596],{"emptyLinePlaceholder":595},[532,14460,14461,14463,14465,14468],{"class":534,"line":674},[532,14462,11280],{"class":545},[532,14464,14396],{"class":553},[532,14466,14467],{"class":553}," fish",[532,14469,14470],{"class":538},"               # Generate Fish shell autocomplete script\n",[450,14472,14474],{"id":14473},"global-flags","Global Flags",[523,14476,14478],{"className":525,"code":14477,"language":527,"meta":528,"style":528},"# ============ GLOBAL FLAGS (dùng với mọi command) ============\n\n# --debug\n# Output debug logs chi tiết (request\u002Fresponse, SQL queries, timing)\n# supabase start --debug\n\n# --experimental\n# Enable tính năng experimental (có thể không ổn định)\n# supabase db push --experimental\n\n# --output json\n# JSON output để scripting\u002Fautomation (thay vì table format)\n# supabase projects list --output json\n\n# --create-ticket\n# Tự động tạo support ticket trên Supabase nếu command gặp lỗi\n# supabase db push --create-ticket\n\n# --workdir \u003Cpath>\n# Chỉ định thư mục làm việc (thay vì thư mục hiện tại)\n# supabase start --workdir .\u002Fmy-project\n\n# --version\n# Hiển thị version của CLI\n# supabase --version\n",[445,14479,14480,14485,14489,14494,14499,14504,14508,14513,14518,14523,14527,14532,14537,14542,14546,14551,14556,14561,14565,14570,14575,14580,14584,14589,14594],{"__ignoreMap":528},[532,14481,14482],{"class":534,"line":535},[532,14483,14484],{"class":538},"# ============ GLOBAL FLAGS (dùng với mọi command) ============\n",[532,14486,14487],{"class":534,"line":542},[532,14488,596],{"emptyLinePlaceholder":595},[532,14490,14491],{"class":534,"line":564},[532,14492,14493],{"class":538},"# --debug\n",[532,14495,14496],{"class":534,"line":579},[532,14497,14498],{"class":538},"# Output debug logs chi tiết (request\u002Fresponse, SQL queries, timing)\n",[532,14500,14501],{"class":534,"line":592},[532,14502,14503],{"class":538},"# supabase start --debug\n",[532,14505,14506],{"class":534,"line":599},[532,14507,596],{"emptyLinePlaceholder":595},[532,14509,14510],{"class":534,"line":605},[532,14511,14512],{"class":538},"# --experimental\n",[532,14514,14515],{"class":534,"line":619},[532,14516,14517],{"class":538},"# Enable tính năng experimental (có thể không ổn định)\n",[532,14519,14520],{"class":534,"line":630},[532,14521,14522],{"class":538},"# supabase db push --experimental\n",[532,14524,14525],{"class":534,"line":635},[532,14526,596],{"emptyLinePlaceholder":595},[532,14528,14529],{"class":534,"line":641},[532,14530,14531],{"class":538},"# --output json\n",[532,14533,14534],{"class":534,"line":661},[532,14535,14536],{"class":538},"# JSON output để scripting\u002Fautomation (thay vì table format)\n",[532,14538,14539],{"class":534,"line":674},[532,14540,14541],{"class":538},"# supabase projects list --output json\n",[532,14543,14544],{"class":534,"line":688},[532,14545,596],{"emptyLinePlaceholder":595},[532,14547,14548],{"class":534,"line":702},[532,14549,14550],{"class":538},"# --create-ticket\n",[532,14552,14553],{"class":534,"line":715},[532,14554,14555],{"class":538},"# Tự động tạo support ticket trên Supabase nếu command gặp lỗi\n",[532,14557,14558],{"class":534,"line":720},[532,14559,14560],{"class":538},"# supabase db push --create-ticket\n",[532,14562,14563],{"class":534,"line":726},[532,14564,596],{"emptyLinePlaceholder":595},[532,14566,14567],{"class":534,"line":745},[532,14568,14569],{"class":538},"# --workdir \u003Cpath>\n",[532,14571,14572],{"class":534,"line":758},[532,14573,14574],{"class":538},"# Chỉ định thư mục làm việc (thay vì thư mục hiện tại)\n",[532,14576,14577],{"class":534,"line":771},[532,14578,14579],{"class":538},"# supabase start --workdir .\u002Fmy-project\n",[532,14581,14582],{"class":534,"line":783},[532,14583,596],{"emptyLinePlaceholder":595},[532,14585,14586],{"class":534,"line":788},[532,14587,14588],{"class":538},"# --version\n",[532,14590,14591],{"class":534,"line":794},[532,14592,14593],{"class":538},"# Hiển thị version của CLI\n",[532,14595,14596],{"class":534,"line":812},[532,14597,14598],{"class":538},"# supabase --version\n",[496,14600,14601,14604,14605,14608,14609,14612,14613,14616,14617,14620],{"color":498,"icon":499},[436,14602,14603],{},"Interview tip — CLI:"," Supabase CLI là công cụ quan trọng cho local development. Các command hay dùng nhất: ",[445,14606,14607],{},"supabase start"," (khởi động toàn bộ stack local qua Docker), ",[445,14610,14611],{},"supabase db push\u002Fpull"," (đồng bộ schema), ",[445,14614,14615],{},"supabase migration new"," (tạo migration), ",[445,14618,14619],{},"supabase gen types"," (generate TypeScript types). Local development stack bao gồm Postgres, Auth (GoTrue), PostgREST, Realtime, Storage, và Edge Functions — tất cả chạy qua Docker.",[1301,14622],{},[427,14624,14626],{"id":14625},"quickstarts-code-mẫu-theo-framework","Quickstarts -- Code mẫu theo framework",[450,14628,14630],{"id":14629},"nuxt-3-vue-quickstart","Nuxt 3 \u002F Vue Quickstart",[432,14632,14633,14636,14637,14644],{},[436,14634,14635],{},"1. Tạo Supabase project:"," vào ",[14638,14639,14643],"a",{"href":14640,"rel":14641},"https:\u002F\u002Fsupabase.com\u002Fdashboard",[14642],"nofollow","supabase.com\u002Fdashboard"," tạo project mới.",[432,14646,14647],{},[436,14648,14649],{},"2. Setup database:",[523,14651,14655],{"className":14652,"code":14653,"language":14654,"meta":528,"style":528},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","-- Tạo bảng instruments\nCREATE TABLE instruments (\n  id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,\n  name TEXT NOT NULL\n);\n\nINSERT INTO instruments (name) VALUES ('violin'), ('viola'), ('cello');\n\n-- Enable RLS + grant quyền\nALTER TABLE instruments ENABLE ROW LEVEL SECURITY;\nGRANT SELECT ON public.instruments TO anon;\n\nCREATE POLICY \"public can read instruments\"\nON public.instruments FOR SELECT TO anon USING (true);\n","sql",[445,14656,14657,14662,14667,14672,14677,14682,14686,14691,14695,14700,14705,14710,14714,14719],{"__ignoreMap":528},[532,14658,14659],{"class":534,"line":535},[532,14660,14661],{},"-- Tạo bảng instruments\n",[532,14663,14664],{"class":534,"line":542},[532,14665,14666],{},"CREATE TABLE instruments (\n",[532,14668,14669],{"class":534,"line":564},[532,14670,14671],{},"  id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,\n",[532,14673,14674],{"class":534,"line":579},[532,14675,14676],{},"  name TEXT NOT NULL\n",[532,14678,14679],{"class":534,"line":592},[532,14680,14681],{},");\n",[532,14683,14684],{"class":534,"line":599},[532,14685,596],{"emptyLinePlaceholder":595},[532,14687,14688],{"class":534,"line":605},[532,14689,14690],{},"INSERT INTO instruments (name) VALUES ('violin'), ('viola'), ('cello');\n",[532,14692,14693],{"class":534,"line":619},[532,14694,596],{"emptyLinePlaceholder":595},[532,14696,14697],{"class":534,"line":630},[532,14698,14699],{},"-- Enable RLS + grant quyền\n",[532,14701,14702],{"class":534,"line":635},[532,14703,14704],{},"ALTER TABLE instruments ENABLE ROW LEVEL SECURITY;\n",[532,14706,14707],{"class":534,"line":641},[532,14708,14709],{},"GRANT SELECT ON public.instruments TO anon;\n",[532,14711,14712],{"class":534,"line":661},[532,14713,596],{"emptyLinePlaceholder":595},[532,14715,14716],{"class":534,"line":674},[532,14717,14718],{},"CREATE POLICY \"public can read instruments\"\n",[532,14720,14721],{"class":534,"line":688},[532,14722,14723],{},"ON public.instruments FOR SELECT TO anon USING (true);\n",[432,14725,14726],{},[436,14727,14728],{},"3. Tạo Nuxt app:",[523,14730,14732],{"className":525,"code":14731,"language":527,"meta":528,"style":528},"npx nuxi@latest init my-app\ncd my-app && npm install @supabase\u002Fsupabase-js\n",[445,14733,14734,14747],{"__ignoreMap":528},[532,14735,14736,14739,14742,14744],{"class":534,"line":535},[532,14737,14738],{"class":545},"npx",[532,14740,14741],{"class":553}," nuxi@latest",[532,14743,12452],{"class":553},[532,14745,14746],{"class":553}," my-app\n",[532,14748,14749,14752,14755,14758,14761,14763],{"class":534,"line":542},[532,14750,14751],{"class":1372},"cd",[532,14753,14754],{"class":553}," my-app",[532,14756,14757],{"class":549}," &&",[532,14759,14760],{"class":545}," npm",[532,14762,12330],{"class":553},[532,14764,14765],{"class":553}," @supabase\u002Fsupabase-js\n",[432,14767,14768],{},[436,14769,14770,14771,954],{},"4. Cấu hình ",[445,14772,14773],{},".env",[523,14775,14777],{"className":525,"code":14776,"language":527,"meta":528,"style":528},"SUPABASE_URL=https:\u002F\u002F[PROJECT_REF].supabase.co\nSUPABASE_PUBLISHABLE_KEY=eyJhbG...[your-anon-key]\n",[445,14778,14779,14792],{"__ignoreMap":528},[532,14780,14781,14784,14786,14789],{"class":534,"line":535},[532,14782,14783],{"class":560},"SUPABASE_URL",[532,14785,982],{"class":549},[532,14787,14788],{"class":553},"https:\u002F\u002F[PROJECT_REF",[532,14790,14791],{"class":560},"].supabase.co\n",[532,14793,14794,14797,14799,14802],{"class":534,"line":542},[532,14795,14796],{"class":560},"SUPABASE_PUBLISHABLE_KEY",[532,14798,982],{"class":549},[532,14800,14801],{"class":553},"eyJhbG...[your-anon-key",[532,14803,14804],{"class":560},"]\n",[432,14806,14807],{},[436,14808,14809,14810,954],{},"5. Cấu hình ",[445,14811,14812],{},"nuxt.config.ts",[523,14814,14816],{"className":11854,"code":14815,"language":11856,"meta":528,"style":528},"export default defineNuxtConfig({\n  runtimeConfig: {\n    public: {\n      supabaseUrl: process.env.SUPABASE_URL,\n      supabasePublishableKey: process.env.SUPABASE_PUBLISHABLE_KEY\n    }\n  }\n})\n",[445,14817,14818,14833,14842,14851,14872,14890,14894,14898],{"__ignoreMap":528},[532,14819,14820,14823,14826,14829,14831],{"class":534,"line":535},[532,14821,14822],{"class":1335},"export",[532,14824,14825],{"class":1335}," default",[532,14827,14828],{"class":1372}," defineNuxtConfig",[532,14830,1197],{"class":560},[532,14832,2288],{"class":549},[532,14834,14835,14838,14840],{"class":534,"line":542},[532,14836,14837],{"class":1756},"  runtimeConfig",[532,14839,954],{"class":549},[532,14841,2628],{"class":549},[532,14843,14844,14847,14849],{"class":534,"line":564},[532,14845,14846],{"class":1756},"    public",[532,14848,954],{"class":549},[532,14850,2628],{"class":549},[532,14852,14853,14856,14858,14861,14863,14866,14868,14870],{"class":534,"line":579},[532,14854,14855],{"class":1756},"      supabaseUrl",[532,14857,954],{"class":549},[532,14859,14860],{"class":560}," process",[532,14862,448],{"class":549},[532,14864,14865],{"class":560},"env",[532,14867,448],{"class":549},[532,14869,14783],{"class":560},[532,14871,1388],{"class":549},[532,14873,14874,14877,14879,14881,14883,14885,14887],{"class":534,"line":592},[532,14875,14876],{"class":1756},"      supabasePublishableKey",[532,14878,954],{"class":549},[532,14880,14860],{"class":560},[532,14882,448],{"class":549},[532,14884,14865],{"class":560},[532,14886,448],{"class":549},[532,14888,14889],{"class":560},"SUPABASE_PUBLISHABLE_KEY\n",[532,14891,14892],{"class":534,"line":599},[532,14893,11641],{"class":549},[532,14895,14896],{"class":534,"line":605},[532,14897,4428],{"class":549},[532,14899,14900,14902],{"class":534,"line":619},[532,14901,1659],{"class":549},[532,14903,1203],{"class":560},[432,14905,14906],{},[436,14907,14908,14909,954],{},"6. Query data trong ",[445,14910,14911],{},"app.vue",[523,14913,14917],{"className":14914,"code":14915,"language":14916,"meta":528,"style":528},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup>\nimport { createClient } from '@supabase\u002Fsupabase-js'\n\nconst config = useRuntimeConfig()\nconst supabase = createClient(\n  config.public.supabaseUrl,\n  config.public.supabasePublishableKey\n)\nconst instruments = ref([])\n\nasync function getInstruments() {\n  const { data } = await supabase.from('instruments').select()\n  instruments.value = data\n}\n\nonMounted(() => { getInstruments() })\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cul>\n    \u003Cli v-for=\"instrument in instruments\" :key=\"instrument.id\">\n      {{ instrument.name }}\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n","vue",[445,14918,14919,14932,14950,14954,14968,14980,14995,15008,15012,15027,15031,15044,15081,15094,15098,15102,15123,15132,15136,15145,15154,15188,15193,15202,15211],{"__ignoreMap":528},[532,14920,14921,14923,14926,14929],{"class":534,"line":535},[532,14922,1042],{"class":549},[532,14924,14925],{"class":1756},"script",[532,14927,14928],{"class":1363}," setup",[532,14930,14931],{"class":549},">\n",[532,14933,14934,14936,14938,14940,14942,14944,14946,14948],{"class":534,"line":542},[532,14935,1336],{"class":1335},[532,14937,1339],{"class":549},[532,14939,1342],{"class":560},[532,14941,1345],{"class":549},[532,14943,1348],{"class":1335},[532,14945,550],{"class":549},[532,14947,1309],{"class":553},[532,14949,589],{"class":549},[532,14951,14952],{"class":534,"line":564},[532,14953,596],{"emptyLinePlaceholder":595},[532,14955,14956,14958,14961,14963,14966],{"class":534,"line":579},[532,14957,1364],{"class":1363},[532,14959,14960],{"class":560}," config ",[532,14962,982],{"class":549},[532,14964,14965],{"class":1372}," useRuntimeConfig",[532,14967,1996],{"class":560},[532,14969,14970,14972,14974,14976,14978],{"class":534,"line":592},[532,14971,1364],{"class":1363},[532,14973,1367],{"class":560},[532,14975,982],{"class":549},[532,14977,1342],{"class":1372},[532,14979,1375],{"class":560},[532,14981,14982,14984,14986,14988,14990,14993],{"class":534,"line":599},[532,14983,9538],{"class":560},[532,14985,448],{"class":549},[532,14987,2418],{"class":560},[532,14989,448],{"class":549},[532,14991,14992],{"class":560},"supabaseUrl",[532,14994,1388],{"class":549},[532,14996,14997,14999,15001,15003,15005],{"class":534,"line":605},[532,14998,9538],{"class":560},[532,15000,448],{"class":549},[532,15002,2418],{"class":560},[532,15004,448],{"class":549},[532,15006,15007],{"class":560},"supabasePublishableKey\n",[532,15009,15010],{"class":534,"line":619},[532,15011,1203],{"class":560},[532,15013,15014,15016,15019,15021,15024],{"class":534,"line":630},[532,15015,1364],{"class":1363},[532,15017,15018],{"class":560}," instruments ",[532,15020,982],{"class":549},[532,15022,15023],{"class":1372}," ref",[532,15025,15026],{"class":560},"([])\n",[532,15028,15029],{"class":534,"line":635},[532,15030,596],{"emptyLinePlaceholder":595},[532,15032,15033,15035,15037,15040,15042],{"class":534,"line":641},[532,15034,10913],{"class":1363},[532,15036,11354],{"class":1363},[532,15038,15039],{"class":1372}," getInstruments",[532,15041,8682],{"class":549},[532,15043,2628],{"class":549},[532,15045,15046,15048,15050,15052,15054,15056,15058,15060,15062,15064,15066,15068,15071,15073,15075,15077,15079],{"class":534,"line":661},[532,15047,11376],{"class":1363},[532,15049,1339],{"class":549},[532,15051,1650],{"class":560},[532,15053,1345],{"class":549},[532,15055,1662],{"class":549},[532,15057,1665],{"class":1335},[532,15059,2273],{"class":560},[532,15061,448],{"class":549},[532,15063,1676],{"class":1372},[532,15065,1197],{"class":1756},[532,15067,557],{"class":549},[532,15069,15070],{"class":553},"instruments",[532,15072,557],{"class":549},[532,15074,1310],{"class":1756},[532,15076,448],{"class":549},[532,15078,870],{"class":1372},[532,15080,1996],{"class":1756},[532,15082,15083,15086,15088,15090,15092],{"class":534,"line":674},[532,15084,15085],{"class":560},"  instruments",[532,15087,448],{"class":549},[532,15089,7857],{"class":560},[532,15091,1662],{"class":549},[532,15093,5397],{"class":560},[532,15095,15096],{"class":534,"line":688},[532,15097,11266],{"class":549},[532,15099,15100],{"class":534,"line":702},[532,15101,596],{"emptyLinePlaceholder":595},[532,15103,15104,15107,15109,15111,15113,15115,15117,15119,15121],{"class":534,"line":715},[532,15105,15106],{"class":1372},"onMounted",[532,15108,1197],{"class":560},[532,15110,8682],{"class":549},[532,15112,2452],{"class":1363},[532,15114,1339],{"class":549},[532,15116,15039],{"class":1372},[532,15118,11632],{"class":1756},[532,15120,1659],{"class":549},[532,15122,1203],{"class":560},[532,15124,15125,15128,15130],{"class":534,"line":720},[532,15126,15127],{"class":549},"\u003C\u002F",[532,15129,14925],{"class":1756},[532,15131,14931],{"class":549},[532,15133,15134],{"class":534,"line":726},[532,15135,596],{"emptyLinePlaceholder":595},[532,15137,15138,15140,15143],{"class":534,"line":745},[532,15139,1042],{"class":549},[532,15141,15142],{"class":1756},"template",[532,15144,14931],{"class":549},[532,15146,15147,15150,15152],{"class":534,"line":758},[532,15148,15149],{"class":549},"  \u003C",[532,15151,455],{"class":1756},[532,15153,14931],{"class":549},[532,15155,15156,15159,15161,15164,15166,15169,15172,15174,15177,15179,15181,15184,15186],{"class":534,"line":771},[532,15157,15158],{"class":549},"    \u003C",[532,15160,458],{"class":1756},[532,15162,15163],{"class":1363}," v-for",[532,15165,982],{"class":549},[532,15167,15168],{"class":549},"\"",[532,15170,15171],{"class":553},"instrument in instruments",[532,15173,15168],{"class":549},[532,15175,15176],{"class":1363}," :key",[532,15178,982],{"class":549},[532,15180,15168],{"class":549},[532,15182,15183],{"class":553},"instrument.id",[532,15185,15168],{"class":549},[532,15187,14931],{"class":549},[532,15189,15190],{"class":534,"line":783},[532,15191,15192],{"class":560},"      {{ instrument.name }}\n",[532,15194,15195,15198,15200],{"class":534,"line":788},[532,15196,15197],{"class":549},"    \u003C\u002F",[532,15199,458],{"class":1756},[532,15201,14931],{"class":549},[532,15203,15204,15207,15209],{"class":534,"line":794},[532,15205,15206],{"class":549},"  \u003C\u002F",[532,15208,455],{"class":1756},[532,15210,14931],{"class":549},[532,15212,15213,15215,15217],{"class":534,"line":812},[532,15214,15127],{"class":549},[532,15216,15142],{"class":1756},[532,15218,14931],{"class":549},[432,15220,15221],{},[436,15222,15223],{},"7. Chạy app:",[523,15225,15227],{"className":525,"code":15226,"language":527,"meta":528,"style":528},"npm run dev\n",[445,15228,15229],{"__ignoreMap":528},[532,15230,15231,15233,15236],{"class":534,"line":535},[532,15232,12327],{"class":545},[532,15234,15235],{"class":553}," run",[532,15237,15238],{"class":553}," dev\n",[496,15240,15242,15243,15246,15247,507,15250,507,15253,15256],{"color":9339,"icon":15241},"i-lucide-info","Có community-maintained module ",[445,15244,15245],{},"@nuxtjs\u002Fsupabase"," cung cấp DX tốt hơn cho Nuxt với composables như ",[445,15248,15249],{},"useSupabaseClient()",[445,15251,15252],{},"useSupabaseUser()",[445,15254,15255],{},"useSupabaseSession()",". Nên dùng module này thay vì tự tạo client trong production.",[450,15258,15260],{"id":15259},"react-vite-quickstart","React + Vite Quickstart",[523,15262,15264],{"className":525,"code":15263,"language":527,"meta":528,"style":528},"npm create vite@latest my-app -- --template react\ncd my-app && npm install @supabase\u002Fsupabase-js\n",[445,15265,15266,15286],{"__ignoreMap":528},[532,15267,15268,15270,15272,15275,15277,15280,15283],{"class":534,"line":535},[532,15269,12327],{"class":545},[532,15271,13532],{"class":553},[532,15273,15274],{"class":553}," vite@latest",[532,15276,14754],{"class":553},[532,15278,15279],{"class":553}," --",[532,15281,15282],{"class":553}," --template",[532,15284,15285],{"class":553}," react\n",[532,15287,15288,15290,15292,15294,15296,15298],{"class":534,"line":542},[532,15289,14751],{"class":1372},[532,15291,14754],{"class":553},[532,15293,14757],{"class":549},[532,15295,14760],{"class":545},[532,15297,12330],{"class":553},[532,15299,14765],{"class":553},[523,15301,15305],{"className":15302,"code":15303,"language":15304,"meta":528,"style":528},"language-jsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F App.jsx\nimport { createClient } from '@supabase\u002Fsupabase-js'\nimport { useEffect, useState } from 'react'\n\nconst supabase = createClient(\n  import.meta.env.VITE_SUPABASE_URL,\n  import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY\n)\n\nfunction App() {\n  const [instruments, setInstruments] = useState([])\n\n  useEffect(() => { getInstruments() }, [])\n\n  async function getInstruments() {\n    const { data } = await supabase.from('instruments').select()\n    setInstruments(data)\n  }\n\n  return (\n    \u003Cul>\n      {instruments.map((inst) => (\n        \u003Cli key={inst.id}>{inst.name}\u003C\u002Fli>\n      ))}\n    \u003C\u002Ful>\n  )\n}\n\nexport default App\n","jsx",[445,15306,15307,15312,15317,15322,15326,15331,15336,15341,15345,15349,15354,15359,15363,15368,15372,15377,15382,15387,15391,15395,15400,15405,15410,15415,15420,15425,15429,15433,15437],{"__ignoreMap":528},[532,15308,15309],{"class":534,"line":535},[532,15310,15311],{},"\u002F\u002F App.jsx\n",[532,15313,15314],{"class":534,"line":542},[532,15315,15316],{},"import { createClient } from '@supabase\u002Fsupabase-js'\n",[532,15318,15319],{"class":534,"line":564},[532,15320,15321],{},"import { useEffect, useState } from 'react'\n",[532,15323,15324],{"class":534,"line":579},[532,15325,596],{"emptyLinePlaceholder":595},[532,15327,15328],{"class":534,"line":592},[532,15329,15330],{},"const supabase = createClient(\n",[532,15332,15333],{"class":534,"line":599},[532,15334,15335],{},"  import.meta.env.VITE_SUPABASE_URL,\n",[532,15337,15338],{"class":534,"line":605},[532,15339,15340],{},"  import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY\n",[532,15342,15343],{"class":534,"line":619},[532,15344,1203],{},[532,15346,15347],{"class":534,"line":630},[532,15348,596],{"emptyLinePlaceholder":595},[532,15350,15351],{"class":534,"line":635},[532,15352,15353],{},"function App() {\n",[532,15355,15356],{"class":534,"line":641},[532,15357,15358],{},"  const [instruments, setInstruments] = useState([])\n",[532,15360,15361],{"class":534,"line":661},[532,15362,596],{"emptyLinePlaceholder":595},[532,15364,15365],{"class":534,"line":674},[532,15366,15367],{},"  useEffect(() => { getInstruments() }, [])\n",[532,15369,15370],{"class":534,"line":688},[532,15371,596],{"emptyLinePlaceholder":595},[532,15373,15374],{"class":534,"line":702},[532,15375,15376],{},"  async function getInstruments() {\n",[532,15378,15379],{"class":534,"line":715},[532,15380,15381],{},"    const { data } = await supabase.from('instruments').select()\n",[532,15383,15384],{"class":534,"line":720},[532,15385,15386],{},"    setInstruments(data)\n",[532,15388,15389],{"class":534,"line":726},[532,15390,4428],{},[532,15392,15393],{"class":534,"line":745},[532,15394,596],{"emptyLinePlaceholder":595},[532,15396,15397],{"class":534,"line":758},[532,15398,15399],{},"  return (\n",[532,15401,15402],{"class":534,"line":771},[532,15403,15404],{},"    \u003Cul>\n",[532,15406,15407],{"class":534,"line":783},[532,15408,15409],{},"      {instruments.map((inst) => (\n",[532,15411,15412],{"class":534,"line":788},[532,15413,15414],{},"        \u003Cli key={inst.id}>{inst.name}\u003C\u002Fli>\n",[532,15416,15417],{"class":534,"line":794},[532,15418,15419],{},"      ))}\n",[532,15421,15422],{"class":534,"line":812},[532,15423,15424],{},"    \u003C\u002Ful>\n",[532,15426,15427],{"class":534,"line":825},[532,15428,2485],{},[532,15430,15431],{"class":534,"line":2099},[532,15432,11266],{},[532,15434,15435],{"class":534,"line":2105},[532,15436,596],{"emptyLinePlaceholder":595},[532,15438,15439],{"class":534,"line":2126},[532,15440,15441],{},"export default App\n",[450,15443,15445],{"id":15444},"nextjs-quickstart-app-router","Next.js Quickstart (App Router)",[523,15447,15449],{"className":525,"code":15448,"language":527,"meta":528,"style":528},"npx create-next-app -e with-supabase\n",[445,15450,15451],{"__ignoreMap":528},[532,15452,15453,15455,15458,15461],{"class":534,"line":535},[532,15454,14738],{"class":545},[532,15456,15457],{"class":553}," create-next-app",[532,15459,15460],{"class":553}," -e",[532,15462,15463],{"class":553}," with-supabase\n",[523,15465,15467],{"className":11854,"code":15466,"language":11856,"meta":528,"style":528},"\u002F\u002F app\u002Finstruments\u002Fpage.tsx\nimport { createClient } from '@\u002Futils\u002Fsupabase\u002Fserver'\nimport { Suspense } from 'react'\n\nasync function InstrumentsData() {\n  const supabase = await createClient()\n  const { data: instruments } = await supabase.from('instruments').select()\n\n  return \u003Cpre>{JSON.stringify(instruments, null, 2)}\u003C\u002Fpre>\n}\n\nexport default function Instruments() {\n  return (\n    \u003CSuspense fallback={\u003Cdiv>Loading instruments...\u003C\u002Fdiv>}>\n      \u003CInstrumentsData \u002F>\n    \u003C\u002FSuspense>\n  )\n}\n",[445,15468,15469,15474,15493,15513,15517,15530,15544,15585,15589,15623,15627,15631,15646,15653,15678,15689,15697,15701],{"__ignoreMap":528},[532,15470,15471],{"class":534,"line":535},[532,15472,15473],{"class":538},"\u002F\u002F app\u002Finstruments\u002Fpage.tsx\n",[532,15475,15476,15478,15480,15482,15484,15486,15488,15491],{"class":534,"line":542},[532,15477,1336],{"class":1335},[532,15479,1339],{"class":549},[532,15481,1342],{"class":560},[532,15483,1345],{"class":549},[532,15485,1348],{"class":1335},[532,15487,550],{"class":549},[532,15489,15490],{"class":553},"@\u002Futils\u002Fsupabase\u002Fserver",[532,15492,589],{"class":549},[532,15494,15495,15497,15499,15502,15504,15506,15508,15511],{"class":534,"line":564},[532,15496,1336],{"class":1335},[532,15498,1339],{"class":549},[532,15500,15501],{"class":560}," Suspense",[532,15503,1345],{"class":549},[532,15505,1348],{"class":1335},[532,15507,550],{"class":549},[532,15509,15510],{"class":553},"react",[532,15512,589],{"class":549},[532,15514,15515],{"class":534,"line":579},[532,15516,596],{"emptyLinePlaceholder":595},[532,15518,15519,15521,15523,15526,15528],{"class":534,"line":592},[532,15520,10913],{"class":1363},[532,15522,11354],{"class":1363},[532,15524,15525],{"class":1372}," InstrumentsData",[532,15527,8682],{"class":549},[532,15529,2628],{"class":549},[532,15531,15532,15534,15536,15538,15540,15542],{"class":534,"line":599},[532,15533,11376],{"class":1363},[532,15535,2273],{"class":560},[532,15537,1662],{"class":549},[532,15539,1665],{"class":1335},[532,15541,1342],{"class":1372},[532,15543,1996],{"class":1756},[532,15545,15546,15548,15550,15552,15554,15557,15559,15561,15563,15565,15567,15569,15571,15573,15575,15577,15579,15581,15583],{"class":534,"line":605},[532,15547,11376],{"class":1363},[532,15549,1339],{"class":549},[532,15551,1650],{"class":1756},[532,15553,954],{"class":549},[532,15555,15556],{"class":560}," instruments",[532,15558,1345],{"class":549},[532,15560,1662],{"class":549},[532,15562,1665],{"class":1335},[532,15564,2273],{"class":560},[532,15566,448],{"class":549},[532,15568,1676],{"class":1372},[532,15570,1197],{"class":1756},[532,15572,557],{"class":549},[532,15574,15070],{"class":553},[532,15576,557],{"class":549},[532,15578,1310],{"class":1756},[532,15580,448],{"class":549},[532,15582,870],{"class":1372},[532,15584,1996],{"class":1756},[532,15586,15587],{"class":534,"line":619},[532,15588,596],{"emptyLinePlaceholder":595},[532,15590,15591,15593,15595,15597,15599,15601,15604,15606,15608,15610,15612,15614,15616,15619,15621],{"class":534,"line":630},[532,15592,11656],{"class":1335},[532,15594,12820],{"class":1756},[532,15596,523],{"class":545},[532,15598,1012],{"class":1756},[532,15600,1851],{"class":549},[532,15602,15603],{"class":1756},"JSON.stringify(",[532,15605,15070],{"class":560},[532,15607,1653],{"class":549},[532,15609,2897],{"class":560},[532,15611,1653],{"class":549},[532,15613,2987],{"class":1782},[532,15615,1310],{"class":1756},[532,15617,15618],{"class":549},"}\u003C\u002F",[532,15620,523],{"class":560},[532,15622,14931],{"class":549},[532,15624,15625],{"class":534,"line":635},[532,15626,11266],{"class":549},[532,15628,15629],{"class":534,"line":641},[532,15630,596],{"emptyLinePlaceholder":595},[532,15632,15633,15635,15637,15639,15642,15644],{"class":534,"line":661},[532,15634,14822],{"class":1335},[532,15636,14825],{"class":1335},[532,15638,11354],{"class":1363},[532,15640,15641],{"class":1372}," Instruments",[532,15643,8682],{"class":549},[532,15645,2628],{"class":549},[532,15647,15648,15650],{"class":534,"line":674},[532,15649,11656],{"class":1335},[532,15651,15652],{"class":1756}," (\n",[532,15654,15655,15657,15660,15663,15666,15669,15672,15675],{"class":534,"line":688},[532,15656,15158],{"class":549},[532,15658,15659],{"class":560},"Suspense",[532,15661,15662],{"class":560}," fallback",[532,15664,15665],{"class":549},"={",[532,15667,15668],{"class":1756},"\u003Cdiv>Loading instruments",[532,15670,15671],{"class":549},"...\u003C\u002F",[532,15673,15674],{"class":560},"div",[532,15676,15677],{"class":549},">}>\n",[532,15679,15680,15683,15686],{"class":534,"line":702},[532,15681,15682],{"class":549},"      \u003C",[532,15684,15685],{"class":560},"InstrumentsData",[532,15687,15688],{"class":549}," \u002F>\n",[532,15690,15691,15693,15695],{"class":534,"line":715},[532,15692,15197],{"class":549},[532,15694,15659],{"class":560},[532,15696,14931],{"class":549},[532,15698,15699],{"class":534,"line":720},[532,15700,2485],{"class":1756},[532,15702,15703],{"class":534,"line":726},[532,15704,11266],{"class":549},[450,15706,15708],{"id":15707},"flutter-quickstart","Flutter Quickstart",[523,15710,15714],{"className":15711,"code":15712,"language":15713,"meta":528,"style":528},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import 'package:supabase_flutter\u002Fsupabase_flutter.dart';\n\nFuture\u003Cvoid> main() async {\n  await Supabase.initialize(\n    url: 'https:\u002F\u002F[PROJECT_REF].supabase.co',\n    anonKey: 'your-anon-key',\n  );\n  runApp(MyApp());\n}\n\n\u002F\u002F Query data\nfinal data = await Supabase.instance.client\n  .from('instruments')\n  .select();\n","dart",[445,15715,15716,15721,15725,15730,15735,15740,15745,15750,15755,15759,15763,15768,15773,15778],{"__ignoreMap":528},[532,15717,15718],{"class":534,"line":535},[532,15719,15720],{},"import 'package:supabase_flutter\u002Fsupabase_flutter.dart';\n",[532,15722,15723],{"class":534,"line":542},[532,15724,596],{"emptyLinePlaceholder":595},[532,15726,15727],{"class":534,"line":564},[532,15728,15729],{},"Future\u003Cvoid> main() async {\n",[532,15731,15732],{"class":534,"line":579},[532,15733,15734],{},"  await Supabase.initialize(\n",[532,15736,15737],{"class":534,"line":592},[532,15738,15739],{},"    url: 'https:\u002F\u002F[PROJECT_REF].supabase.co',\n",[532,15741,15742],{"class":534,"line":599},[532,15743,15744],{},"    anonKey: 'your-anon-key',\n",[532,15746,15747],{"class":534,"line":605},[532,15748,15749],{},"  );\n",[532,15751,15752],{"class":534,"line":619},[532,15753,15754],{},"  runApp(MyApp());\n",[532,15756,15757],{"class":534,"line":630},[532,15758,11266],{},[532,15760,15761],{"class":534,"line":635},[532,15762,596],{"emptyLinePlaceholder":595},[532,15764,15765],{"class":534,"line":641},[532,15766,15767],{},"\u002F\u002F Query data\n",[532,15769,15770],{"class":534,"line":661},[532,15771,15772],{},"final data = await Supabase.instance.client\n",[532,15774,15775],{"class":534,"line":674},[532,15776,15777],{},"  .from('instruments')\n",[532,15779,15780],{"class":534,"line":688},[532,15781,15782],{},"  .select();\n",[450,15784,15786],{"id":15785},"auth-setup-dùng-chung-cho-mọi-framework","Auth Setup -- dùng chung cho mọi framework",[523,15788,15790],{"className":1326,"code":15789,"language":1328,"meta":528,"style":528},"\u002F\u002F signUp\nconst { data, error } = await supabase.auth.signUp({\n  email: 'user@example.com',\n  password: 'password123'\n})\n\n\u002F\u002F signIn\nconst { data, error } = await supabase.auth.signInWithPassword({\n  email: 'user@example.com',\n  password: 'password123'\n})\n\n\u002F\u002F signIn with OAuth\nconst { data, error } = await supabase.auth.signInWithOAuth({\n  provider: 'google',\n  options: { redirectTo: 'https:\u002F\u002Fmyapp.com\u002Fauth\u002Fcallback' }\n})\n\n\u002F\u002F signOut\nawait supabase.auth.signOut()\n\n\u002F\u002F Listen auth state changes\nsupabase.auth.onAuthStateChange((event, session) => {\n  if (event === 'SIGNED_IN') console.log('User signed in:', session.user)\n  if (event === 'SIGNED_OUT') console.log('User signed out')\n})\n",[445,15791,15792,15797,15829,15843,15855,15861,15865,15870,15902,15916,15928,15934,15938,15943,15975,15989,16009,16015,16019,16024,16040,16044,16049,16077,16123,16159],{"__ignoreMap":528},[532,15793,15794],{"class":534,"line":535},[532,15795,15796],{"class":538},"\u002F\u002F signUp\n",[532,15798,15799,15801,15803,15805,15807,15809,15811,15813,15815,15817,15819,15821,15823,15825,15827],{"class":534,"line":542},[532,15800,1364],{"class":1363},[532,15802,1339],{"class":549},[532,15804,1650],{"class":560},[532,15806,1653],{"class":549},[532,15808,1656],{"class":560},[532,15810,1659],{"class":549},[532,15812,1662],{"class":549},[532,15814,1665],{"class":1335},[532,15816,2273],{"class":560},[532,15818,448],{"class":549},[532,15820,2278],{"class":560},[532,15822,448],{"class":549},[532,15824,2283],{"class":1372},[532,15826,1197],{"class":560},[532,15828,2288],{"class":549},[532,15830,15831,15833,15835,15837,15839,15841],{"class":534,"line":564},[532,15832,2294],{"class":1756},[532,15834,954],{"class":549},[532,15836,550],{"class":549},[532,15838,2301],{"class":553},[532,15840,557],{"class":549},[532,15842,1388],{"class":549},[532,15844,15845,15847,15849,15851,15853],{"class":534,"line":579},[532,15846,2311],{"class":1756},[532,15848,954],{"class":549},[532,15850,550],{"class":549},[532,15852,7080],{"class":553},[532,15854,589],{"class":549},[532,15856,15857,15859],{"class":534,"line":592},[532,15858,1659],{"class":549},[532,15860,1203],{"class":560},[532,15862,15863],{"class":534,"line":599},[532,15864,596],{"emptyLinePlaceholder":595},[532,15866,15867],{"class":534,"line":605},[532,15868,15869],{"class":538},"\u002F\u002F signIn\n",[532,15871,15872,15874,15876,15878,15880,15882,15884,15886,15888,15890,15892,15894,15896,15898,15900],{"class":534,"line":619},[532,15873,1364],{"class":1363},[532,15875,1339],{"class":549},[532,15877,1650],{"class":560},[532,15879,1653],{"class":549},[532,15881,1656],{"class":560},[532,15883,1659],{"class":549},[532,15885,1662],{"class":549},[532,15887,1665],{"class":1335},[532,15889,2273],{"class":560},[532,15891,448],{"class":549},[532,15893,2278],{"class":560},[532,15895,448],{"class":549},[532,15897,4472],{"class":1372},[532,15899,1197],{"class":560},[532,15901,2288],{"class":549},[532,15903,15904,15906,15908,15910,15912,15914],{"class":534,"line":630},[532,15905,2294],{"class":1756},[532,15907,954],{"class":549},[532,15909,550],{"class":549},[532,15911,2301],{"class":553},[532,15913,557],{"class":549},[532,15915,1388],{"class":549},[532,15917,15918,15920,15922,15924,15926],{"class":534,"line":635},[532,15919,2311],{"class":1756},[532,15921,954],{"class":549},[532,15923,550],{"class":549},[532,15925,7080],{"class":553},[532,15927,589],{"class":549},[532,15929,15930,15932],{"class":534,"line":641},[532,15931,1659],{"class":549},[532,15933,1203],{"class":560},[532,15935,15936],{"class":534,"line":661},[532,15937,596],{"emptyLinePlaceholder":595},[532,15939,15940],{"class":534,"line":674},[532,15941,15942],{"class":538},"\u002F\u002F signIn with OAuth\n",[532,15944,15945,15947,15949,15951,15953,15955,15957,15959,15961,15963,15965,15967,15969,15971,15973],{"class":534,"line":688},[532,15946,1364],{"class":1363},[532,15948,1339],{"class":549},[532,15950,1650],{"class":560},[532,15952,1653],{"class":549},[532,15954,1656],{"class":560},[532,15956,1659],{"class":549},[532,15958,1662],{"class":549},[532,15960,1665],{"class":1335},[532,15962,2273],{"class":560},[532,15964,448],{"class":549},[532,15966,2278],{"class":560},[532,15968,448],{"class":549},[532,15970,4818],{"class":1372},[532,15972,1197],{"class":560},[532,15974,2288],{"class":549},[532,15976,15977,15979,15981,15983,15985,15987],{"class":534,"line":702},[532,15978,4827],{"class":1756},[532,15980,954],{"class":549},[532,15982,550],{"class":549},[532,15984,4834],{"class":553},[532,15986,557],{"class":549},[532,15988,1388],{"class":549},[532,15990,15991,15993,15995,15997,15999,16001,16003,16005,16007],{"class":534,"line":715},[532,15992,4360],{"class":1756},[532,15994,954],{"class":549},[532,15996,1339],{"class":549},[532,15998,5961],{"class":1756},[532,16000,954],{"class":549},[532,16002,550],{"class":549},[532,16004,4585],{"class":553},[532,16006,557],{"class":549},[532,16008,2653],{"class":549},[532,16010,16011,16013],{"class":534,"line":720},[532,16012,1659],{"class":549},[532,16014,1203],{"class":560},[532,16016,16017],{"class":534,"line":726},[532,16018,596],{"emptyLinePlaceholder":595},[532,16020,16021],{"class":534,"line":745},[532,16022,16023],{"class":538},"\u002F\u002F signOut\n",[532,16025,16026,16028,16030,16032,16034,16036,16038],{"class":534,"line":758},[532,16027,10146],{"class":1335},[532,16029,2273],{"class":560},[532,16031,448],{"class":549},[532,16033,2278],{"class":560},[532,16035,448],{"class":549},[532,16037,5663],{"class":1372},[532,16039,1996],{"class":560},[532,16041,16042],{"class":534,"line":771},[532,16043,596],{"emptyLinePlaceholder":595},[532,16045,16046],{"class":534,"line":783},[532,16047,16048],{"class":538},"\u002F\u002F Listen auth state changes\n",[532,16050,16051,16053,16055,16057,16059,16061,16063,16065,16067,16069,16071,16073,16075],{"class":534,"line":788},[532,16052,11280],{"class":560},[532,16054,448],{"class":549},[532,16056,2278],{"class":560},[532,16058,448],{"class":549},[532,16060,5525],{"class":1372},[532,16062,1197],{"class":560},[532,16064,1197],{"class":549},[532,16066,5536],{"class":2446},[532,16068,1653],{"class":549},[532,16070,5386],{"class":2446},[532,16072,1310],{"class":549},[532,16074,2452],{"class":1363},[532,16076,2628],{"class":549},[532,16078,16079,16081,16083,16085,16087,16089,16092,16094,16096,16099,16101,16103,16105,16107,16110,16112,16114,16116,16118,16121],{"class":534,"line":794},[532,16080,10934],{"class":1335},[532,16082,10916],{"class":1756},[532,16084,5536],{"class":560},[532,16086,10941],{"class":549},[532,16088,550],{"class":549},[532,16090,16091],{"class":553},"SIGNED_IN",[532,16093,557],{"class":549},[532,16095,1768],{"class":1756},[532,16097,16098],{"class":560},"console",[532,16100,448],{"class":549},[532,16102,2460],{"class":1372},[532,16104,1197],{"class":1756},[532,16106,557],{"class":549},[532,16108,16109],{"class":553},"User signed in:",[532,16111,557],{"class":549},[532,16113,1653],{"class":549},[532,16115,5386],{"class":560},[532,16117,448],{"class":549},[532,16119,16120],{"class":560},"user",[532,16122,1203],{"class":1756},[532,16124,16125,16127,16129,16131,16133,16135,16138,16140,16142,16144,16146,16148,16150,16152,16155,16157],{"class":534,"line":812},[532,16126,10934],{"class":1335},[532,16128,10916],{"class":1756},[532,16130,5536],{"class":560},[532,16132,10941],{"class":549},[532,16134,550],{"class":549},[532,16136,16137],{"class":553},"SIGNED_OUT",[532,16139,557],{"class":549},[532,16141,1768],{"class":1756},[532,16143,16098],{"class":560},[532,16145,448],{"class":549},[532,16147,2460],{"class":1372},[532,16149,1197],{"class":1756},[532,16151,557],{"class":549},[532,16153,16154],{"class":553},"User signed out",[532,16156,557],{"class":549},[532,16158,1203],{"class":1756},[532,16160,16161,16163],{"class":534,"line":825},[532,16162,1659],{"class":549},[532,16164,1203],{"class":560},[450,16166,16168],{"id":16167},"realtime-subscription-pattern","Realtime Subscription pattern",[523,16170,16172],{"className":1326,"code":16171,"language":1328,"meta":528,"style":528},"const channel = supabase\n  .channel('user-posts')\n  .on(\n    'postgres_changes',\n    {\n      event: '*',\n      schema: 'public',\n      table: 'posts',\n      filter: `user_id=eq.${user.id}`\n    },\n    (payload) => {\n      if (payload.eventType === 'INSERT') {\n        posts.value = [payload.new, ...posts.value]\n      }\n      if (payload.eventType === 'DELETE') {\n        posts.value = posts.value.filter(p => p.id !== payload.old.id)\n      }\n    }\n  )\n  .subscribe()\n",[445,16173,16174,16184,16201,16209,16220,16225,16240,16255,16270,16294,16299,16311,16336,16368,16372,16397,16446,16450,16454,16458],{"__ignoreMap":528},[532,16175,16176,16178,16180,16182],{"class":534,"line":535},[532,16177,1364],{"class":1363},[532,16179,2346],{"class":560},[532,16181,982],{"class":549},[532,16183,1668],{"class":560},[532,16185,16186,16188,16190,16192,16194,16197,16199],{"class":534,"line":542},[532,16187,1673],{"class":549},[532,16189,2358],{"class":1372},[532,16191,1197],{"class":560},[532,16193,557],{"class":549},[532,16195,16196],{"class":553},"user-posts",[532,16198,557],{"class":549},[532,16200,1203],{"class":560},[532,16202,16203,16205,16207],{"class":534,"line":564},[532,16204,1673],{"class":549},[532,16206,2377],{"class":1372},[532,16208,1375],{"class":560},[532,16210,16211,16214,16216,16218],{"class":534,"line":579},[532,16212,16213],{"class":549},"    '",[532,16215,2384],{"class":553},[532,16217,557],{"class":549},[532,16219,1388],{"class":549},[532,16221,16222],{"class":534,"line":592},[532,16223,16224],{"class":549},"    {\n",[532,16226,16227,16230,16232,16234,16236,16238],{"class":534,"line":599},[532,16228,16229],{"class":1756},"      event",[532,16231,954],{"class":549},[532,16233,550],{"class":549},[532,16235,9661],{"class":553},[532,16237,557],{"class":549},[532,16239,1388],{"class":549},[532,16241,16242,16245,16247,16249,16251,16253],{"class":534,"line":605},[532,16243,16244],{"class":1756},"      schema",[532,16246,954],{"class":549},[532,16248,550],{"class":549},[532,16250,2418],{"class":553},[532,16252,557],{"class":549},[532,16254,1388],{"class":549},[532,16256,16257,16260,16262,16264,16266,16268],{"class":534,"line":619},[532,16258,16259],{"class":1756},"      table",[532,16261,954],{"class":549},[532,16263,550],{"class":549},[532,16265,1683],{"class":553},[532,16267,557],{"class":549},[532,16269,1388],{"class":549},[532,16271,16272,16275,16277,16280,16283,16285,16287,16289,16291],{"class":534,"line":630},[532,16273,16274],{"class":1756},"      filter",[532,16276,954],{"class":549},[532,16278,16279],{"class":549}," `",[532,16281,16282],{"class":553},"user_id=eq.",[532,16284,11397],{"class":549},[532,16286,16120],{"class":560},[532,16288,448],{"class":549},[532,16290,1978],{"class":560},[532,16292,16293],{"class":549},"}`\n",[532,16295,16296],{"class":534,"line":635},[532,16297,16298],{"class":549},"    },\n",[532,16300,16301,16303,16305,16307,16309],{"class":534,"line":641},[532,16302,2443],{"class":549},[532,16304,2447],{"class":2446},[532,16306,1310],{"class":549},[532,16308,2452],{"class":1363},[532,16310,2628],{"class":549},[532,16312,16313,16316,16318,16320,16322,16324,16326,16328,16330,16332,16334],{"class":534,"line":661},[532,16314,16315],{"class":1335},"      if",[532,16317,10916],{"class":1756},[532,16319,2447],{"class":560},[532,16321,448],{"class":549},[532,16323,9727],{"class":560},[532,16325,10941],{"class":549},[532,16327,550],{"class":549},[532,16329,2404],{"class":553},[532,16331,557],{"class":549},[532,16333,1768],{"class":1756},[532,16335,2288],{"class":549},[532,16337,16338,16341,16343,16345,16347,16349,16351,16353,16355,16357,16360,16362,16364,16366],{"class":534,"line":674},[532,16339,16340],{"class":560},"        posts",[532,16342,448],{"class":549},[532,16344,7857],{"class":560},[532,16346,1662],{"class":549},[532,16348,2979],{"class":1756},[532,16350,2447],{"class":560},[532,16352,448],{"class":549},[532,16354,9758],{"class":560},[532,16356,1653],{"class":549},[532,16358,16359],{"class":549}," ...",[532,16361,1683],{"class":560},[532,16363,448],{"class":549},[532,16365,7857],{"class":560},[532,16367,14804],{"class":1756},[532,16369,16370],{"class":534,"line":688},[532,16371,12097],{"class":549},[532,16373,16374,16376,16378,16380,16382,16384,16386,16388,16391,16393,16395],{"class":534,"line":702},[532,16375,16315],{"class":1335},[532,16377,10916],{"class":1756},[532,16379,2447],{"class":560},[532,16381,448],{"class":549},[532,16383,9727],{"class":560},[532,16385,10941],{"class":549},[532,16387,550],{"class":549},[532,16389,16390],{"class":553},"DELETE",[532,16392,557],{"class":549},[532,16394,1768],{"class":1756},[532,16396,2288],{"class":549},[532,16398,16399,16401,16403,16405,16407,16410,16412,16414,16416,16418,16420,16422,16424,16427,16429,16431,16434,16436,16438,16440,16442,16444],{"class":534,"line":715},[532,16400,16340],{"class":560},[532,16402,448],{"class":549},[532,16404,7857],{"class":560},[532,16406,1662],{"class":549},[532,16408,16409],{"class":560}," posts",[532,16411,448],{"class":549},[532,16413,7857],{"class":560},[532,16415,448],{"class":549},[532,16417,3686],{"class":1372},[532,16419,1197],{"class":1756},[532,16421,432],{"class":2446},[532,16423,2452],{"class":1363},[532,16425,16426],{"class":560}," p",[532,16428,448],{"class":549},[532,16430,1978],{"class":560},[532,16432,16433],{"class":549}," !==",[532,16435,2474],{"class":560},[532,16437,448],{"class":549},[532,16439,9790],{"class":560},[532,16441,448],{"class":549},[532,16443,1978],{"class":560},[532,16445,1203],{"class":1756},[532,16447,16448],{"class":534,"line":720},[532,16449,12097],{"class":549},[532,16451,16452],{"class":534,"line":726},[532,16453,11641],{"class":549},[532,16455,16456],{"class":534,"line":745},[532,16457,2485],{"class":560},[532,16459,16460,16462,16464],{"class":534,"line":758},[532,16461,1673],{"class":549},[532,16463,2493],{"class":1372},[532,16465,1996],{"class":560},[1301,16467],{},[427,16469,16471],{"id":16470},"các-sdk-khác","Các SDK khác",[842,16473,16474,16486],{},[845,16475,16476],{},[848,16477,16478,16481,16484],{},[851,16479,16480],{},"Ngôn ngữ",[851,16482,16483],{},"Package",[851,16485,12312],{},[861,16487,16488,16505,16521,16538,16552],{},[848,16489,16490,16495,16500],{},[866,16491,16492],{},[436,16493,16494],{},"Flutter\u002FDart",[866,16496,16497],{},[445,16498,16499],{},"supabase_flutter",[866,16501,16502],{},[445,16503,16504],{},"flutter pub add supabase_flutter",[848,16506,16507,16512,16516],{},[866,16508,16509],{},[436,16510,16511],{},"Python",[866,16513,16514],{},[445,16515,11280],{},[866,16517,16518],{},[445,16519,16520],{},"pip install supabase",[848,16522,16523,16528,16533],{},[866,16524,16525],{},[436,16526,16527],{},"C#",[866,16529,16530],{},[445,16531,16532],{},"Supabase",[866,16534,16535],{},[445,16536,16537],{},"dotnet add package Supabase",[848,16539,16540,16545,16549],{},[866,16541,16542],{},[436,16543,16544],{},"Swift",[866,16546,16547],{},[445,16548,16532],{},[866,16550,16551],{},"Swift Package Manager",[848,16553,16554,16559,16564],{},[866,16555,16556],{},[436,16557,16558],{},"Kotlin",[866,16560,16561],{},[445,16562,16563],{},"supabase-kt",[866,16565,16566],{},"Maven Central",[523,16568,16570],{"className":15711,"code":16569,"language":15713,"meta":528,"style":528},"\u002F\u002F Flutter\nimport 'package:supabase_flutter\u002Fsupabase_flutter.dart';\nawait Supabase.initialize(url: '...', anonKey: '...');\nfinal data = await Supabase.instance.client.from('posts').select();\n",[445,16571,16572,16577,16581,16586],{"__ignoreMap":528},[532,16573,16574],{"class":534,"line":535},[532,16575,16576],{},"\u002F\u002F Flutter\n",[532,16578,16579],{"class":534,"line":542},[532,16580,15720],{},[532,16582,16583],{"class":534,"line":564},[532,16584,16585],{},"await Supabase.initialize(url: '...', anonKey: '...');\n",[532,16587,16588],{"class":534,"line":579},[532,16589,16590],{},"final data = await Supabase.instance.client.from('posts').select();\n",[523,16592,16596],{"className":16593,"code":16594,"language":16595,"meta":528,"style":528},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Python\nfrom supabase import create_client\nsupabase = create_client('https:\u002F\u002F[REF].supabase.co', 'anon-key')\ndata = supabase.table('posts').select('*').execute()\n","python",[445,16597,16598,16603,16608,16613],{"__ignoreMap":528},[532,16599,16600],{"class":534,"line":535},[532,16601,16602],{},"# Python\n",[532,16604,16605],{"class":534,"line":542},[532,16606,16607],{},"from supabase import create_client\n",[532,16609,16610],{"class":534,"line":564},[532,16611,16612],{},"supabase = create_client('https:\u002F\u002F[REF].supabase.co', 'anon-key')\n",[532,16614,16615],{"class":534,"line":579},[532,16616,16617],{},"data = supabase.table('posts').select('*').execute()\n",[1301,16619],{},[427,16621,16623],{"id":16622},"management-api","Management API",[523,16625,16627],{"className":525,"code":16626,"language":527,"meta":528,"style":528},"GET    https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Fprojects          # Liệt kê projects\nPOST   https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Fprojects          # Tạo project mới\nDELETE https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Fprojects\u002F{ref}    # Xóa project\n\nGET    https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Forganizations     # Liệt kê organizations\nPOST   https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Forganizations     # Tạo organization\n",[445,16628,16629,16640,16651,16661,16665,16675],{"__ignoreMap":528},[532,16630,16631,16634,16637],{"class":534,"line":535},[532,16632,16633],{"class":545},"GET",[532,16635,16636],{"class":553},"    https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Fprojects",[532,16638,16639],{"class":538},"          # Liệt kê projects\n",[532,16641,16642,16645,16648],{"class":534,"line":542},[532,16643,16644],{"class":545},"POST",[532,16646,16647],{"class":553},"   https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Fprojects",[532,16649,16650],{"class":538},"          # Tạo project mới\n",[532,16652,16653,16655,16658],{"class":534,"line":564},[532,16654,16390],{"class":545},[532,16656,16657],{"class":553}," https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Fprojects\u002F{ref}",[532,16659,16660],{"class":538},"    # Xóa project\n",[532,16662,16663],{"class":534,"line":579},[532,16664,596],{"emptyLinePlaceholder":595},[532,16666,16667,16669,16672],{"class":534,"line":592},[532,16668,16633],{"class":545},[532,16670,16671],{"class":553},"    https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Forganizations",[532,16673,16674],{"class":538},"     # Liệt kê organizations\n",[532,16676,16677,16679,16682],{"class":534,"line":599},[532,16678,16644],{"class":545},[532,16680,16681],{"class":553},"   https:\u002F\u002Fapi.supabase.com\u002Fv1\u002Forganizations",[532,16683,16684],{"class":538},"     # Tạo organization\n",[1301,16686],{},[427,16688,16690],{"id":16689},"bài-tập-thực-hành","Bài tập thực hành",[16692,16693,16694,16774],"field-group",{},[16695,16696,16698,16701,16763,16766],"field",{"name":16697},"Bài tập 1: Build Blog API với filters",[432,16699,16700],{},"Xây dựng một blog API sử dụng Supabase REST API, đáp ứng các yêu cầu:",[455,16702,16703,16712,16718,16728,16736,16744,16754],{},[458,16704,16705,16706,10916,16709,1310],{},"Chỉ hiển thị ",[436,16707,16708],{},"bài đã publish",[445,16710,16711],{},"status = 'published'",[458,16713,16714,16717],{},[436,16715,16716],{},"Sắp xếp"," theo ngày tạo giảm dần (mới nhất trước)",[458,16719,16720,16723,16724,1320,16726],{},[436,16721,16722],{},"Phân trang",": mỗi trang 10 bài, hỗ trợ chuyển trang qua ",[445,16725,903],{},[445,16727,918],{},[458,16729,16730,16733,16734,1310],{},[436,16731,16732],{},"Tìm kiếm"," bài viết theo title (dùng ",[445,16735,1082],{},[458,16737,16738,16741,16742,1310],{},[436,16739,16740],{},"Lọc theo category"," (dùng ",[445,16743,1112],{},[458,16745,16746,16749,16750,16753],{},[436,16747,16748],{},"Join"," với bảng ",[445,16751,16752],{},"authors"," để hiển thị tên và avatar tác giả",[458,16755,16756,16757,1320,16760],{},"Triển khai cả bằng ",[436,16758,16759],{},"REST API trực tiếp",[436,16761,16762],{},"JavaScript SDK",[432,16764,16765],{},"Mẫu query REST:",[523,16767,16772],{"className":16768,"code":16770,"language":16771},[16769],"language-text","\u002Frest\u002Fv1\u002Fposts?select=id,title,created_at,author:author_id(name,avatar)&status=eq.published&order=created_at.desc&limit=10&offset=0\n","text",[445,16773,16770],{"__ignoreMap":528},[16695,16775,16777,16780,16821,16824],{"name":16776},"Bài tập 2: Type-safe queries với generated types",[432,16778,16779],{},"Trong một dự án Nuxt 3:",[455,16781,16782,16785,16792,16798,16807,16814],{},[458,16783,16784],{},"Setup Supabase + generate TypeScript types từ remote database",[458,16786,16787,16788,16791],{},"Tạo một ",[436,16789,16790],{},"PostList"," component hiển thị danh sách bài viết với type-safe queries",[458,16793,16787,16794,16797],{},[436,16795,16796],{},"PostForm"," component cho phép tạo bài mới, validate form với TypeScript types",[458,16799,16800,16801,16803,16804,1310],{},"Sử dụng ",[445,16802,15245],{}," module (hoặc tự tạo composable ",[445,16805,16806],{},"useSupabase",[458,16808,16809,16810,16813],{},"Triển khai ",[436,16811,16812],{},"real-time cập nhật"," danh sách bài viết khi có bài mới",[458,16815,16816,16817,16820],{},"Viết một ",[436,16818,16819],{},"Edge Function"," để xử lý webhook nhận comment mới từ bên thứ ba",[432,16822,16823],{},"Gợi ý cấu trúc thư mục:",[523,16825,16828],{"className":16826,"code":16827,"language":16771},[16769],"composables\u002F\n  useSupabase.ts       # Singleton client\n  usePosts.ts          # Posts CRUD composable\ntypes\u002F\n  supabase.ts          # Generated types\ncomponents\u002F\n  PostList.vue\n  PostForm.vue\nserver\u002F\n  api\u002F\n    webhooks\u002F\n      comments.post.ts # Nitro server route xử lý webhook\n",[445,16829,16827],{"__ignoreMap":528},[1301,16831],{},[16833,16834],"navigation",{":next":16835,":prev":16835,"nextIcon":282,"nextTitle":279,"nextTo":16836,"prevIcon":268,"prevTitle":16837,"prevTo":16838},"true",".\u002F6.platform-deploy","4. Edge Functions",".\u002F4.edge-functions",[16840,16841,16842],"style",{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":528,"searchDepth":542,"depth":542,"links":16844},[16845,16852,16862,16865,16884,16892,16893,16894],{"id":429,"depth":542,"text":430,"children":16846},[16847,16848,16849,16850,16851],{"id":452,"depth":564,"text":453},{"id":520,"depth":564,"text":521},{"id":836,"depth":564,"text":837},{"id":946,"depth":564,"text":947},{"id":1273,"depth":564,"text":1274},{"id":1305,"depth":542,"text":16853,"children":16854},"JavaScript\u002FTypeScript Client (@supabase\u002Fsupabase-js)",[16855,16856,16857,16858,16859,16860,16861],{"id":1404,"depth":564,"text":1405},{"id":1630,"depth":564,"text":1631},{"id":2663,"depth":564,"text":2664},{"id":4275,"depth":564,"text":4276},{"id":8084,"depth":564,"text":8085},{"id":9486,"depth":564,"text":9487},{"id":11786,"depth":564,"text":11787},{"id":12018,"depth":542,"text":12019,"children":16863},[16864],{"id":12194,"depth":564,"text":12195},{"id":12307,"depth":542,"text":12308,"children":16866},[16867,16868,16869,16870,16871,16872,16873,16874,16875,16876,16877,16878,16879,16880,16881,16882,16883],{"id":12311,"depth":564,"text":12312},{"id":12430,"depth":564,"text":12431},{"id":12590,"depth":564,"text":12591},{"id":12793,"depth":564,"text":12794},{"id":12977,"depth":564,"text":12978},{"id":13107,"depth":564,"text":13108},{"id":13366,"depth":564,"text":13367},{"id":13507,"depth":564,"text":13508},{"id":13729,"depth":564,"text":13730},{"id":13792,"depth":564,"text":13793},{"id":13912,"depth":564,"text":13913},{"id":13946,"depth":564,"text":13947},{"id":8120,"depth":564,"text":1592},{"id":14266,"depth":564,"text":14267},{"id":14306,"depth":564,"text":14307},{"id":14374,"depth":564,"text":14375},{"id":14473,"depth":564,"text":14474},{"id":14625,"depth":542,"text":14626,"children":16885},[16886,16887,16888,16889,16890,16891],{"id":14629,"depth":564,"text":14630},{"id":15259,"depth":564,"text":15260},{"id":15444,"depth":564,"text":15445},{"id":15707,"depth":564,"text":15708},{"id":15785,"depth":564,"text":15786},{"id":16167,"depth":564,"text":16168},{"id":16470,"depth":542,"text":16471},{"id":16622,"depth":542,"text":16623},{"id":16689,"depth":542,"text":16690},"Supabase API reference — REST API (PostgREST), GraphQL (pg_graphql), Client SDKs (JS, Flutter, Python, C#, Swift, Kotlin), CLI.","md",null,{},{"title":275,"icon":181},{"title":422,"description":16895},"qHOulzyRv7QOi_23HP0968BQjANUIXjkaDXE4WsDnK4",[16903,16905],{"title":270,"path":271,"stem":272,"description":16904,"icon":273,"children":-1},"Supabase Edge Functions (Deno, TypeScript, global) và AI\u002FVector (pgvector, RAG, semantic search, embeddings).",{"title":279,"path":280,"stem":281,"description":16906,"icon":282,"children":-1},"Supabase Platform — Studio, organizations, branching, logs, self-hosting Docker\u002FK8s. Migration từ Firebase, Heroku, RDS, MySQL.",1783490368769]