@slashgear/gdpr-cookie-scanner 3.7.0 → 3.8.0

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 (70) hide show
  1. package/.dockerignore +3 -0
  2. package/.gitattributes +1 -0
  3. package/.github/workflows/website.yml +80 -0
  4. package/CHANGELOG.md +8 -0
  5. package/CONTRIBUTING.md +32 -4
  6. package/package.json +7 -3
  7. package/pnpm-workspace.yaml +3 -0
  8. package/scripts/build-showcase.mjs +113 -0
  9. package/website/Dockerfile +55 -0
  10. package/website/node_modules/.bin/oxfmt +21 -0
  11. package/website/node_modules/.bin/oxlint +21 -0
  12. package/website/node_modules/.bin/tsc +21 -0
  13. package/website/node_modules/.bin/tsserver +21 -0
  14. package/website/node_modules/.bin/tsx +21 -0
  15. package/website/package.json +29 -0
  16. package/{docs → website/public}/index.html +70 -20
  17. package/website/public/reports/www.20minutes.fr/after-accept.png +3 -0
  18. package/website/public/reports/www.20minutes.fr/after-reject.png +3 -0
  19. package/{docs/reports/www.leboncoin.fr/gdpr-report-leboncoin.fr-2026-02-22.html → website/public/reports/www.20minutes.fr/gdpr-report-20minutes.fr-2026-02-22.html} +194 -51
  20. package/website/public/reports/www.20minutes.fr/modal-initial.png +3 -0
  21. package/website/public/reports/www.arte.tv/after-accept.png +3 -0
  22. package/website/public/reports/www.arte.tv/after-reject.png +3 -0
  23. package/{docs → website/public}/reports/www.arte.tv/gdpr-report-arte.tv-2026-02-24.html +1 -0
  24. package/website/public/reports/www.arte.tv/modal-initial.png +3 -0
  25. package/website/public/reports/www.backmarket.fr/after-accept.png +3 -0
  26. package/website/public/reports/www.backmarket.fr/after-reject.png +3 -0
  27. package/website/public/reports/www.backmarket.fr/gdpr-report-backmarket.fr-2026-02-24.html +1530 -0
  28. package/website/public/reports/www.backmarket.fr/modal-initial.png +3 -0
  29. package/website/public/reports/www.deezer.com/after-accept.png +3 -0
  30. package/website/public/reports/www.deezer.com/after-reject.png +3 -0
  31. package/{docs → website/public}/reports/www.deezer.com/gdpr-report-deezer.com-2026-02-22.html +1 -0
  32. package/website/public/reports/www.deezer.com/modal-initial.png +3 -0
  33. package/website/public/reports/www.france.tv/after-accept.png +3 -0
  34. package/website/public/reports/www.france.tv/after-reject.png +3 -0
  35. package/website/public/reports/www.france.tv/gdpr-report-france.tv-2026-02-23.html +977 -0
  36. package/website/public/reports/www.france.tv/modal-initial.png +3 -0
  37. package/website/public/reports/www.m6.fr/after-accept.png +3 -0
  38. package/website/public/reports/www.m6.fr/after-reject.png +3 -0
  39. package/website/public/reports/www.m6.fr/gdpr-report-m6.fr-2026-02-28.html +1862 -0
  40. package/website/public/reports/www.m6.fr/modal-initial.png +3 -0
  41. package/website/public/reports/www.netflix.com/after-accept.png +3 -0
  42. package/website/public/reports/www.netflix.com/after-reject.png +3 -0
  43. package/{docs → website/public}/reports/www.netflix.com/gdpr-report-netflix.com-2026-02-23.html +1 -0
  44. package/website/public/reports/www.netflix.com/modal-initial.png +3 -0
  45. package/website/public/reports/www.radiofrance.fr/after-accept.png +3 -0
  46. package/website/public/reports/www.radiofrance.fr/after-reject.png +3 -0
  47. package/{docs → website/public}/reports/www.radiofrance.fr/gdpr-report-radiofrance.fr-2026-02-24.html +1 -0
  48. package/website/public/reports/www.radiofrance.fr/modal-initial.png +3 -0
  49. package/website/public/reports/www.tf1.fr/after-accept.png +3 -0
  50. package/website/public/reports/www.tf1.fr/after-reject.png +3 -0
  51. package/website/public/reports/www.tf1.fr/gdpr-report-tf1.fr-2026-02-23.html +1512 -0
  52. package/website/public/reports/www.tf1.fr/modal-initial.png +3 -0
  53. package/website/src/index.ts +15 -0
  54. package/website/src/security.ts +26 -0
  55. package/website/tsconfig.json +14 -0
  56. package/.github/workflows/pages.yml +0 -40
  57. package/docs/reports/www.arte.tv/after-accept.png +0 -0
  58. package/docs/reports/www.arte.tv/after-reject.png +0 -0
  59. package/docs/reports/www.deezer.com/after-accept.png +0 -0
  60. package/docs/reports/www.deezer.com/after-reject.png +0 -0
  61. package/docs/reports/www.impots.gouv.fr/after-accept.png +0 -0
  62. package/docs/reports/www.impots.gouv.fr/after-reject.png +0 -0
  63. package/docs/reports/www.impots.gouv.fr/gdpr-report-impots.gouv.fr-2026-02-22.html +0 -751
  64. package/docs/reports/www.leboncoin.fr/after-accept.png +0 -0
  65. package/docs/reports/www.leboncoin.fr/after-reject.png +0 -0
  66. package/docs/reports/www.netflix.com/after-accept.png +0 -0
  67. package/docs/reports/www.netflix.com/after-reject.png +0 -0
  68. package/docs/reports/www.radiofrance.fr/after-accept.png +0 -0
  69. package/docs/reports/www.radiofrance.fr/after-reject.png +0 -0
  70. /package/{docs → website/public}/style.css +0 -0
package/.dockerignore CHANGED
@@ -7,6 +7,9 @@ dist/
7
7
  reports/
8
8
  gdpr-reports/
9
9
  tests/
10
+ docs/
11
+ website/node_modules/
12
+ website/dist/
10
13
  *.md
11
14
  *.log
12
15
  .DS_Store
package/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ website/public/reports/**/*.png filter=lfs diff=lfs merge=lfs -text
@@ -0,0 +1,80 @@
1
+ name: Website
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "website/**"
8
+ - "pnpm-workspace.yaml"
9
+ - ".github/workflows/website.yml"
10
+
11
+ env:
12
+ SCW_DEFAULT_REGION: fr-par
13
+
14
+ jobs:
15
+ build-and-push:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ contents: read
19
+ packages: write
20
+
21
+ outputs:
22
+ image: ${{ steps.meta.outputs.image }}
23
+
24
+ steps:
25
+ - uses: actions/checkout@v6
26
+ with:
27
+ lfs: true
28
+
29
+ - name: Log in to GitHub Container Registry
30
+ uses: docker/login-action@v3
31
+ with:
32
+ registry: ghcr.io
33
+ username: ${{ github.actor }}
34
+ password: ${{ secrets.GITHUB_TOKEN }}
35
+
36
+ - name: Set up QEMU
37
+ uses: docker/setup-qemu-action@v3
38
+
39
+ - name: Set up Docker Buildx
40
+ uses: docker/setup-buildx-action@v3
41
+
42
+ - name: Compute image name
43
+ id: meta
44
+ run: |
45
+ echo "image=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')-website" >> "$GITHUB_OUTPUT"
46
+
47
+ - name: Build and push
48
+ uses: docker/build-push-action@v6
49
+ with:
50
+ context: .
51
+ file: website/Dockerfile
52
+ push: true
53
+ platforms: linux/amd64,linux/arm64
54
+ tags: |
55
+ ${{ steps.meta.outputs.image }}:latest
56
+ ${{ steps.meta.outputs.image }}:${{ github.sha }}
57
+ cache-from: type=gha
58
+ cache-to: type=gha,mode=max
59
+
60
+ deploy:
61
+ needs: build-and-push
62
+ runs-on: ubuntu-latest
63
+ environment: production
64
+
65
+ steps:
66
+ - name: Install Scaleway CLI
67
+ run: |
68
+ curl -fsSL https://raw.githubusercontent.com/scaleway/scaleway-cli/master/scripts/get.sh | sh
69
+
70
+ - name: Deploy to Scaleway Serverless Container
71
+ run: |
72
+ scw container container update ${{ secrets.SCW_CONTAINER_ID }} \
73
+ registry-image=${{ needs.build-and-push.outputs.image }}:${{ github.sha }} \
74
+ region=${{ env.SCW_DEFAULT_REGION }} \
75
+ redeploy=true
76
+ env:
77
+ SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY }}
78
+ SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY }}
79
+ SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID }}
80
+ SCW_DEFAULT_PROJECT_ID: ${{ secrets.SCW_PROJECT_ID }}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @slashgear/gdpr-cookie-scanner
2
2
 
3
+ ## 3.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 88d944f: Introduce pnpm workspace monorepo and `website` package.
8
+
9
+ Converts the repo to a pnpm workspace and adds a new private `website` package (`@slashgear/gdpr-website`) built with Hono on Node.js. The package exposes a Docker image (`ghcr.io/slashgear/gdpr-website`) intended for deployment as a Scaleway Serverless Container at `gdpr.slashgear.dev`. A dedicated GitHub Actions workflow (`website.yml`) builds and pushes the image on every push to `main` that touches `website/**`, then redeploys the container via the Scaleway CLI.
10
+
3
11
  ## 3.7.0
4
12
 
5
13
  ### Minor Changes
package/CONTRIBUTING.md CHANGED
@@ -2,20 +2,32 @@
2
2
 
3
3
  ## Prerequisites
4
4
 
5
- - Node.js ≥ 20
5
+ - Node.js ≥ 24
6
6
  - pnpm
7
- - Playwright: `npx playwright install chromium`
7
+ - Playwright: `pnpm exec playwright install chromium`
8
+
9
+ ## Repository structure
10
+
11
+ This is a **pnpm workspace monorepo** with two packages:
12
+
13
+ | Package | Path | Description |
14
+ | -------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
15
+ | `@slashgear/gdpr-cookie-scanner` | `/` (root) | Published CLI tool |
16
+ | `@slashgear/gdpr-website` | `website/` | Hono web app — not published, deployed as a Docker image to [gdpr.slashgear.dev](https://gdpr.slashgear.dev) |
8
17
 
9
18
  ## Getting started
10
19
 
11
20
  ```bash
12
21
  git clone https://github.com/Slashgear/gdpr-report.git
13
22
  cd gdpr-report
14
- pnpm install
15
- pnpm build
23
+ pnpm install # installs all workspace packages
24
+ pnpm build # builds the CLI
16
25
 
17
26
  # Run the CLI locally
18
27
  node dist/cli.js scan https://example.com
28
+
29
+ # Run the website locally (http://localhost:8080)
30
+ pnpm website:dev
19
31
  ```
20
32
 
21
33
  ## Workflow
@@ -28,6 +40,7 @@ node dist/cli.js scan https://example.com
28
40
  pnpm lint
29
41
  pnpm typecheck
30
42
  pnpm build
43
+ pnpm website:typecheck
31
44
  ```
32
45
  4. Open a Pull Request targeting `main`
33
46
 
@@ -37,6 +50,21 @@ node dist/cli.js scan https://example.com
37
50
  - **Consent modal detection** — improve CMP detection in `src/scanner/consent-modal.ts`
38
51
  - **Compliance rules** — refine scoring rules in `src/analyzers/compliance.ts`
39
52
  - **Report** — improve report rendering in `src/report/generator.ts`
53
+ - **Website** — Hono server and landing page in `website/src/` and `website/public/`
54
+
55
+ ## Website — live reports showcase
56
+
57
+ The `website/public/reports/` directory contains pre-generated HTML reports (grades A–D only).
58
+ After adding new reports, run:
59
+
60
+ ```bash
61
+ pnpm build:showcase # regenerates the report cards in website/public/index.html
62
+ ```
63
+
64
+ The script reads `website/public/reports/` and injects sorted report cards between the
65
+ `<!-- ── REPORTS_START ── -->` / `<!-- ── REPORTS_END ── -->` markers.
66
+
67
+ Report screenshots (`.png`) are tracked via **Git LFS** — make sure `git lfs` is installed before cloning.
40
68
 
41
69
  ## Releasing
42
70
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slashgear/gdpr-cookie-scanner",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "CLI tool to scan websites for GDPR cookie consent compliance",
5
5
  "keywords": [
6
6
  "compliance",
@@ -12,7 +12,7 @@
12
12
  "rgpd",
13
13
  "scanner"
14
14
  ],
15
- "homepage": "https://github.com/Slashgear/gdpr-cookie-scanner#readme",
15
+ "homepage": "https://gdpr.slashgear.dev",
16
16
  "bugs": {
17
17
  "url": "https://github.com/Slashgear/gdpr-cookie-scanner/issues"
18
18
  },
@@ -68,6 +68,10 @@
68
68
  "changeset": "changeset",
69
69
  "update-trackers": "node --experimental-strip-types scripts/update-trackers.ts",
70
70
  "update-trackers:dry": "node --experimental-strip-types scripts/update-trackers.ts --dry-run",
71
- "update:ocd": "node scripts/update-cookie-db.mjs"
71
+ "update:ocd": "node scripts/update-cookie-db.mjs",
72
+ "build:showcase": "node scripts/build-showcase.mjs && pnpm format",
73
+ "website:dev": "pnpm --filter @slashgear/gdpr-website dev",
74
+ "website:build": "pnpm --filter @slashgear/gdpr-website build",
75
+ "website:typecheck": "pnpm --filter @slashgear/gdpr-website typecheck"
72
76
  }
73
77
  }
@@ -0,0 +1,3 @@
1
+ packages:
2
+ - "."
3
+ - website
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Reads docs/reports/<host>/ directories, extracts grade/score/date from
3
+ * each HTML report, and regenerates the "Live Reports" cards in docs/index.html.
4
+ *
5
+ * Usage: node scripts/build-showcase.mjs
6
+ * Or: pnpm build:showcase
7
+ */
8
+
9
+ import { readdir, readFile, writeFile } from "fs/promises";
10
+ import { join, resolve } from "path";
11
+ import { existsSync } from "fs";
12
+
13
+ const WEBSITE_PUBLIC_DIR = resolve("website/public");
14
+ const REPORTS_DIR = join(WEBSITE_PUBLIC_DIR, "reports");
15
+ const INDEX_HTML = join(WEBSITE_PUBLIC_DIR, "index.html");
16
+
17
+ const START_MARKER = "<!-- ── REPORTS_START ── -->";
18
+ const END_MARKER = "<!-- ── REPORTS_END ── -->";
19
+
20
+ async function extractMeta(hostDir) {
21
+ const files = await readdir(join(REPORTS_DIR, hostDir));
22
+ const htmlFile = files.find((f) => f.endsWith(".html"));
23
+ if (!htmlFile) return null;
24
+
25
+ const content = await readFile(join(REPORTS_DIR, hostDir, htmlFile), "utf8");
26
+
27
+ // oxfmt may split closing tags across lines — match opening tag content only
28
+ const grade = content.match(/"grade-badge"[^>]*>([A-F])<\/div>/)?.[1] ?? "?";
29
+ const score = content.match(/"score-num"[^>]*>(\d+)/)?.[1] ?? "?";
30
+
31
+ // Date from filename: gdpr-report-<host>-YYYY-MM-DD.html
32
+ const dateRaw = htmlFile.match(/(\d{4}-\d{2}-\d{2})\.html$/)?.[1];
33
+ const dateStr = dateRaw
34
+ ? new Date(dateRaw).toLocaleDateString("en-GB", {
35
+ day: "numeric",
36
+ month: "short",
37
+ year: "numeric",
38
+ })
39
+ : "";
40
+
41
+ const displayHost = hostDir.replace(/^www\./, "");
42
+
43
+ // Inject modal screenshot if PNG exists alongside the HTML but isn't referenced yet
44
+ const pngPath = join(REPORTS_DIR, hostDir, "modal-initial.png");
45
+ const htmlPath = join(REPORTS_DIR, hostDir, htmlFile);
46
+ if (existsSync(pngPath) && !content.includes("modal-initial.png")) {
47
+ const IMG = `<img src="modal-initial.png" alt="Consent modal screenshot" class="modal-screenshot" />`;
48
+ // Insert right after the section-body div that follows <h2>Consent modal</h2>
49
+ const patched = content.replace(
50
+ /(<h2>Consent modal<\/h2>[\s\S]*?<div class="section-body">)/,
51
+ `$1\n ${IMG}`,
52
+ );
53
+ if (patched !== content) {
54
+ await writeFile(htmlPath, patched, "utf8");
55
+ }
56
+ }
57
+
58
+ return { grade, score: parseInt(score, 10) || 0, dateStr, displayHost, hostDir, htmlFile };
59
+ }
60
+
61
+ function buildCard({ grade, score, dateStr, displayHost, hostDir, htmlFile }) {
62
+ return ` <!-- ${displayHost} — ${score}/100 ${grade} -->
63
+ <div class="report-card">
64
+ <div class="report-header">
65
+ <div class="grade-badge grade-${grade}">${grade}</div>
66
+ <div class="report-meta">
67
+ <h3>${displayHost}</h3>
68
+ <span class="score">${score} / 100</span>
69
+ </div>
70
+ </div>
71
+ <p class="report-date">Scanned ${dateStr}</p>
72
+ <a class="btn btn-outline" href="reports/${hostDir}/${htmlFile}">
73
+ View report →
74
+ </a>
75
+ </div>`;
76
+ }
77
+
78
+ async function main() {
79
+ const hosts = (await readdir(REPORTS_DIR, { withFileTypes: true }))
80
+ .filter((d) => d.isDirectory())
81
+ .map((d) => d.name);
82
+
83
+ const reports = (await Promise.all(hosts.map(extractMeta))).filter(Boolean);
84
+
85
+ // Sort by score descending (best first)
86
+ reports.sort((a, b) => b.score - a.score);
87
+
88
+ const cards = reports.map(buildCard).join("\n\n");
89
+
90
+ let index = await readFile(INDEX_HTML, "utf8");
91
+ const startIdx = index.indexOf(START_MARKER);
92
+ const endIdx = index.indexOf(END_MARKER);
93
+
94
+ if (startIdx === -1 || endIdx === -1) {
95
+ throw new Error(`Markers not found in ${INDEX_HTML}. Add:\n ${START_MARKER}\n ${END_MARKER}`);
96
+ }
97
+
98
+ const newIndex =
99
+ index.slice(0, startIdx + START_MARKER.length) +
100
+ "\n" +
101
+ cards +
102
+ "\n " +
103
+ index.slice(endIdx);
104
+
105
+ await writeFile(INDEX_HTML, newIndex, "utf8");
106
+ console.log(`✓ ${INDEX_HTML} updated with ${reports.length} report cards`);
107
+ reports.forEach((r) => console.log(` ${r.grade} ${r.score}/100 ${r.displayHost}`));
108
+ }
109
+
110
+ main().catch((e) => {
111
+ console.error(e);
112
+ process.exit(1);
113
+ });
@@ -0,0 +1,55 @@
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"]
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,29 @@
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
+ }