@slashgear/gdpr-cookie-scanner 3.8.1 → 3.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.github/workflows/ci.yml +17 -11
  2. package/.github/workflows/release.yml +6 -7
  3. package/.github/workflows/update-cookie-db.yml +9 -10
  4. package/.github/workflows/update-trackers.yml +8 -9
  5. package/.github/workflows/website.yml +18 -60
  6. package/CHANGELOG.md +12 -0
  7. package/CONTRIBUTING.md +1 -1
  8. package/Dockerfile +14 -16
  9. package/README.md +3 -3
  10. package/bun.lock +322 -0
  11. package/dist/cli.js +0 -0
  12. package/package.json +22 -25
  13. package/tests/analyzers/colour.test.ts +1 -1
  14. package/tests/analyzers/compliance.test.ts +1 -1
  15. package/tests/analyzers/tcf-decoder.test.ts +1 -1
  16. package/tests/analyzers/wording.test.ts +1 -1
  17. package/tests/classifiers/cookie-classifier.test.ts +1 -1
  18. package/tests/classifiers/network-classifier.test.ts +1 -1
  19. package/tests/e2e/scanner.test.ts +35 -47
  20. package/tests/scanner/button-classification.test.ts +1 -1
  21. package/tests/scanner/contrast-ratio.test.ts +1 -1
  22. package/tests/unit/compliance.test.ts +1 -1
  23. package/tests/unit/cookie-classifier.test.ts +1 -1
  24. package/tests/unit/network-classifier.test.ts +1 -1
  25. package/tests/unit/wording.test.ts +1 -1
  26. package/pnpm-workspace.yaml +0 -3
  27. package/vitest.config.ts +0 -9
  28. package/website/Dockerfile +0 -55
  29. package/website/node_modules/.bin/oxfmt +0 -21
  30. package/website/node_modules/.bin/oxlint +0 -21
  31. package/website/node_modules/.bin/tsc +0 -21
  32. package/website/node_modules/.bin/tsserver +0 -21
  33. package/website/node_modules/.bin/tsx +0 -21
  34. package/website/package.json +0 -29
  35. package/website/src/index.ts +0 -15
  36. package/website/src/security.ts +0 -26
  37. package/website/tsconfig.json +0 -14
@@ -1,14 +1,12 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
1
+ import { describe, it, expect, beforeAll, afterAll } from "bun:test";
2
2
  import { mkdtemp, rm } from "fs/promises";
3
3
  import { tmpdir } from "os";
4
4
  import { join } from "path";
5
+ import type { ScanResult } from "../../src/types.js";
5
6
  import { Scanner } from "../../src/scanner/index.js";
6
7
  import { startTestServer, type TestServer } from "../helpers/test-server.js";
7
8
 
8
- // E2E tests spin up real Playwright browsers — allow generous timeouts
9
- const E2E_TIMEOUT = 60_000;
10
-
11
- describe("Scanner E2E", { timeout: E2E_TIMEOUT }, () => {
9
+ describe("Scanner E2E", () => {
12
10
  let server: TestServer;
13
11
  let outputDir: string;
14
12
 
@@ -34,98 +32,88 @@ describe("Scanner E2E", { timeout: E2E_TIMEOUT }, () => {
34
32
  }
35
33
 
36
34
  describe("compliant-site.html", () => {
37
- it("detects the consent modal", async () => {
38
- const scanner = new Scanner(makeOptions("compliant-site.html"));
39
- const result = await scanner.run();
35
+ let result: ScanResult;
36
+
37
+ beforeAll(async () => {
38
+ result = await new Scanner(makeOptions("compliant-site.html")).run();
39
+ });
40
+
41
+ it("detects the consent modal", () => {
40
42
  expect(result.modal.detected).toBe(true);
41
43
  });
42
44
 
43
- it("finds both accept and reject buttons", async () => {
44
- const scanner = new Scanner(makeOptions("compliant-site.html"));
45
- const result = await scanner.run();
45
+ it("finds both accept and reject buttons", () => {
46
46
  const types = result.modal.buttons.map((b) => b.type);
47
47
  expect(types).toContain("accept");
48
48
  expect(types).toContain("reject");
49
49
  });
50
50
 
51
- it("finds the privacy policy link in the modal", async () => {
52
- const scanner = new Scanner(makeOptions("compliant-site.html"));
53
- const result = await scanner.run();
51
+ it("finds the privacy policy link in the modal", () => {
54
52
  expect(result.modal.privacyPolicyUrl).toBeTruthy();
55
53
  });
56
54
 
57
- it("finds a privacy policy link on the page", async () => {
58
- const scanner = new Scanner(makeOptions("compliant-site.html"));
59
- const result = await scanner.run();
55
+ it("finds a privacy policy link on the page", () => {
60
56
  expect(result.privacyPolicyUrl).toBeTruthy();
61
57
  });
62
58
 
63
- it("assigns a passing compliance grade (A or B)", async () => {
64
- const scanner = new Scanner(makeOptions("compliant-site.html"));
65
- const result = await scanner.run();
59
+ it("assigns a passing compliance grade (A or B)", () => {
66
60
  expect(["A", "B"]).toContain(result.compliance.grade);
67
61
  });
68
62
 
69
- it("does not flag pre-consent cookies", async () => {
70
- const scanner = new Scanner(makeOptions("compliant-site.html"));
71
- const result = await scanner.run();
63
+ it("does not flag pre-consent cookies", () => {
72
64
  const illegalPreConsent = result.cookiesBeforeInteraction.filter((c) => c.requiresConsent);
73
65
  expect(illegalPreConsent).toHaveLength(0);
74
66
  });
75
67
  });
76
68
 
77
69
  describe("non-compliant-site.html", () => {
78
- it("detects the consent modal", async () => {
79
- const scanner = new Scanner(makeOptions("non-compliant-site.html"));
80
- const result = await scanner.run();
70
+ let result: ScanResult;
71
+
72
+ beforeAll(async () => {
73
+ result = await new Scanner(makeOptions("non-compliant-site.html")).run();
74
+ });
75
+
76
+ it("detects the consent modal", () => {
81
77
  expect(result.modal.detected).toBe(true);
82
78
  });
83
79
 
84
- it("detects _ga cookie set before any interaction", async () => {
85
- const scanner = new Scanner(makeOptions("non-compliant-site.html"));
86
- const result = await scanner.run();
80
+ it("detects _ga cookie set before any interaction", () => {
87
81
  const gaBeforeInteraction = result.cookiesBeforeInteraction.some(
88
82
  (c) => c.name === "_ga" && c.requiresConsent,
89
83
  );
90
84
  expect(gaBeforeInteraction).toBe(true);
91
85
  });
92
86
 
93
- it("raises an auto-consent issue for pre-interaction cookies", async () => {
94
- const scanner = new Scanner(makeOptions("non-compliant-site.html"));
95
- const result = await scanner.run();
87
+ it("raises an auto-consent issue for pre-interaction cookies", () => {
96
88
  const issue = result.compliance.issues.find((i) => i.type === "auto-consent");
97
89
  expect(issue).toBeDefined();
98
90
  });
99
91
 
100
- it("assigns a failing grade (C, D, or F)", async () => {
101
- const scanner = new Scanner(makeOptions("non-compliant-site.html"));
102
- const result = await scanner.run();
92
+ it("assigns a failing grade (C, D, or F)", () => {
103
93
  expect(["C", "D", "F"]).toContain(result.compliance.grade);
104
94
  });
105
95
  });
106
96
 
107
97
  describe("no-modal-site.html", () => {
108
- it("reports modal as not detected", async () => {
109
- const scanner = new Scanner(makeOptions("no-modal-site.html"));
110
- const result = await scanner.run();
98
+ let result: ScanResult;
99
+
100
+ beforeAll(async () => {
101
+ result = await new Scanner(makeOptions("no-modal-site.html")).run();
102
+ });
103
+
104
+ it("reports modal as not detected", () => {
111
105
  expect(result.modal.detected).toBe(false);
112
106
  });
113
107
 
114
- it("still finds the page-level privacy policy link", async () => {
115
- const scanner = new Scanner(makeOptions("no-modal-site.html"));
116
- const result = await scanner.run();
108
+ it("still finds the page-level privacy policy link", () => {
117
109
  expect(result.privacyPolicyUrl).toBeTruthy();
118
110
  });
119
111
 
120
- it("assigns grade A — no consent mechanism needed for a tracking-free site", async () => {
121
- const scanner = new Scanner(makeOptions("no-modal-site.html"));
122
- const result = await scanner.run();
112
+ it("assigns grade A — no consent mechanism needed for a tracking-free site", () => {
123
113
  expect(result.compliance.grade).toBe("A");
124
114
  });
125
115
 
126
- it("raises no compliance issues for a tracking-free site without a modal", async () => {
127
- const scanner = new Scanner(makeOptions("no-modal-site.html"));
128
- const result = await scanner.run();
116
+ it("raises no compliance issues for a tracking-free site without a modal", () => {
129
117
  expect(result.compliance.issues).toHaveLength(0);
130
118
  });
131
119
  });
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect } from "bun:test";
2
2
  import { classifyButtonText } from "../../src/scanner/consent-modal.js";
3
3
 
4
4
  // ── English ───────────────────────────────────────────────────────────────────
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect } from "bun:test";
2
2
  import {
3
3
  computeContrastRatio,
4
4
  parseRgb,
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect } from "bun:test";
2
2
  import { analyzeCompliance } from "../../src/analyzers/compliance.js";
3
3
  import type {
4
4
  ConsentModal,
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect } from "bun:test";
2
2
  import { classifyCookie } from "../../src/classifiers/cookie-classifier.js";
3
3
 
4
4
  describe("classifyCookie", () => {
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect } from "bun:test";
2
2
  import { classifyNetworkRequest } from "../../src/classifiers/network-classifier.js";
3
3
 
4
4
  describe("classifyNetworkRequest", () => {
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect } from "bun:test";
2
2
  import { analyzeButtonWording, analyzeModalText } from "../../src/analyzers/wording.js";
3
3
  import type { ConsentButton } from "../../src/types.js";
4
4
 
@@ -1,3 +0,0 @@
1
- packages:
2
- - "."
3
- - website
package/vitest.config.ts DELETED
@@ -1,9 +0,0 @@
1
- import { defineConfig } from "vitest/config";
2
-
3
- export default defineConfig({
4
- test: {
5
- environment: "node",
6
- include: ["tests/**/*.test.ts"],
7
- globals: false,
8
- },
9
- });
@@ -1,55 +0,0 @@
1
- # Build context: repo root (docker build -f website/Dockerfile .)
2
-
3
- # ── Stage 1: build ────────────────────────────────────────────────────────────
4
- FROM node:24-slim AS builder
5
- WORKDIR /app
6
-
7
- # Install compression tools (brotli, zstd, zopfli)
8
- RUN apt-get update && apt-get install -y --no-install-recommends brotli zstd zopfli \
9
- && rm -rf /var/lib/apt/lists/*
10
-
11
- RUN npm install -g pnpm@latest
12
-
13
- # Copy workspace manifests for layer caching
14
- COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
15
- COPY website/package.json ./website/
16
-
17
- # Install website deps only (no playwright, no CLI deps)
18
- RUN pnpm install --frozen-lockfile --filter @slashgear/gdpr-website
19
-
20
- # Copy source and compile
21
- COPY website/tsconfig.json ./website/
22
- COPY website/src ./website/src
23
- RUN pnpm --filter @slashgear/gdpr-website build
24
-
25
- # Copy static assets and precompress them
26
- COPY website/public ./website/public
27
- RUN find /app/website/public -type f \( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.json" -o -name "*.svg" \) | \
28
- while read f; do \
29
- brotli --best -k "$f"; \
30
- zstd --ultra -22 -k "$f"; \
31
- zopfli --gzip "$f"; \
32
- done
33
-
34
- # ── Stage 2: runtime ──────────────────────────────────────────────────────────
35
- FROM node:24-slim
36
- WORKDIR /app
37
- ENV NODE_ENV=production
38
-
39
- RUN npm install -g pnpm@latest
40
-
41
- COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
42
- COPY website/package.json ./website/
43
- RUN pnpm install --prod --frozen-lockfile --filter @slashgear/gdpr-website
44
-
45
- # Static assets with precompressed variants (.br, .zst, .gz)
46
- COPY --from=builder /app/website/public ./website/public
47
-
48
- # Compiled server
49
- COPY --from=builder /app/website/dist ./website/dist
50
-
51
- WORKDIR /app/website
52
- ENV PORT=8080
53
- EXPOSE 8080
54
-
55
- CMD ["node", "dist/index.js"]
@@ -1,21 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules/oxfmt/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules/oxfmt/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxfmt@0.34.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../oxfmt/bin/oxfmt" "$@"
19
- else
20
- exec node "$basedir/../oxfmt/bin/oxfmt" "$@"
21
- fi
@@ -1,21 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules/oxlint/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules/oxlint/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/oxlint@1.49.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../oxlint/bin/oxlint" "$@"
19
- else
20
- exec node "$basedir/../oxlint/bin/oxlint" "$@"
21
- fi
@@ -1,21 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
19
- else
20
- exec node "$basedir/../typescript/bin/tsc" "$@"
21
- fi
@@ -1,21 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
19
- else
20
- exec node "$basedir/../typescript/bin/tsserver" "$@"
21
- fi
@@ -1,21 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/runner/work/gdpr-cookie-scanner/gdpr-cookie-scanner/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../tsx/dist/cli.mjs" "$@"
19
- else
20
- exec node "$basedir/../tsx/dist/cli.mjs" "$@"
21
- fi
@@ -1,29 +0,0 @@
1
- {
2
- "name": "@slashgear/gdpr-website",
3
- "version": "0.1.0",
4
- "private": true,
5
- "description": "Web interface for gdpr-cookie-scanner",
6
- "type": "module",
7
- "scripts": {
8
- "build": "tsc",
9
- "dev": "tsx src/index.ts",
10
- "start": "node dist/index.js",
11
- "typecheck": "tsc --noEmit",
12
- "lint": "oxlint .",
13
- "format": "oxfmt ."
14
- },
15
- "dependencies": {
16
- "@hono/node-server": "^1.14.0",
17
- "hono": "^4.7.0"
18
- },
19
- "devDependencies": {
20
- "@types/node": "^22.0.0",
21
- "oxfmt": "^0.34.0",
22
- "oxlint": "^1.48.0",
23
- "tsx": "^4.19.0",
24
- "typescript": "^5.5.0"
25
- },
26
- "engines": {
27
- "node": ">=24.0.0"
28
- }
29
- }
@@ -1,15 +0,0 @@
1
- import { serve } from "@hono/node-server";
2
- import { serveStatic } from "@hono/node-server/serve-static";
3
- import { Hono } from "hono";
4
- import { securityHeaders } from "./security.js";
5
-
6
- const app = new Hono();
7
-
8
- app.use("/*", securityHeaders);
9
- app.use("/*", serveStatic({ root: "./public", precompressed: true }));
10
-
11
- const port = Number(process.env.PORT) || 8080;
12
-
13
- serve({ fetch: app.fetch, port }, (info) => {
14
- console.log(`Server running on http://localhost:${info.port}`);
15
- });
@@ -1,26 +0,0 @@
1
- import type { MiddlewareHandler } from "hono";
2
-
3
- const CSP = [
4
- "default-src 'self'",
5
- "script-src 'self'",
6
- "style-src 'self' 'unsafe-inline'",
7
- "img-src 'self' data: https:",
8
- "font-src 'self'",
9
- "connect-src 'self'",
10
- "frame-ancestors 'none'",
11
- "base-uri 'self'",
12
- "form-action 'self'",
13
- "upgrade-insecure-requests",
14
- ].join("; ");
15
-
16
- export const securityHeaders: MiddlewareHandler = async (c, next) => {
17
- await next();
18
- c.header("X-Frame-Options", "DENY");
19
- c.header("X-Content-Type-Options", "nosniff");
20
- c.header("X-XSS-Protection", "1; mode=block");
21
- c.header("Referrer-Policy", "strict-origin-when-cross-origin");
22
- c.header("Permissions-Policy", "geolocation=(), microphone=(), camera=()");
23
- if (process.env.NODE_ENV === "production") {
24
- c.header("Content-Security-Policy", CSP);
25
- }
26
- };
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "outDir": "dist",
7
- "rootDir": "src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true
11
- },
12
- "include": ["src/**/*"],
13
- "exclude": ["node_modules", "dist"]
14
- }