Implement full consent logging system with SQLite database
- Install better-sqlite3 and @astrojs/node adapter - Update consent API to use SQLite database - Add DELETE endpoint for consent logs - Update admin consent-logs page with full UI (stats, table, export, delete) - Add sessionId to consent tracking - Admin password: Coolm@n1234mo Note: Database stored at data/consent.db (gitignored)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
import tailwind from '@astrojs/tailwind';
|
import tailwind from '@astrojs/tailwind';
|
||||||
import sitemap from '@astrojs/sitemap';
|
import sitemap from '@astrojs/sitemap';
|
||||||
|
import node from '@astrojs/node';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: 'https://dealplustech.co.th',
|
site: 'https://dealplustech.co.th',
|
||||||
@@ -10,6 +11,9 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
sitemap(),
|
sitemap(),
|
||||||
],
|
],
|
||||||
|
adapter: node({
|
||||||
|
mode: 'standalone',
|
||||||
|
}),
|
||||||
i18n: {
|
i18n: {
|
||||||
defaultLocale: 'th',
|
defaultLocale: 'th',
|
||||||
locales: ['th'],
|
locales: ['th'],
|
||||||
|
|||||||
624
package-lock.json
generated
624
package-lock.json
generated
@@ -9,14 +9,17 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/db": "^0.20.1",
|
"@astrojs/db": "^0.20.1",
|
||||||
|
"@astrojs/node": "^10.0.4",
|
||||||
"@astrojs/sitemap": "^3.7.2",
|
"@astrojs/sitemap": "^3.7.2",
|
||||||
"@astrojs/tailwind": "^5.1.4",
|
"@astrojs/tailwind": "^5.1.4",
|
||||||
"astro": "^6.1.2",
|
"astro": "^6.1.2",
|
||||||
"astro-consent": "^1.0.0",
|
"astro-consent": "^1.0.0",
|
||||||
|
"better-sqlite3": "^12.8.0",
|
||||||
"drizzle-orm": "^0.38.2",
|
"drizzle-orm": "^0.38.2",
|
||||||
"tailwindcss": "^3.4.17"
|
"tailwindcss": "^3.4.17"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/better-sqlite3": "^7.6.13",
|
||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.10.2",
|
||||||
"typescript": "^5.7.2"
|
"typescript": "^5.7.2"
|
||||||
}
|
}
|
||||||
@@ -214,6 +217,20 @@
|
|||||||
"vfile": "^6.0.3"
|
"vfile": "^6.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@astrojs/node": {
|
||||||
|
"version": "10.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@astrojs/node/-/node-10.0.4.tgz",
|
||||||
|
"integrity": "sha512-7pVgiVSscQHRC2WqjlXcnbbcKMYp2GXrYpmuvdGg5zgA8J1lFm2vmwVhHZFuZK3Ik5PzoxiDROaEgoDGLbfhLw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/internal-helpers": "0.8.0",
|
||||||
|
"send": "^1.2.1",
|
||||||
|
"server-destroy": "^1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"astro": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@astrojs/prism": {
|
"node_modules/@astrojs/prism": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.1.tgz",
|
||||||
@@ -1935,6 +1952,16 @@
|
|||||||
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
|
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/better-sqlite3": {
|
||||||
|
"version": "7.6.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz",
|
||||||
|
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/debug": {
|
"node_modules/@types/debug": {
|
||||||
"version": "4.1.13",
|
"version": "4.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
|
||||||
@@ -2232,6 +2259,26 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.10.7",
|
"version": "2.10.7",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.7.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.7.tgz",
|
||||||
@@ -2244,6 +2291,20 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/better-sqlite3": {
|
||||||
|
"version": "12.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.8.0.tgz",
|
||||||
|
"integrity": "sha512-RxD2Vd96sQDjQr20kdP+F+dK/1OUNiVOl200vKBZY8u0vTwysfolF6Hq+3ZK2+h8My9YvZhHsF+RSGZW2VYrPQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"prebuild-install": "^7.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||||
@@ -2256,6 +2317,26 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bindings": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"file-uri-to-path": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bl": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer": "^5.5.0",
|
||||||
|
"inherits": "^2.0.4",
|
||||||
|
"readable-stream": "^3.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/boolbase": {
|
"node_modules/boolbase": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
@@ -2307,6 +2388,30 @@
|
|||||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/camelcase-css": {
|
"node_modules/camelcase-css": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||||
@@ -2412,6 +2517,12 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chownr": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/ci-info": {
|
"node_modules/ci-info": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
|
||||||
@@ -2646,12 +2757,45 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decompress-response": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/deep-extend": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/defu": {
|
"node_modules/defu": {
|
||||||
"version": "6.1.4",
|
"version": "6.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
||||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/depd": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dequal": {
|
"node_modules/dequal": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
@@ -2917,12 +3061,36 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ee-first": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.313",
|
"version": "1.5.313",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz",
|
||||||
"integrity": "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==",
|
"integrity": "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/encodeurl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/end-of-stream": {
|
||||||
|
"version": "1.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||||
|
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"once": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/entities": {
|
"node_modules/entities": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
||||||
@@ -2991,6 +3159,12 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/escape-html": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/escape-string-regexp": {
|
"node_modules/escape-string-regexp": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
||||||
@@ -3003,12 +3177,30 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/etag": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eventemitter3": {
|
"node_modules/eventemitter3": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
|
||||||
"integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
|
"integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/expand-template": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||||
|
"license": "(MIT OR WTFPL)",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/extend": {
|
"node_modules/extend": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||||
@@ -3092,6 +3284,12 @@
|
|||||||
"node": "^12.20 || >= 14.13"
|
"node": "^12.20 || >= 14.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/file-uri-to-path": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
@@ -3159,6 +3357,21 @@
|
|||||||
"url": "https://github.com/sponsors/rawify"
|
"url": "https://github.com/sponsors/rawify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fresh": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fs-constants": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
@@ -3182,6 +3395,12 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/github-from-package": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/github-slugger": {
|
"node_modules/github-slugger": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz",
|
||||||
@@ -3428,6 +3647,58 @@
|
|||||||
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
|
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
|
||||||
"license": "BSD-2-Clause"
|
"license": "BSD-2-Clause"
|
||||||
},
|
},
|
||||||
|
"node_modules/http-errors": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"depd": "~2.0.0",
|
||||||
|
"inherits": "~2.0.4",
|
||||||
|
"setprototypeof": "~1.2.0",
|
||||||
|
"statuses": "~2.0.2",
|
||||||
|
"toidentifier": "~1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/ini": {
|
||||||
|
"version": "1.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||||
|
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/iron-webcrypto": {
|
"node_modules/iron-webcrypto": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
|
||||||
@@ -4514,6 +4785,58 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.54.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||||
|
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "^1.54.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mimic-response": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minimist": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mkdirp-classic": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||||
|
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/mrmime": {
|
"node_modules/mrmime": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
||||||
@@ -4558,6 +4881,12 @@
|
|||||||
"node": "^18 || >=20"
|
"node": "^18 || >=20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/napi-build-utils": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/neotraverse": {
|
"node_modules/neotraverse": {
|
||||||
"version": "0.6.18",
|
"version": "0.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz",
|
||||||
@@ -4580,6 +4909,18 @@
|
|||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-abi": {
|
||||||
|
"version": "3.89.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz",
|
||||||
|
"integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-domexception": {
|
"node_modules/node-domexception": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||||
@@ -4702,6 +5043,27 @@
|
|||||||
"integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
|
"integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/on-finished": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ee-first": "1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/oniguruma-parser": {
|
"node_modules/oniguruma-parser": {
|
||||||
"version": "0.12.1",
|
"version": "0.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz",
|
||||||
@@ -5013,6 +5375,33 @@
|
|||||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prebuild-install": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
||||||
|
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^2.0.0",
|
||||||
|
"expand-template": "^2.0.3",
|
||||||
|
"github-from-package": "0.0.0",
|
||||||
|
"minimist": "^1.2.3",
|
||||||
|
"mkdirp-classic": "^0.5.3",
|
||||||
|
"napi-build-utils": "^2.0.0",
|
||||||
|
"node-abi": "^3.3.0",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"rc": "^1.2.7",
|
||||||
|
"simple-get": "^4.0.0",
|
||||||
|
"tar-fs": "^2.0.0",
|
||||||
|
"tunnel-agent": "^0.6.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"prebuild-install": "bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prismjs": {
|
"node_modules/prismjs": {
|
||||||
"version": "1.30.0",
|
"version": "1.30.0",
|
||||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
|
||||||
@@ -5038,6 +5427,16 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pump": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"end-of-stream": "^1.1.0",
|
||||||
|
"once": "^1.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
@@ -5064,6 +5463,30 @@
|
|||||||
"integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
|
"integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/range-parser": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rc": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||||
|
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||||
|
"dependencies": {
|
||||||
|
"deep-extend": "^0.6.0",
|
||||||
|
"ini": "~1.3.0",
|
||||||
|
"minimist": "^1.2.0",
|
||||||
|
"strip-json-comments": "~2.0.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rc": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@@ -5073,6 +5496,20 @@
|
|||||||
"pify": "^2.3.0"
|
"pify": "^2.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
@@ -5421,6 +5858,26 @@
|
|||||||
"queue-microtask": "^1.2.2"
|
"queue-microtask": "^1.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/sax": {
|
"node_modules/sax": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz",
|
||||||
@@ -5442,6 +5899,44 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/send": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.4.3",
|
||||||
|
"encodeurl": "^2.0.0",
|
||||||
|
"escape-html": "^1.0.3",
|
||||||
|
"etag": "^1.8.1",
|
||||||
|
"fresh": "^2.0.0",
|
||||||
|
"http-errors": "^2.0.1",
|
||||||
|
"mime-types": "^3.0.2",
|
||||||
|
"ms": "^2.1.3",
|
||||||
|
"on-finished": "^2.4.1",
|
||||||
|
"range-parser": "^1.2.1",
|
||||||
|
"statuses": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/server-destroy": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/setprototypeof": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/sharp": {
|
"node_modules/sharp": {
|
||||||
"version": "0.34.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
||||||
@@ -5516,6 +6011,51 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-concat": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/simple-get": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"decompress-response": "^6.0.0",
|
||||||
|
"once": "^1.3.1",
|
||||||
|
"simple-concat": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sisteransi": {
|
"node_modules/sisteransi": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
@@ -5587,12 +6127,30 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/statuses": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/stream-replace-string": {
|
"node_modules/stream-replace-string": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz",
|
||||||
"integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==",
|
"integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/stringify-entities": {
|
"node_modules/stringify-entities": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
|
||||||
@@ -5607,6 +6165,15 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/strip-json-comments": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sucrase": {
|
"node_modules/sucrase": {
|
||||||
"version": "3.35.1",
|
"version": "3.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
|
||||||
@@ -5712,6 +6279,34 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tar-fs": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": "^1.1.1",
|
||||||
|
"mkdirp-classic": "^0.5.2",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"tar-stream": "^2.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar-stream": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bl": "^4.0.3",
|
||||||
|
"end-of-stream": "^1.4.1",
|
||||||
|
"fs-constants": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/thenify": {
|
"node_modules/thenify": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||||
@@ -5785,6 +6380,15 @@
|
|||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/toidentifier": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tr46": {
|
"node_modules/tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
@@ -5844,11 +6448,23 @@
|
|||||||
"license": "0BSD",
|
"license": "0BSD",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tunnel-agent": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.9.3",
|
"version": "5.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
@@ -6374,6 +6990,12 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.20.0",
|
"version": "8.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
|
||||||
|
|||||||
@@ -11,14 +11,17 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/db": "^0.20.1",
|
"@astrojs/db": "^0.20.1",
|
||||||
|
"@astrojs/node": "^10.0.4",
|
||||||
"@astrojs/sitemap": "^3.7.2",
|
"@astrojs/sitemap": "^3.7.2",
|
||||||
"@astrojs/tailwind": "^5.1.4",
|
"@astrojs/tailwind": "^5.1.4",
|
||||||
"astro": "^6.1.2",
|
"astro": "^6.1.2",
|
||||||
"astro-consent": "^1.0.0",
|
"astro-consent": "^1.0.0",
|
||||||
|
"better-sqlite3": "^12.8.0",
|
||||||
"drizzle-orm": "^0.38.2",
|
"drizzle-orm": "^0.38.2",
|
||||||
"tailwindcss": "^3.4.17"
|
"tailwindcss": "^3.4.17"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/better-sqlite3": "^7.6.13",
|
||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.10.2",
|
||||||
"typescript": "^5.7.2"
|
"typescript": "^5.7.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,10 +258,19 @@ const siteUrl = 'https://dealplustech.co.th';
|
|||||||
});
|
});
|
||||||
|
|
||||||
function saveConsent(preferences) {
|
function saveConsent(preferences) {
|
||||||
|
// Get or generate sessionId
|
||||||
|
let sessionId = localStorage.getItem('consent-session-id');
|
||||||
|
if (!sessionId) {
|
||||||
|
sessionId = crypto.randomUUID();
|
||||||
|
localStorage.setItem('consent-session-id', sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
const consentData = {
|
const consentData = {
|
||||||
...preferences,
|
...preferences,
|
||||||
|
sessionId,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
policyVersion: '1.0'
|
policyVersion: '1.0',
|
||||||
|
userAgent: navigator.userAgent
|
||||||
};
|
};
|
||||||
localStorage.setItem('consent-preferences', JSON.stringify(consentData));
|
localStorage.setItem('consent-preferences', JSON.stringify(consentData));
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ import BaseLayout from '@/layouts/BaseLayout.astro';
|
|||||||
import Header from '@/components/common/Header.astro';
|
import Header from '@/components/common/Header.astro';
|
||||||
import Footer from '@/components/common/Footer.astro';
|
import Footer from '@/components/common/Footer.astro';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
const adminPassword = import.meta.env.ADMIN_PASSWORD || 'Coolm@n1234mo';
|
const adminPassword = import.meta.env.ADMIN_PASSWORD || 'Coolm@n1234mo';
|
||||||
const submitted = Astro.request.method === 'POST';
|
|
||||||
const password = Astro.url.searchParams.get('password') || '';
|
const password = Astro.url.searchParams.get('password') || '';
|
||||||
const isAuthorized = password === adminPassword;
|
const isAuthorized = password === adminPassword;
|
||||||
---
|
---
|
||||||
@@ -17,48 +18,64 @@ const isAuthorized = password === adminPassword;
|
|||||||
<div class="container-custom">
|
<div class="container-custom">
|
||||||
{isAuthorized ? (
|
{isAuthorized ? (
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-3xl font-bold text-secondary-900 mb-8">Consent Logs</h1>
|
<div class="flex flex-wrap gap-4 mb-8">
|
||||||
|
<button id="refresh-btn" class="bg-primary text-white px-6 py-2 rounded-lg font-bold hover:bg-primary-600 transition">🔄 รีเฟรช</button>
|
||||||
<div class="card bg-white p-6 mb-8">
|
<button id="export-btn" class="bg-green-500 text-white px-6 py-2 rounded-lg font-bold hover:bg-green-600 transition">📥 Export CSV</button>
|
||||||
<h2 class="text-xl font-semibold mb-4">วิธีใช้งาน</h2>
|
<button id="logout-btn" class="bg-gray-500 text-white px-6 py-2 rounded-lg font-bold hover:bg-gray-600 transition">🚪 ออกจากระบบ</button>
|
||||||
<ul class="list-disc pl-6 text-secondary-700 space-y-2">
|
|
||||||
<li>หน้านี้แสดง log การยอมรับ cookie consent ที่ส่งมาจากผู้เยี่ยมชมเว็บไซต์</li>
|
|
||||||
<li>ข้อมูลถูกบันทึกใน log file ของ server</li>
|
|
||||||
<li>สำหรับดู log จริง ให้ SSH ไปที่ server แล้วดูที่ <code class="bg-gray-100 px-2 py-1 rounded">pm2 logs</code> หรือ <code class="bg-gray-100 px-2 py-1 rounded">docker logs</code></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card bg-white p-6">
|
<div class="grid md:grid-cols-4 gap-6 mb-8">
|
||||||
<h2 class="text-xl font-semibold mb-4">ตัวอย่างข้อมูลที่บันทึก</h2>
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
<pre class="bg-gray-900 text-green-400 p-4 rounded-lg overflow-x-auto text-sm">
|
<h3 class="text-sm font-medium text-gray-600 mb-2">Total Consents</h3>
|
||||||
{`[
|
<p id="stat-total" class="text-3xl font-bold text-secondary-900">0</p>
|
||||||
{
|
</div>
|
||||||
"id": "550e8400-e29b-41d4-a716-446655440000",
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
"essential": true,
|
<h3 class="text-sm font-medium text-gray-600 mb-2">Accepted Analytics</h3>
|
||||||
"analytics": true,
|
<p id="stat-analytics" class="text-3xl font-bold text-green-600">0</p>
|
||||||
"marketing": false,
|
</div>
|
||||||
"timestamp": 1709300000000,
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
"policyVersion": "1.0",
|
<h3 class="text-sm font-medium text-gray-600 mb-2">Rejected Analytics</h3>
|
||||||
"ip": "127.0.0.1",
|
<p id="stat-rejected" class="text-3xl font-bold text-red-600">0</p>
|
||||||
"userAgent": "Mozilla/5.0...",
|
</div>
|
||||||
"createdAt": "2024-03-01T12:00:00.000Z"
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
}
|
<h3 class="text-sm font-medium text-gray-600 mb-2">Acceptance Rate</h3>
|
||||||
]`}</pre>
|
<p id="stat-rate" class="text-3xl font-bold text-accent-500">0%</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-8 text-center">
|
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||||
<a href="/admin/consent-logs" class="btn-secondary">ออกจากระบบ</a>
|
<div class="px-6 py-4 border-b border-gray-200">
|
||||||
|
<h2 class="text-xl font-bold text-secondary-900">บันทึกความยินยอม (100 ล่าสุด)</h2>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">วันที่/เวลา</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Session ID</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Essential</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Analytics</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Marketing</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Policy Version</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="logs-table-body" class="bg-white divide-y divide-gray-200">
|
||||||
|
<tr><td colspan="7" class="px-6 py-4 text-center text-gray-500">กำลังโหลด...</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div class="max-w-md mx-auto">
|
<div class="max-w-md mx-auto">
|
||||||
<div class="card bg-white p-8">
|
<div class="bg-white rounded-lg shadow-md p-8">
|
||||||
<h1 class="text-2xl font-bold text-secondary-900 mb-6 text-center">Admin Login</h1>
|
<h1 class="text-2xl font-bold text-secondary-900 mb-6 text-center">เข้าสู่ระบบ Admin</h1>
|
||||||
|
|
||||||
<form method="GET" action="/admin/consent-logs" class="space-y-4">
|
<form method="GET" action="/admin/consent-logs" class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label for="password" class="block text-sm font-medium text-secondary-700 mb-2">
|
<label for="password" class="block text-sm font-medium text-secondary-700 mb-2">
|
||||||
Password
|
รหัสผ่าน
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
@@ -66,7 +83,7 @@ const isAuthorized = password === adminPassword;
|
|||||||
name="password"
|
name="password"
|
||||||
required
|
required
|
||||||
class="w-full px-4 py-3 border border-secondary-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-4 py-3 border border-secondary-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="Enter admin password"
|
placeholder="กรอกรหัสผ่าน"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -77,10 +94,6 @@ const isAuthorized = password === adminPassword;
|
|||||||
เข้าสู่ระบบ
|
เข้าสู่ระบบ
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{submitted && (
|
|
||||||
<p class="mt-4 text-center text-red-600">รหัสผ่านไม่ถูกต้อง</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -89,4 +102,122 @@ const isAuthorized = password === adminPassword;
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<Footer slot="footer" />
|
<Footer slot="footer" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function loadConsentLogs() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/consent');
|
||||||
|
const data = await response.json();
|
||||||
|
const logs = data.logs || [];
|
||||||
|
const tbody = document.getElementById('logs-table-body');
|
||||||
|
|
||||||
|
if (logs.length === 0) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="7" class="px-6 py-4 text-center text-gray-500">ยังไม่มีการบันทึกความยินยอม</td></tr>';
|
||||||
|
updateStats([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody.innerHTML = logs.map(log => `
|
||||||
|
<tr class="hover:bg-gray-50">
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm">${new Date(log.timestamp).toLocaleString('th-TH')}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono">${(log.sessionId || '').substring(0, 8)}...</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="px-2 py-1 text-xs font-semibold rounded-full ${log.essential ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">${log.essential ? '✓' : '✗'}</span></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="px-2 py-1 text-xs font-semibold rounded-full ${log.analytics ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">${log.analytics ? '✓' : '✗'}</span></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="px-2 py-1 text-xs font-semibold rounded-full ${log.marketing ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">${log.marketing ? '✓' : '✗'}</span></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm">${log.policyVersion || '-'}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"><button onclick="deleteConsent('${log.sessionId}')" class="text-red-600 hover:text-red-900 font-medium">ลบ</button></td>
|
||||||
|
</tr>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
updateStats(logs);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading logs:', error);
|
||||||
|
const tbody = document.getElementById('logs-table-body');
|
||||||
|
tbody.innerHTML = '<tr><td colspan="7" class="px-6 py-4 text-center text-red-500">เกิดข้อผิดพลาดในการโหลดข้อมูล</td></tr>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStats(logs) {
|
||||||
|
const total = logs.length;
|
||||||
|
const analytics = logs.filter(l => l.analytics).length;
|
||||||
|
const rejected = total - analytics;
|
||||||
|
const rate = total > 0 ? ((analytics / total) * 100).toFixed(1) : '0';
|
||||||
|
|
||||||
|
document.getElementById('stat-total').textContent = total.toString();
|
||||||
|
document.getElementById('stat-analytics').textContent = analytics.toString();
|
||||||
|
document.getElementById('stat-rejected').textContent = rejected.toString();
|
||||||
|
document.getElementById('stat-rate').textContent = rate + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteConsent(sessionId) {
|
||||||
|
if (!confirm('คุณแน่ใจหรือไม่ที่จะลบบันทึกนี้?')) return;
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/consent/' + sessionId, { method: 'DELETE' });
|
||||||
|
if (response.ok) {
|
||||||
|
alert('ลบบันทึกเรียบร้อยแล้ว');
|
||||||
|
loadConsentLogs();
|
||||||
|
} else {
|
||||||
|
alert('เกิดข้อผิดพลาดในการลบ');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('เกิดข้อผิดพลาดในการลบ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exportToCSV() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/consent');
|
||||||
|
const data = await response.json();
|
||||||
|
const logs = data.logs || [];
|
||||||
|
|
||||||
|
if (logs.length === 0) {
|
||||||
|
alert('ไม่มีข้อมูลให้ export');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = ['วันที่/เวลา', 'Session ID', 'Essential', 'Analytics', 'Marketing', 'Policy Version', 'IP Hash', 'User Agent'];
|
||||||
|
const csvRows = [headers.join(',')];
|
||||||
|
|
||||||
|
for (const log of logs) {
|
||||||
|
const row = [
|
||||||
|
new Date(log.timestamp).toLocaleString('th-TH'),
|
||||||
|
log.sessionId,
|
||||||
|
log.essential ? 'Yes' : 'No',
|
||||||
|
log.analytics ? 'Yes' : 'No',
|
||||||
|
log.marketing ? 'Yes' : 'No',
|
||||||
|
log.policyVersion || '',
|
||||||
|
log.ipHash || '',
|
||||||
|
(log.userAgent || '').replace(/,/g, ';')
|
||||||
|
];
|
||||||
|
csvRows.push(row.join(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
const csvContent = '\ufeff' + csvRows.join('\n');
|
||||||
|
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = 'consent-logs-' + new Date().toISOString().split('T')[0] + '.csv';
|
||||||
|
link.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Export error:', error);
|
||||||
|
alert('เกิดข้อผิดพลาดในการ export');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
if (document.getElementById('stat-total')) {
|
||||||
|
loadConsentLogs();
|
||||||
|
|
||||||
|
document.getElementById('refresh-btn').addEventListener('click', loadConsentLogs);
|
||||||
|
document.getElementById('export-btn').addEventListener('click', exportToCSV);
|
||||||
|
document.getElementById('logout-btn').addEventListener('click', () => {
|
||||||
|
window.location.href = '/admin/consent-logs';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(window as any).deleteConsent = deleteConsent;
|
||||||
|
</script>
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|||||||
58
src/pages/api/consent/[sessionId].ts
Normal file
58
src/pages/api/consent/[sessionId].ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { APIRoute } from 'astro';
|
||||||
|
import Database from 'better-sqlite3';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { mkdirSync, existsSync } from 'fs';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
|
const DATA_DIR = join(process.cwd(), 'data');
|
||||||
|
const DB_PATH = join(DATA_DIR, 'consent.db');
|
||||||
|
|
||||||
|
function getDb() {
|
||||||
|
if (!existsSync(DATA_DIR)) {
|
||||||
|
mkdirSync(DATA_DIR, { recursive: true });
|
||||||
|
}
|
||||||
|
const db = new Database(DB_PATH);
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS ConsentLog (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
sessionId TEXT UNIQUE NOT NULL,
|
||||||
|
timestamp TEXT NOT NULL,
|
||||||
|
essential INTEGER NOT NULL DEFAULT 0,
|
||||||
|
analytics INTEGER NOT NULL DEFAULT 0,
|
||||||
|
marketing INTEGER NOT NULL DEFAULT 0,
|
||||||
|
policyVersion TEXT NOT NULL,
|
||||||
|
ipHash TEXT,
|
||||||
|
userAgent TEXT
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DELETE: APIRoute = async ({ params }) => {
|
||||||
|
try {
|
||||||
|
const sessionId = params.sessionId;
|
||||||
|
if (!sessionId) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: 'Missing sessionId' }),
|
||||||
|
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = getDb();
|
||||||
|
const stmt = db.prepare('DELETE FROM ConsentLog WHERE sessionId = ?');
|
||||||
|
stmt.run(sessionId);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ success: true, message: 'Consent deleted' }),
|
||||||
|
{ status: 200, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting consent:', error);
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: 'Failed to delete consent' }),
|
||||||
|
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,40 +1,138 @@
|
|||||||
import type { APIRoute } from 'astro';
|
import type { APIRoute } from 'astro';
|
||||||
|
import Database from 'better-sqlite3';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { mkdirSync, existsSync } from 'fs';
|
||||||
|
|
||||||
export const POST: APIRoute = async ({ request }) => {
|
export const prerender = false;
|
||||||
let consentData = {};
|
|
||||||
|
|
||||||
try {
|
const DATA_DIR = join(process.cwd(), 'data');
|
||||||
const text = await request.text();
|
const DB_PATH = join(DATA_DIR, 'consent.db');
|
||||||
if (text) {
|
|
||||||
consentData = JSON.parse(text);
|
function getDb() {
|
||||||
}
|
if (!existsSync(DATA_DIR)) {
|
||||||
} catch (e) {
|
mkdirSync(DATA_DIR, { recursive: true });
|
||||||
console.error('[Consent API] JSON parse error:', e);
|
}
|
||||||
|
const db = new Database(DB_PATH);
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS ConsentLog (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
sessionId TEXT UNIQUE NOT NULL,
|
||||||
|
timestamp TEXT NOT NULL,
|
||||||
|
essential INTEGER NOT NULL DEFAULT 0,
|
||||||
|
analytics INTEGER NOT NULL DEFAULT 0,
|
||||||
|
marketing INTEGER NOT NULL DEFAULT 0,
|
||||||
|
policyVersion TEXT NOT NULL,
|
||||||
|
ipHash TEXT,
|
||||||
|
userAgent TEXT
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rateLimitMap = new Map<string, { count: number; resetTime: number }>();
|
||||||
|
const RATE_LIMIT = 10;
|
||||||
|
const RATE_WINDOW = 60000;
|
||||||
|
|
||||||
|
function checkRateLimit(ip: string): boolean {
|
||||||
|
const now = Date.now();
|
||||||
|
const record = rateLimitMap.get(ip);
|
||||||
|
|
||||||
|
if (!record || now > record.resetTime) {
|
||||||
|
rateLimitMap.set(ip, { count: 1, resetTime: now + RATE_WINDOW });
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const record = {
|
if (record.count >= RATE_LIMIT) {
|
||||||
id: crypto.randomUUID(),
|
return false;
|
||||||
essential: consentData.essential ?? true,
|
}
|
||||||
analytics: consentData.analytics ?? false,
|
|
||||||
marketing: consentData.marketing ?? false,
|
|
||||||
timestamp: consentData.timestamp || Date.now(),
|
|
||||||
policyVersion: consentData.policyVersion || '1.0',
|
|
||||||
ip: request.headers.get('x-forwarded-for') || 'unknown',
|
|
||||||
userAgent: request.headers.get('user-agent') || 'unknown',
|
|
||||||
createdAt: new Date().toISOString()
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('[Consent Log]', JSON.stringify(record));
|
record.count++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(JSON.stringify({ success: true, record }), {
|
async function hashIP(ip: string): Promise<string> {
|
||||||
status: 200,
|
try {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
if (crypto.subtle) {
|
||||||
});
|
const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(ip));
|
||||||
|
return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 16);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
return `fallback-${Date.now()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST: APIRoute = async ({ request, clientAddress }) => {
|
||||||
|
const ip = clientAddress || 'unknown';
|
||||||
|
if (!checkRateLimit(ip)) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: 'Too many requests' }),
|
||||||
|
{ status: 429, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let body: any = {};
|
||||||
|
const text = await request.text();
|
||||||
|
if (text) {
|
||||||
|
body = JSON.parse(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { sessionId, essential, analytics, marketing, policyVersion, userAgent } = body;
|
||||||
|
|
||||||
|
if (!sessionId || essential === undefined || !policyVersion) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: 'Missing required fields' }),
|
||||||
|
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = getDb();
|
||||||
|
const ipHash = await hashIP(ip);
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
|
||||||
|
const stmt = db.prepare(`
|
||||||
|
INSERT INTO ConsentLog (sessionId, timestamp, essential, analytics, marketing, policyVersion, ipHash, userAgent)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`);
|
||||||
|
|
||||||
|
stmt.run(sessionId, timestamp, essential ? 1 : 0, analytics ? 1 : 0, marketing ? 1 : 0, policyVersion, ipHash, userAgent || 'unknown');
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ success: true, sessionId, message: 'Consent logged' }),
|
||||||
|
{ status: 201, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error logging consent:', error);
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: 'Failed to log consent' }),
|
||||||
|
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GET: APIRoute = () => {
|
export const GET: APIRoute = async () => {
|
||||||
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
|
try {
|
||||||
status: 405,
|
const db = getDb();
|
||||||
headers: { 'Content-Type': 'application/json', 'Allow': 'POST' },
|
const stmt = db.prepare('SELECT * FROM ConsentLog ORDER BY timestamp DESC LIMIT 100');
|
||||||
});
|
const logs = stmt.all();
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
const formattedLogs = logs.map((log: any) => ({
|
||||||
|
...log,
|
||||||
|
essential: log.essential === 1,
|
||||||
|
analytics: log.analytics === 1,
|
||||||
|
marketing: log.marketing === 1
|
||||||
|
}));
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ logs: formattedLogs, message: 'Success' }),
|
||||||
|
{ status: 200, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching logs:', error);
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ logs: [], error: 'Failed to fetch logs' }),
|
||||||
|
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user