diff --git a/App.tsx b/App.tsx index c446e6c3..e078e670 100644 --- a/App.tsx +++ b/App.tsx @@ -200,13 +200,10 @@ function App() { } }; - supabase.auth.getSession().then(({ data: { session } }) => { - fetchRealUserSessionData(session); - }); - // Add a separate listener for specific auth events to provide user feedback. const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => { logger.info(`Supabase auth event: ${event}`); + // This single listener now handles all auth events, including the initial session. if (event === "SIGNED_OUT") { setIsProfileManagerOpen(false); } diff --git a/package-lock.json b/package-lock.json index c69aa517..5e538d78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "@supabase/supabase-js": "^2.78.0", "react": "^19.2.0", "react-dom": "^19.2.0", - "recharts": "^3.3.0" + "recharts": "^3.3.0", + "supabase": "^2.54.11" }, "devDependencies": { "@types/node": "^22.14.0", @@ -799,6 +800,18 @@ "node": ">=12" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1652,6 +1665,22 @@ "node": "*" } }, + "node_modules/bin-links": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-6.0.0.tgz", + "integrity": "sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w==", + "license": "ISC", + "dependencies": { + "cmd-shim": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "proc-log": "^6.0.0", + "read-cmd-shim": "^6.0.0", + "write-file-atomic": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -1796,6 +1825,15 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -1805,6 +1843,15 @@ "node": ">=6" } }, + "node_modules/cmd-shim": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-8.0.0.tgz", + "integrity": "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2445,6 +2492,15 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -2710,6 +2766,18 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2812,6 +2880,15 @@ "node": ">=0.10.0" } }, + "node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", + "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3079,6 +3156,15 @@ "dev": true, "license": "MIT" }, + "node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3171,6 +3257,15 @@ "pify": "^2.3.0" } }, + "node_modules/read-cmd-shim": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-6.0.0.tgz", + "integrity": "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -3559,6 +3654,25 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/supabase": { + "version": "2.54.11", + "resolved": "https://registry.npmjs.org/supabase/-/supabase-2.54.11.tgz", + "integrity": "sha512-KuDDVi1s2fhfun81LNPaCLpW4/LFsP3G2LKUQimzEoj64sP1DtZ/d97uw6GFYbNMPW9JC2Ruuei53qHInOwJLA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bin-links": "^6.0.0", + "https-proxy-agent": "^7.0.2", + "node-fetch": "^3.3.2", + "tar": "7.5.1" + }, + "bin": { + "supabase": "bin/supabase" + }, + "engines": { + "npm": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -3610,6 +3724,31 @@ "node": ">=14.0.0" } }, + "node_modules/tar": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", + "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -3961,6 +4100,19 @@ "node": ">=8" } }, + "node_modules/write-file-atomic": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.0.tgz", + "integrity": "sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", diff --git a/package.json b/package.json index 10eacda0..68f8044d 100644 --- a/package.json +++ b/package.json @@ -9,19 +9,20 @@ "preview": "vite preview" }, "dependencies": { + "@google/genai": "^1.28.0", + "@supabase/supabase-js": "^2.78.0", "react": "^19.2.0", "react-dom": "^19.2.0", - "@google/genai": "^1.28.0", "recharts": "^3.3.0", - "@supabase/supabase-js": "^2.78.0" + "supabase": "^2.54.11" }, "devDependencies": { "@types/node": "^22.14.0", "@vitejs/plugin-react": "^5.0.0", - "typescript": "~5.8.2", - "vite": "^6.2.0", - "tailwindcss": "^3.4.10", + "autoprefixer": "^10.4.19", "postcss": "^8.4.40", - "autoprefixer": "^10.4.19" + "tailwindcss": "^3.4.10", + "typescript": "~5.8.2", + "vite": "^6.2.0" } } diff --git a/supabase/.vscode/settings.json b/supabase/.vscode/settings.json new file mode 100644 index 00000000..1535e139 --- /dev/null +++ b/supabase/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "deno.enable": true, + "deno.lint": true, + "deno.unstable": true +} \ No newline at end of file diff --git a/supabase/config.toml b/supabase/config.toml new file mode 100644 index 00000000..77261918 --- /dev/null +++ b/supabase/config.toml @@ -0,0 +1,14 @@ +project_id = "azmmnxkvjryracrnmhvj" + +[functions.delete-user] +# Point to the single import map in the supabase/ directory +import_map = "import_map.json" +entrypoint = "./functions/delete-user/index.ts" + +[functions.seed-database] +import_map = "import_map.json" +entrypoint = "./functions/seed-database/index.ts" + +[functions.system-check] +import_map = "import_map.json" +entrypoint = "./functions/system-check/index.ts" \ No newline at end of file diff --git a/supabase/deno.json b/supabase/deno.json new file mode 100644 index 00000000..ecc5a2b3 --- /dev/null +++ b/supabase/deno.json @@ -0,0 +1,11 @@ +{ + "importMap": "./import_map.json", + "compilerOptions": { + "lib": ["deno.ns", "dom"] + }, + "lint": { + "rules": { + "exclude": ["no-explicit-any"] + } + } +} \ No newline at end of file diff --git a/supabase/deno.lock b/supabase/deno.lock new file mode 100644 index 00000000..ca928e85 --- /dev/null +++ b/supabase/deno.lock @@ -0,0 +1,30 @@ +{ + "version": "5", + "specifiers": { + "npm:@types/node@*": "24.2.0" + }, + "npm": { + "@types/node@24.2.0": { + "integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==", + "dependencies": [ + "undici-types" + ] + }, + "undici-types@7.10.0": { + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==" + } + }, + "redirects": { + "https://esm.sh/@supabase/supabase-js@2": "https://esm.sh/@supabase/supabase-js@2.81.0" + }, + "remote": { + "https://esm.sh/@supabase/auth-js@2.81.0/denonext/auth-js.mjs": "b5fd37fcb23c29d8aced42fa5860351b2c3cdf6c93f682f5ad18eae9a5ec975f", + "https://esm.sh/@supabase/functions-js@2.81.0/denonext/functions-js.mjs": "9d372092ef779df5229d5dfdb99418b18a3ca13aa2c75bdfc2bb800152e63209", + "https://esm.sh/@supabase/postgrest-js@2.81.0/denonext/postgrest-js.mjs": "06f7dfb7d7a12928ca6b032ff85c08da7e615bde3d6ce8296a15f6e5275b9c67", + "https://esm.sh/@supabase/realtime-js@2.81.0/denonext/realtime-js.mjs": "9dd5143d77cf76c29eeaba47d275ba175b1757d95de746c6ac47dcc9cc20dc35", + "https://esm.sh/@supabase/storage-js@2.81.0/denonext/storage-js.mjs": "a1fd4ba5177e3929f8ef2d0e3a67925bc2a8fe3a44842c86ed272fe8ab4d32ac", + "https://esm.sh/@supabase/supabase-js@2.81.0": "3770fbb84be9073d4e9961daf72e0b750d9af22be7798386a487e653ab8ce0b5", + "https://esm.sh/@supabase/supabase-js@2.81.0/denonext/supabase-js.mjs": "14d334ff59edbb57f86e22c7b63ffe9b0ba16987884b7cbcd028d460714a57fc", + "https://esm.sh/tslib@2.8.1/denonext/tslib.mjs": "ebce3cd5facb654623020337f867b426ba95f71596ba87acc9e6c6f4e55905ca" + } +} diff --git a/supabase/functions/_shared/config.toml b/supabase/functions/_shared/config.toml deleted file mode 100644 index 027ee244..00000000 --- a/supabase/functions/_shared/config.toml +++ /dev/null @@ -1,33 +0,0 @@ - -[functions.delete-user] -enabled = true -verify_jwt = true -import_map = "./functions/delete-user/deno.json" -# Uncomment to specify a custom file path to the entrypoint. -# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx -entrypoint = "./functions/delete-user/index.ts" -# Specifies static files to be bundled with the function. Supports glob patterns. -# For example, if you want to serve static HTML pages in your function: -# static_files = [ "./functions/delete-user/*.html" ] - -[functions.seed-database] -enabled = true -verify_jwt = true -import_map = "./functions/seed-database/deno.json" -# Uncomment to specify a custom file path to the entrypoint. -# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx -entrypoint = "./functions/seed-database/index.ts" -# Specifies static files to be bundled with the function. Supports glob patterns. -# For example, if you want to serve static HTML pages in your function: -# static_files = [ "./functions/seed-database/*.html" ] - -[functions.system-check] -enabled = true -verify_jwt = true -import_map = "./functions/system-check/deno.json" -# Uncomment to specify a custom file path to the entrypoint. -# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx -entrypoint = "./functions/system-check/index.ts" -# Specifies static files to be bundled with the function. Supports glob patterns. -# For example, if you want to serve static HTML pages in your function: -# static_files = [ "./functions/system-check/*.html" ] diff --git a/supabase/functions/delete-user/.npmrc b/supabase/functions/delete-user/.npmrc deleted file mode 100644 index 48c63886..00000000 --- a/supabase/functions/delete-user/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -# Configuration for private npm package dependencies -# For more information on using private registries with Edge Functions, see: -# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries diff --git a/supabase/functions/delete-user/deno.json b/supabase/functions/delete-user/deno.json deleted file mode 100644 index f6ca8454..00000000 --- a/supabase/functions/delete-user/deno.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "imports": {} -} diff --git a/supabase/functions/delete-user/index.ts b/supabase/functions/delete-user/index.ts index da7bfd5f..248cd31e 100644 --- a/supabase/functions/delete-user/index.ts +++ b/supabase/functions/delete-user/index.ts @@ -1,10 +1,3 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -// Setup type definitions for built-in Supabase Runtime APIs -//import "jsr:@supabase/functions-js/edge-runtime.d.ts" - //console.log("Hello from Functions!") //Deno.serve(async (req) => { @@ -30,22 +23,26 @@ --data '{"name":"Functions"}' */ -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; -import { corsHeaders } from '../_shared/.temp/functions/_shared/cors.ts'; +import { createClient } from '@supabase/supabase-js' +import { corsHeaders } from '../_shared/cors.ts'; -Deno.serve(async (req) => { +Deno.serve(async (req: Request) => { // Handle preflight OPTIONS request for CORS if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }); } try { + console.log("delete-user function invoked."); + const { password } = await req.json(); if (!password) { + console.error("Function called without a password in the body."); throw new Error('Password is required.'); } // Create a Supabase client with the user's authentication token + console.log("Checking for Authorization header..."); const authHeader = req.headers.get('Authorization'); if (!authHeader) { throw new Error('Missing authorization header.'); @@ -58,13 +55,16 @@ Deno.serve(async (req) => { ); // Get the user from the token + console.log("Attempting to get user from provided token..."); const { data: { user }, error: userError } = await userSupabaseClient.auth.getUser(); if (userError || !user) { + console.error("Could not get user from token.", { error: userError?.message }); return new Response(JSON.stringify({ error: userError?.message || 'User not authenticated.' }), { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, }); } + console.log(`User identified: ${user.id}. Verifying password...`); // Verify the user's password by attempting to sign in const { error: signInError } = await userSupabaseClient.auth.signInWithPassword({ @@ -73,12 +73,14 @@ Deno.serve(async (req) => { }); if (signInError) { + console.error(`Password verification failed for user ${user.id}.`, { error: signInError.message }); return new Response(JSON.stringify({ error: 'Invalid password.' }), { status: 403, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, }); } + console.log(`Password verified for user ${user.id}. Proceeding with account deletion.`); // If password is correct, create an admin client with the service_role key const adminSupabaseClient = createClient( Deno.env.get('SUPABASE_URL')!, @@ -89,15 +91,20 @@ Deno.serve(async (req) => { // Delete the user const { error: deleteError } = await adminSupabaseClient.auth.admin.deleteUser(user.id); if (deleteError) { + console.error(`Admin client failed to delete user ${user.id}.`, { error: deleteError.message }); throw deleteError; } + console.log(`Successfully deleted user ${user.id}.`); return new Response(JSON.stringify({ message: 'User deleted successfully.' }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 200, }); - } catch (error) { + } catch (e) { + // This is the most important part: log the full error and stack trace. + const error = e instanceof Error ? e : new Error(String(e)); + console.error("An unexpected error occurred in delete-user function:", { error: error.message, stack: error.stack }); // Return a detailed error with a stack trace for better debugging. return new Response(JSON.stringify({ error: error.message, stack: error.stack }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, diff --git a/supabase/functions/globals.d.ts b/supabase/functions/globals.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/supabase/functions/seed-database/.npmrc b/supabase/functions/seed-database/.npmrc deleted file mode 100644 index 48c63886..00000000 --- a/supabase/functions/seed-database/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -# Configuration for private npm package dependencies -# For more information on using private registries with Edge Functions, see: -# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries diff --git a/supabase/functions/seed-database/deno.json b/supabase/functions/seed-database/deno.json deleted file mode 100644 index f6ca8454..00000000 --- a/supabase/functions/seed-database/deno.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "imports": {} -} diff --git a/supabase/functions/seed-database/index.ts b/supabase/functions/seed-database/index.ts index 233c25ab..09bf9a43 100644 --- a/supabase/functions/seed-database/index.ts +++ b/supabase/functions/seed-database/index.ts @@ -1,10 +1,3 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -// Setup type definitions for built-in Supabase Runtime APIs -//import "jsr:@supabase/functions-js/edge-runtime.d.ts" - //console.log("Hello from Functions!") //Deno.serve(async (req) => { @@ -30,11 +23,10 @@ --data '{"name":"Functions"}' */ +import { createClient, type User } from '@supabase/supabase-js' +import { corsHeaders } from '../_shared/cors.ts'; -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; -import { corsHeaders } from '../_shared/.temp/functions/_shared/cors.ts'; - -Deno.serve(async (req) => { +Deno.serve(async (req: Request) => { if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }); } @@ -67,7 +59,7 @@ Deno.serve(async (req) => { const { data: { users: existingUserList }, error: listError } = await adminSupabaseClient.auth.admin.listUsers(); if (listError) throw listError; - const existingEmails = new Set(existingUserList.map(u => u.email)); + const existingEmails = new Set(existingUserList.map((u: User) => u.email)); for (const user of usersToSeed) { if (!existingEmails.has(user.email)) { @@ -103,8 +95,9 @@ Deno.serve(async (req) => { status: 200, }); - } catch (error) { + } catch (e) { // Return a detailed error with a stack trace for better debugging. + const error = e instanceof Error ? e : new Error(String(e)); return new Response(JSON.stringify({ error: error.message, stack: error.stack }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 500, diff --git a/supabase/functions/system-check/.npmrc b/supabase/functions/system-check/.npmrc deleted file mode 100644 index 48c63886..00000000 --- a/supabase/functions/system-check/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -# Configuration for private npm package dependencies -# For more information on using private registries with Edge Functions, see: -# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries diff --git a/supabase/functions/system-check/deno.json b/supabase/functions/system-check/deno.json deleted file mode 100644 index f6ca8454..00000000 --- a/supabase/functions/system-check/deno.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "imports": {} -} diff --git a/supabase/functions/system-check/index.ts b/supabase/functions/system-check/index.ts index bcd679c9..c1277fd4 100644 --- a/supabase/functions/system-check/index.ts +++ b/supabase/functions/system-check/index.ts @@ -1,10 +1,3 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -// Setup type definitions for built-in Supabase Runtime APIs -// import "jsr:@supabase/functions-js/edge-runtime.d.ts" - // console.log("Hello from Functions!") // Deno.serve(async (req) => { @@ -30,9 +23,8 @@ --data '{"name":"Functions"}' */ - -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; -import { corsHeaders } from '../_shared/.temp/functions/_shared/cors.ts'; +import { createClient, type SupabaseClient } from '@supabase/supabase-js' +import { corsHeaders } from '../_shared/cors.ts'; // Helper function to create a Supabase admin client const createAdminClient = () => createClient( @@ -41,7 +33,11 @@ const createAdminClient = () => createClient( { auth: { autoRefreshToken: false, persistSession: false } } ); -const checkDatabaseSchema = async (client) => { +interface SchemaCheckResult { + tables: string[]; +} + +const checkDatabaseSchema = async (client: SupabaseClient) => { const { data, error } = await client.rpc('check_schema'); if (error) throw new Error(`Schema check failed: ${error.message}`); if (!data) throw new Error('Schema check returned no data.'); @@ -54,11 +50,16 @@ const checkDatabaseSchema = async (client) => { return { pass: true, message: 'All required tables exist.' }; }; -const checkRlsPolicies = async (client) => { +interface RlsCheckResult { + table_name: string; + policy_name: string; +} + +const checkRlsPolicies = async (client: SupabaseClient) => { const { data, error } = await client.rpc('check_rls'); if (error) throw new Error(`RLS check failed: ${error.message}`); - const requiredPolicies = { + const requiredPolicies: { [key: string]: string } = { 'profiles': 'Users can update their own profile.', 'shopping_lists': 'Users can manage their own shopping lists.', 'flyer_items': `Allow anon users to manage test items` @@ -66,14 +67,14 @@ const checkRlsPolicies = async (client) => { for (const table in requiredPolicies) { const policyName = requiredPolicies[table]; - if (!data.some(p => p.table_name === table && p.policy_name === policyName)) { + if (!data.some((p: RlsCheckResult) => p.table_name === table && p.policy_name === policyName)) { return { pass: false, message: `Missing RLS policy "${policyName}" on table "${table}". Please run the schema.sql.txt script.` }; } } return { pass: true, message: 'Key RLS policies are in place.' }; }; -const checkUserCreationTrigger = async (client) => { +const checkUserCreationTrigger = async (client: SupabaseClient) => { const { data, error } = await client.rpc('check_trigger_security'); if (error) throw new Error(`Trigger check failed: ${error.message}`); @@ -91,7 +92,7 @@ const checkUserCreationTrigger = async (client) => { return { pass: true, message: 'User creation trigger is correctly configured.' }; }; -const checkStorageBucket = async (client) => { +const checkStorageBucket = async (client: SupabaseClient) => { const { data, error } = await client.storage.getBucket('flyers'); if (error) { return { pass: false, message: `Failed to access 'flyers' bucket: ${error.message}. Ensure it exists and permissions are set.` }; @@ -102,14 +103,14 @@ const checkStorageBucket = async (client) => { return { pass: true, message: "'flyers' bucket exists and is public." }; }; -Deno.serve(async (req) => { +Deno.serve(async (req: Request) => { if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }); } try { const adminClient = createAdminClient(); - const results = {}; + const results: { [key: string]: { pass: boolean; message: string } } = {}; results['schema'] = await checkDatabaseSchema(adminClient); results['rls'] = await checkRlsPolicies(adminClient); @@ -120,7 +121,8 @@ Deno.serve(async (req) => { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 200, }); - } catch (error) { + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); return new Response(JSON.stringify({ error: error.message, stack: error.stack }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 500, diff --git a/supabase/import_map.json b/supabase/import_map.json new file mode 100644 index 00000000..4d8178d6 --- /dev/null +++ b/supabase/import_map.json @@ -0,0 +1,6 @@ +{ + "imports": { + "@supabase/supabase-js": "https://esm.sh/@supabase/supabase-js@2", + "std/": "https://deno.land/std@0.224.0/" + } +} \ No newline at end of file diff --git a/supabase/tsconfig.json b/supabase/tsconfig.json new file mode 100644 index 00000000..67738ec0 --- /dev/null +++ b/supabase/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + /* Base Options */ + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "allowImportingTsExtensions": true, + "noEmit": true, // This fixes the error with 'allowImportingTsExtensions' + + /* Deno-specific settings */ + "module": "ESNext", + "moduleResolution": "bundler", + // The Deno Language Server will provide "deno.ns" automatically from deno.json. + // We can keep a basic lib for other tools. + "lib": ["ESNext", "DOM", "DOM.Iterable"] + } +} \ No newline at end of file