diff --git a/package-lock.json b/package-lock.json
index 1d179019c..09ecc0011 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4859,6 +4859,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4872,6 +4873,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4885,6 +4887,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4898,6 +4901,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4911,6 +4915,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4924,6 +4929,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4937,6 +4943,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4950,6 +4957,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4963,6 +4971,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4976,6 +4985,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4989,6 +4999,7 @@
"cpu": [
"loong64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5002,6 +5013,7 @@
"cpu": [
"loong64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5015,6 +5027,7 @@
"cpu": [
"ppc64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5028,6 +5041,7 @@
"cpu": [
"ppc64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5041,6 +5055,7 @@
"cpu": [
"riscv64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5054,6 +5069,7 @@
"cpu": [
"riscv64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5067,6 +5083,7 @@
"cpu": [
"s390x"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5080,6 +5097,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5093,6 +5111,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5106,6 +5125,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5119,6 +5139,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5132,6 +5153,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5145,6 +5167,7 @@
"cpu": [
"ia32"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5158,6 +5181,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5171,6 +5195,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -16230,6 +16255,7 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
diff --git a/package.json b/package.json
index b1726392f..2098aa94d 100644
--- a/package.json
+++ b/package.json
@@ -3,15 +3,16 @@
"version": "0.2.0",
"private": true,
"scripts": {
- "dev": "next dev",
- "build": "next build && node scripts/copy-standalone-static.js",
- "start": "next start",
- "lint": "next lint",
- "type-check": "tsc --noEmit",
- "test": "vitest run",
- "test:e2e": "playwright test",
- "supabase:generate-types": "npx supabase@latest gen types typescript --local > src/types/supabase.ts"
- },
+ "dev": "next dev",
+ "validate-env": "node scripts/validate-env.js",
+ "build": "npm run validate-env && next build && node scripts/copy-standalone-static.js",
+ "start": "next start",
+ "lint": "next lint",
+ "type-check": "tsc --noEmit",
+ "test": "vitest run",
+ "test:e2e": "playwright test",
+ "supabase:generate-types": "npx supabase@latest gen types typescript --local > src/types/supabase.ts"
+},
"dependencies": {
"@ducanh2912/next-pwa": "^10.2.9",
"@supabase/ssr": "^0.10.3",
diff --git a/scripts/validate-env.js b/scripts/validate-env.js
new file mode 100644
index 000000000..5e09938e1
--- /dev/null
+++ b/scripts/validate-env.js
@@ -0,0 +1,34 @@
+const sensitivePatterns = [
+ "private_key",
+ "secret",
+ "supabase_secret",
+ "github_token",
+ "token",
+ "password",
+ "api_key",
+ "apikey",
+];
+
+let hasErrors = false;
+
+console.log("š Validating environment variables...");
+
+for (const key of Object.keys(process.env)) {
+ const lowerKey = key.toLowerCase();
+
+ const isSensitive = sensitivePatterns.some((pattern) =>
+ lowerKey.includes(pattern)
+ );
+
+ if (isSensitive && !key.startsWith("NEXT_PUBLIC_")) {
+ console.error(`ā Sensitive environment variable detected: ${key}`);
+ hasErrors = true;
+ }
+}
+
+if (hasErrors) {
+ console.error("\nšØ Build blocked: Private credentials detected.");
+ process.exit(1);
+}
+
+console.log("ā
Environment validation passed.");
\ No newline at end of file
diff --git a/src/components/ExportButton.tsx b/src/components/ExportButton.tsx
index 7102bd92e..f4698a159 100644
--- a/src/components/ExportButton.tsx
+++ b/src/components/ExportButton.tsx
@@ -709,10 +709,17 @@ export default function ExportButton() {
aria-label="Export dashboard metrics as CSV"
className="flex w-full items-center justify-center gap-2 rounded-lg border border-[var(--border)] bg-[var(--control)] px-4 py-2 text-sm font-medium text-[var(--card-foreground)] transition-all hover:border-[var(--accent)] disabled:opacity-50 sm:w-auto sm:min-w-[140px] hover:opacity-90 active:scale-95"
>
-
- {isExportingCSV ? "Exporting..." : "Export CSV"}
+ {isExportingCSV ? (
+
+) : (
+
+)}
+{isExportingCSV ? "Exporting..." : "Export CSV"}
);