diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..272c111 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +node_modules +.next +.next_old +.next_old/* +.git +.gitignore +.github +.vscode +.idea +docs +nginx +scripts/dev-scripts-*.sh +*.log +*.md +!vitest.config.ts +.env +.env.local +.env*.local +coverage +*.tsbuildinfo +tt.md +Dockerfile +Dockerfile.dev +docker-compose.yaml +docker-compose.dev.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d0e7720 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + branches: [main, admin] + pull_request: + branches: [main, admin] + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 15 + + env: + ADMIN_SESSION_SECRET: ${{ secrets.ADMIN_SESSION_SECRET || '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' }} + SUPER_ADMIN_USERNAME: super + SUPER_ADMIN_PASSWORD_HASH: ${{ secrets.SUPER_ADMIN_PASSWORD_HASH || '$2a$12$abcdefghijklmnopqrstuv' }} + DATABASE_URL: postgresql://postgres:postgres@localhost:5432/ci + NEXT_PUBLIC_APP_DOMAIN: ci.test + NEXT_PUBLIC_APP_URL: https://ci.test + NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: pk_test_placeholder + CLERK_SECRET_KEY: sk_test_placeholder + S3_ENDPOINT: https://s3.example.com + S3_REGION: eu-2 + S3_ACCESS_KEY_ID: placeholder + S3_SECRET_ACCESS_KEY: placeholder + S3_BUCKET_NAME: ci-bucket + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Generate Prisma client + run: npx prisma generate + + - name: Typecheck + run: npm run typecheck + + - name: Lint + run: npm run lint + continue-on-error: true + + - name: Tests + run: npm test + + - name: Build + run: npm run build diff --git a/.gitignore b/.gitignore index b35bd8a..5e15651 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ yarn-error.log* next-env.d.ts # docker -certbot/.next_old/ +/.next_old/ diff --git a/.next_old/cache/webpack/client-development/0.pack.gz b/.next_old/cache/webpack/client-development/0.pack.gz deleted file mode 100644 index bd226ec..0000000 Binary files a/.next_old/cache/webpack/client-development/0.pack.gz and /dev/null differ diff --git a/.next_old/cache/webpack/client-development/1.pack.gz_ b/.next_old/cache/webpack/client-development/1.pack.gz_ deleted file mode 100644 index b8e0a39..0000000 Binary files a/.next_old/cache/webpack/client-development/1.pack.gz_ and /dev/null differ diff --git a/.next_old/cache/webpack/client-development/3.pack.gz_ b/.next_old/cache/webpack/client-development/3.pack.gz_ deleted file mode 100644 index 02e4146..0000000 Binary files a/.next_old/cache/webpack/client-development/3.pack.gz_ and /dev/null differ diff --git a/.next_old/cache/webpack/client-development/4.pack.gz_ b/.next_old/cache/webpack/client-development/4.pack.gz_ deleted file mode 100644 index cb14e17..0000000 Binary files a/.next_old/cache/webpack/client-development/4.pack.gz_ and /dev/null differ diff --git a/.next_old/cache/webpack/client-development/index.pack.gz b/.next_old/cache/webpack/client-development/index.pack.gz deleted file mode 100644 index e3d4a94..0000000 Binary files a/.next_old/cache/webpack/client-development/index.pack.gz and /dev/null differ diff --git a/.next_old/cache/webpack/edge-server-development/3.pack.gz_ b/.next_old/cache/webpack/edge-server-development/3.pack.gz_ deleted file mode 100644 index e54ad70..0000000 Binary files a/.next_old/cache/webpack/edge-server-development/3.pack.gz_ and /dev/null differ diff --git a/.next_old/cache/webpack/server-development/6.pack.gz_ b/.next_old/cache/webpack/server-development/6.pack.gz_ deleted file mode 100644 index b733f5e..0000000 Binary files a/.next_old/cache/webpack/server-development/6.pack.gz_ and /dev/null differ diff --git a/.next_old/server/static/webpack/57c1a1c3af9932d9.edge-runtime-webpack.hot-update.json b/.next_old/server/static/webpack/57c1a1c3af9932d9.edge-runtime-webpack.hot-update.json deleted file mode 100644 index 1f699c2..0000000 --- a/.next_old/server/static/webpack/57c1a1c3af9932d9.edge-runtime-webpack.hot-update.json +++ /dev/null @@ -1 +0,0 @@ -{"c":["middleware","edge-runtime-webpack"],"r":[],"m":[]} \ No newline at end of file diff --git a/.next_old/server/static/webpack/8aa9df7462bda35c.edge-runtime-webpack.hot-update.json b/.next_old/server/static/webpack/8aa9df7462bda35c.edge-runtime-webpack.hot-update.json deleted file mode 100644 index 53c9122..0000000 --- a/.next_old/server/static/webpack/8aa9df7462bda35c.edge-runtime-webpack.hot-update.json +++ /dev/null @@ -1 +0,0 @@ -{"c":["middleware","edge-runtime-webpack"],"r":[],"m":["crypto"]} \ No newline at end of file diff --git a/.next_old/server/static/webpack/edge-runtime-webpack.57c1a1c3af9932d9.hot-update.js b/.next_old/server/static/webpack/edge-runtime-webpack.57c1a1c3af9932d9.hot-update.js deleted file mode 100644 index ded0a18..0000000 --- a/.next_old/server/static/webpack/edge-runtime-webpack.57c1a1c3af9932d9.hot-update.js +++ /dev/null @@ -1,18 +0,0 @@ -"use strict"; -/* - * ATTENTION: An "eval-source-map" devtool has been used. - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -self["webpackHotUpdate_N_E"]("edge-runtime-webpack",{}, -/******/ function(__webpack_require__) { // webpackRuntimeModules -/******/ /* webpack/runtime/getFullHash */ -/******/ (() => { -/******/ __webpack_require__.h = () => ("4f7aad26b0af8eaa") -/******/ })(); -/******/ -/******/ } -); \ No newline at end of file diff --git a/.next_old/server/static/webpack/edge-runtime-webpack.8aa9df7462bda35c.hot-update.js b/.next_old/server/static/webpack/edge-runtime-webpack.8aa9df7462bda35c.hot-update.js deleted file mode 100644 index 34562db..0000000 --- a/.next_old/server/static/webpack/edge-runtime-webpack.8aa9df7462bda35c.hot-update.js +++ /dev/null @@ -1,18 +0,0 @@ -"use strict"; -/* - * ATTENTION: An "eval-source-map" devtool has been used. - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -self["webpackHotUpdate_N_E"]("edge-runtime-webpack",{}, -/******/ function(__webpack_require__) { // webpackRuntimeModules -/******/ /* webpack/runtime/getFullHash */ -/******/ (() => { -/******/ __webpack_require__.h = () => ("57c1a1c3af9932d9") -/******/ })(); -/******/ -/******/ } -); \ No newline at end of file diff --git a/.next_old/server/static/webpack/middleware.57c1a1c3af9932d9.hot-update.js b/.next_old/server/static/webpack/middleware.57c1a1c3af9932d9.hot-update.js deleted file mode 100644 index 4775075..0000000 --- a/.next_old/server/static/webpack/middleware.57c1a1c3af9932d9.hot-update.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -/* - * ATTENTION: An "eval-source-map" devtool has been used. - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -self["webpackHotUpdate_N_E"]("middleware",{ - -/***/ "(middleware)/./src/middleware.ts": -/*!***************************!*\ - !*** ./src/middleware.ts ***! - \***************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ config: () => (/* binding */ config),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _clerk_nextjs_server__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @clerk/nextjs/server */ \"(middleware)/./node_modules/@clerk/nextjs/dist/esm/server/routeMatcher.js\");\n/* harmony import */ var _clerk_nextjs_server__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @clerk/nextjs/server */ \"(middleware)/./node_modules/@clerk/nextjs/dist/esm/server/clerkMiddleware.js\");\n/* harmony import */ var next_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! next/server */ \"(middleware)/./node_modules/next/dist/esm/api/server.js\");\n/* harmony import */ var _lib_admin_session__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/lib/admin-session */ \"(middleware)/./src/lib/admin-session.ts\");\n\n\n\nconst isProtectedRoute = (0,_clerk_nextjs_server__WEBPACK_IMPORTED_MODULE_2__.createRouteMatcher)([\n \"/dashboard(.*)\",\n \"/onboarding(.*)\",\n \"/api/publish(.*)\",\n \"/api/upload(.*)\",\n \"/api/user(.*)\"\n]);\nfunction isAdminRoute(pathname) {\n return pathname.startsWith(\"/admin\") || pathname.startsWith(\"/api/admin\");\n}\nfunction getSubdomain(req) {\n const host = req.headers.get(\"host\");\n if (!host) return null;\n const apex = \"testbed.mk\" || 0;\n const portIndex = host.indexOf(\":\");\n const hostname = portIndex !== -1 ? host.slice(0, portIndex) : host;\n const reserved = [\n \"www\",\n \"coolify\",\n \"mail\",\n \"accounts\",\n \"clerk\",\n \"clk\",\n \"clk2\",\n \"clkmail\"\n ];\n if (hostname === apex || reserved.includes(hostname) || hostname === `www.${apex}`) return null;\n if (hostname.endsWith(`.${apex}`)) {\n const sub = hostname.slice(0, hostname.length - apex.length - 1);\n if (sub && !reserved.includes(sub)) return sub;\n }\n return null;\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,_clerk_nextjs_server__WEBPACK_IMPORTED_MODULE_3__.clerkMiddleware)(async (auth, req)=>{\n if (isAdminRoute(req.nextUrl.pathname)) {\n if (req.nextUrl.pathname === \"/admin/login\") {\n return next_server__WEBPACK_IMPORTED_MODULE_0__.NextResponse.next();\n }\n const token = req.cookies.get(_lib_admin_session__WEBPACK_IMPORTED_MODULE_1__.COOKIE_NAME_ADMIN)?.value;\n if (!token || !await (0,_lib_admin_session__WEBPACK_IMPORTED_MODULE_1__.verifyAdminSession)(token)) {\n if (req.nextUrl.pathname.startsWith(\"/api/\")) {\n return next_server__WEBPACK_IMPORTED_MODULE_0__.NextResponse.json({\n error: \"Неавторизирано\"\n }, {\n status: 401\n });\n }\n return next_server__WEBPACK_IMPORTED_MODULE_0__.NextResponse.redirect(new URL(\"/admin/login\", req.url));\n }\n return next_server__WEBPACK_IMPORTED_MODULE_0__.NextResponse.next();\n }\n if (isProtectedRoute(req)) {\n await auth.protect();\n }\n const subdomain = getSubdomain(req);\n if (subdomain && !req.nextUrl.pathname.startsWith(\"/api\")) {\n const url = req.nextUrl.clone();\n url.pathname = `/${subdomain}${url.pathname === \"/\" ? \"\" : url.pathname}`;\n return next_server__WEBPACK_IMPORTED_MODULE_0__.NextResponse.rewrite(url);\n }\n return next_server__WEBPACK_IMPORTED_MODULE_0__.NextResponse.next();\n}));\nconst config = {\n matcher: [\n \"/(api|trpc)(.*)\",\n \"/__clerk/:path*\",\n \"/((?!_next|api/static|.*\\\\..*).*)\"\n ]\n};\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKG1pZGRsZXdhcmUpLy4vc3JjL21pZGRsZXdhcmUudHMiLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQTJFO0FBQ2hDO0FBRWlDO0FBRTVFLE1BQU1LLG1CQUFtQkosd0VBQWtCQSxDQUFDO0lBQUM7SUFBa0I7SUFBbUI7SUFBb0I7SUFBbUI7Q0FBZ0I7QUFFekksU0FBU0ssYUFBYUMsUUFBZ0I7SUFDcEMsT0FBT0EsU0FBU0MsVUFBVSxDQUFDLGFBQWFELFNBQVNDLFVBQVUsQ0FBQztBQUM5RDtBQUVBLFNBQVNDLGFBQWFDLEdBQWdCO0lBQ3BDLE1BQU1DLE9BQU9ELElBQUlFLE9BQU8sQ0FBQ0MsR0FBRyxDQUFDO0lBQzdCLElBQUksQ0FBQ0YsTUFBTSxPQUFPO0lBRWxCLE1BQU1HLE9BQU9DLFlBQWtDLElBQUksQ0FBWTtJQUMvRCxNQUFNRyxZQUFZUCxLQUFLUSxPQUFPLENBQUM7SUFDL0IsTUFBTUMsV0FBV0YsY0FBYyxDQUFDLElBQUlQLEtBQUtVLEtBQUssQ0FBQyxHQUFHSCxhQUFhUDtJQUUvRCxNQUFNVyxXQUFXO1FBQUM7UUFBTztRQUFXO1FBQVE7UUFBWTtRQUFTO1FBQU87UUFBUTtLQUFVO0lBRTFGLElBQUlGLGFBQWFOLFFBQVFRLFNBQVNDLFFBQVEsQ0FBQ0gsYUFBYUEsYUFBYSxDQUFDLElBQUksRUFBRU4sTUFBTSxFQUFFLE9BQU87SUFFM0YsSUFBSU0sU0FBU0ksUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFVixNQUFNLEdBQUc7UUFDakMsTUFBTVcsTUFBTUwsU0FBU0MsS0FBSyxDQUFDLEdBQUdELFNBQVNNLE1BQU0sR0FBR1osS0FBS1ksTUFBTSxHQUFHO1FBQzlELElBQUlELE9BQU8sQ0FBQ0gsU0FBU0MsUUFBUSxDQUFDRSxNQUFNLE9BQU9BO0lBQzdDO0lBRUEsT0FBTztBQUNUO0FBRUEsaUVBQWV6QixxRUFBZUEsQ0FBQyxPQUFPMkIsTUFBTWpCO0lBQzFDLElBQUlKLGFBQWFJLElBQUlrQixPQUFPLENBQUNyQixRQUFRLEdBQUc7UUFDdEMsSUFBSUcsSUFBSWtCLE9BQU8sQ0FBQ3JCLFFBQVEsS0FBSyxnQkFBZ0I7WUFDM0MsT0FBT0wscURBQVlBLENBQUMyQixJQUFJO1FBQzFCO1FBRUEsTUFBTUMsUUFBUXBCLElBQUlxQixPQUFPLENBQUNsQixHQUFHLENBQUNULGlFQUFpQkEsR0FBRzRCO1FBQ2xELElBQUksQ0FBQ0YsU0FBUyxDQUFFLE1BQU0zQixzRUFBa0JBLENBQUMyQixRQUFTO1lBQ2hELElBQUlwQixJQUFJa0IsT0FBTyxDQUFDckIsUUFBUSxDQUFDQyxVQUFVLENBQUMsVUFBVTtnQkFDNUMsT0FBT04scURBQVlBLENBQUMrQixJQUFJLENBQUM7b0JBQUVDLE9BQU87Z0JBQWlCLEdBQUc7b0JBQUVDLFFBQVE7Z0JBQUk7WUFDdEU7WUFDQSxPQUFPakMscURBQVlBLENBQUNrQyxRQUFRLENBQUMsSUFBSUMsSUFBSSxnQkFBZ0IzQixJQUFJNEIsR0FBRztRQUM5RDtRQUVBLE9BQU9wQyxxREFBWUEsQ0FBQzJCLElBQUk7SUFDMUI7SUFFQSxJQUFJeEIsaUJBQWlCSyxNQUFNO1FBQ3pCLE1BQU1pQixLQUFLWSxPQUFPO0lBQ3BCO0lBRUEsTUFBTUMsWUFBWS9CLGFBQWFDO0lBQy9CLElBQUk4QixhQUFhLENBQUM5QixJQUFJa0IsT0FBTyxDQUFDckIsUUFBUSxDQUFDQyxVQUFVLENBQUMsU0FBUztRQUN6RCxNQUFNOEIsTUFBTTVCLElBQUlrQixPQUFPLENBQUNhLEtBQUs7UUFDN0JILElBQUkvQixRQUFRLEdBQUcsQ0FBQyxDQUFDLEVBQUVpQyxZQUFZRixJQUFJL0IsUUFBUSxLQUFLLE1BQU0sS0FBSytCLElBQUkvQixRQUFRLEVBQUU7UUFDekUsT0FBT0wscURBQVlBLENBQUN3QyxPQUFPLENBQUNKO0lBQzlCO0lBRUEsT0FBT3BDLHFEQUFZQSxDQUFDMkIsSUFBSTtBQUMxQixFQUFFLEVBQUM7QUFFSSxNQUFNYyxTQUFTO0lBQ3BCQyxTQUFTO1FBQUM7UUFBbUI7UUFBbUI7S0FBb0M7QUFDdEYsRUFBRSIsInNvdXJjZXMiOlsiL2FwcC9zcmMvbWlkZGxld2FyZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjbGVya01pZGRsZXdhcmUsIGNyZWF0ZVJvdXRlTWF0Y2hlciB9IGZyb20gXCJAY2xlcmsvbmV4dGpzL3NlcnZlclwiO1xuaW1wb3J0IHsgTmV4dFJlc3BvbnNlIH0gZnJvbSBcIm5leHQvc2VydmVyXCI7XG5pbXBvcnQgdHlwZSB7IE5leHRSZXF1ZXN0IH0gZnJvbSBcIm5leHQvc2VydmVyXCI7XG5pbXBvcnQgeyB2ZXJpZnlBZG1pblNlc3Npb24sIENPT0tJRV9OQU1FX0FETUlOIH0gZnJvbSBcIkAvbGliL2FkbWluLXNlc3Npb25cIjtcblxuY29uc3QgaXNQcm90ZWN0ZWRSb3V0ZSA9IGNyZWF0ZVJvdXRlTWF0Y2hlcihbXCIvZGFzaGJvYXJkKC4qKVwiLCBcIi9vbmJvYXJkaW5nKC4qKVwiLCBcIi9hcGkvcHVibGlzaCguKilcIiwgXCIvYXBpL3VwbG9hZCguKilcIiwgXCIvYXBpL3VzZXIoLiopXCJdKTtcblxuZnVuY3Rpb24gaXNBZG1pblJvdXRlKHBhdGhuYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHBhdGhuYW1lLnN0YXJ0c1dpdGgoXCIvYWRtaW5cIikgfHwgcGF0aG5hbWUuc3RhcnRzV2l0aChcIi9hcGkvYWRtaW5cIik7XG59XG5cbmZ1bmN0aW9uIGdldFN1YmRvbWFpbihyZXE6IE5leHRSZXF1ZXN0KTogc3RyaW5nIHwgbnVsbCB7XG4gIGNvbnN0IGhvc3QgPSByZXEuaGVhZGVycy5nZXQoXCJob3N0XCIpO1xuICBpZiAoIWhvc3QpIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IGFwZXggPSBwcm9jZXNzLmVudi5ORVhUX1BVQkxJQ19BUFBfRE9NQUlOIHx8IFwidGVzdGJlZC5ta1wiO1xuICBjb25zdCBwb3J0SW5kZXggPSBob3N0LmluZGV4T2YoXCI6XCIpO1xuICBjb25zdCBob3N0bmFtZSA9IHBvcnRJbmRleCAhPT0gLTEgPyBob3N0LnNsaWNlKDAsIHBvcnRJbmRleCkgOiBob3N0O1xuXG4gIGNvbnN0IHJlc2VydmVkID0gW1wid3d3XCIsIFwiY29vbGlmeVwiLCBcIm1haWxcIiwgXCJhY2NvdW50c1wiLCBcImNsZXJrXCIsIFwiY2xrXCIsIFwiY2xrMlwiLCBcImNsa21haWxcIl07XG5cbiAgaWYgKGhvc3RuYW1lID09PSBhcGV4IHx8IHJlc2VydmVkLmluY2x1ZGVzKGhvc3RuYW1lKSB8fCBob3N0bmFtZSA9PT0gYHd3dy4ke2FwZXh9YCkgcmV0dXJuIG51bGw7XG5cbiAgaWYgKGhvc3RuYW1lLmVuZHNXaXRoKGAuJHthcGV4fWApKSB7XG4gICAgY29uc3Qgc3ViID0gaG9zdG5hbWUuc2xpY2UoMCwgaG9zdG5hbWUubGVuZ3RoIC0gYXBleC5sZW5ndGggLSAxKTtcbiAgICBpZiAoc3ViICYmICFyZXNlcnZlZC5pbmNsdWRlcyhzdWIpKSByZXR1cm4gc3ViO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsZXJrTWlkZGxld2FyZShhc3luYyAoYXV0aCwgcmVxOiBOZXh0UmVxdWVzdCkgPT4ge1xuICBpZiAoaXNBZG1pblJvdXRlKHJlcS5uZXh0VXJsLnBhdGhuYW1lKSkge1xuICAgIGlmIChyZXEubmV4dFVybC5wYXRobmFtZSA9PT0gXCIvYWRtaW4vbG9naW5cIikge1xuICAgICAgcmV0dXJuIE5leHRSZXNwb25zZS5uZXh0KCk7XG4gICAgfVxuXG4gICAgY29uc3QgdG9rZW4gPSByZXEuY29va2llcy5nZXQoQ09PS0lFX05BTUVfQURNSU4pPy52YWx1ZTtcbiAgICBpZiAoIXRva2VuIHx8ICEoYXdhaXQgdmVyaWZ5QWRtaW5TZXNzaW9uKHRva2VuKSkpIHtcbiAgICAgIGlmIChyZXEubmV4dFVybC5wYXRobmFtZS5zdGFydHNXaXRoKFwiL2FwaS9cIikpIHtcbiAgICAgICAgcmV0dXJuIE5leHRSZXNwb25zZS5qc29uKHsgZXJyb3I6IFwi0J3QtdCw0LLRgtC+0YDQuNC30LjRgNCw0L3QvlwiIH0sIHsgc3RhdHVzOiA0MDEgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gTmV4dFJlc3BvbnNlLnJlZGlyZWN0KG5ldyBVUkwoXCIvYWRtaW4vbG9naW5cIiwgcmVxLnVybCkpO1xuICAgIH1cblxuICAgIHJldHVybiBOZXh0UmVzcG9uc2UubmV4dCgpO1xuICB9XG5cbiAgaWYgKGlzUHJvdGVjdGVkUm91dGUocmVxKSkge1xuICAgIGF3YWl0IGF1dGgucHJvdGVjdCgpO1xuICB9XG5cbiAgY29uc3Qgc3ViZG9tYWluID0gZ2V0U3ViZG9tYWluKHJlcSk7XG4gIGlmIChzdWJkb21haW4gJiYgIXJlcS5uZXh0VXJsLnBhdGhuYW1lLnN0YXJ0c1dpdGgoXCIvYXBpXCIpKSB7XG4gICAgY29uc3QgdXJsID0gcmVxLm5leHRVcmwuY2xvbmUoKTtcbiAgICB1cmwucGF0aG5hbWUgPSBgLyR7c3ViZG9tYWlufSR7dXJsLnBhdGhuYW1lID09PSBcIi9cIiA/IFwiXCIgOiB1cmwucGF0aG5hbWV9YDtcbiAgICByZXR1cm4gTmV4dFJlc3BvbnNlLnJld3JpdGUodXJsKTtcbiAgfVxuXG4gIHJldHVybiBOZXh0UmVzcG9uc2UubmV4dCgpO1xufSk7XG5cbmV4cG9ydCBjb25zdCBjb25maWcgPSB7XG4gIG1hdGNoZXI6IFtcIi8oYXBpfHRycGMpKC4qKVwiLCBcIi9fX2NsZXJrLzpwYXRoKlwiLCBcIi8oKD8hX25leHR8YXBpL3N0YXRpY3wuKlxcXFwuLiopLiopXCJdLFxufTtcbiJdLCJuYW1lcyI6WyJjbGVya01pZGRsZXdhcmUiLCJjcmVhdGVSb3V0ZU1hdGNoZXIiLCJOZXh0UmVzcG9uc2UiLCJ2ZXJpZnlBZG1pblNlc3Npb24iLCJDT09LSUVfTkFNRV9BRE1JTiIsImlzUHJvdGVjdGVkUm91dGUiLCJpc0FkbWluUm91dGUiLCJwYXRobmFtZSIsInN0YXJ0c1dpdGgiLCJnZXRTdWJkb21haW4iLCJyZXEiLCJob3N0IiwiaGVhZGVycyIsImdldCIsImFwZXgiLCJwcm9jZXNzIiwiZW52IiwiTkVYVF9QVUJMSUNfQVBQX0RPTUFJTiIsInBvcnRJbmRleCIsImluZGV4T2YiLCJob3N0bmFtZSIsInNsaWNlIiwicmVzZXJ2ZWQiLCJpbmNsdWRlcyIsImVuZHNXaXRoIiwic3ViIiwibGVuZ3RoIiwiYXV0aCIsIm5leHRVcmwiLCJuZXh0IiwidG9rZW4iLCJjb29raWVzIiwidmFsdWUiLCJqc29uIiwiZXJyb3IiLCJzdGF0dXMiLCJyZWRpcmVjdCIsIlVSTCIsInVybCIsInByb3RlY3QiLCJzdWJkb21haW4iLCJjbG9uZSIsInJld3JpdGUiLCJjb25maWciLCJtYXRjaGVyIl0sImlnbm9yZUxpc3QiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///(middleware)/./src/middleware.ts\n"); - -/***/ }) - -}); \ No newline at end of file diff --git a/.next_old/server/static/webpack/middleware.8aa9df7462bda35c.hot-update.js b/.next_old/server/static/webpack/middleware.8aa9df7462bda35c.hot-update.js deleted file mode 100644 index 4d77b42..0000000 --- a/.next_old/server/static/webpack/middleware.8aa9df7462bda35c.hot-update.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -/* - * ATTENTION: An "eval-source-map" devtool has been used. - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -self["webpackHotUpdate_N_E"]("middleware",{ - -/***/ "(middleware)/./src/lib/admin-session.ts": -/*!**********************************!*\ - !*** ./src/lib/admin-session.ts ***! - \**********************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ COOKIE_NAME_ADMIN: () => (/* binding */ COOKIE_NAME_ADMIN),\n/* harmony export */ cookieOptions: () => (/* binding */ cookieOptions),\n/* harmony export */ createAdminSession: () => (/* binding */ createAdminSession),\n/* harmony export */ getAdminSession: () => (/* binding */ getAdminSession),\n/* harmony export */ verifyAdminSession: () => (/* binding */ verifyAdminSession)\n/* harmony export */ });\n/* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! next/headers */ \"(middleware)/./node_modules/next/dist/esm/api/headers.js\");\n\nconst COOKIE_NAME = \"admin_session\";\nconst SEP = \".\";\nfunction getSecret() {\n const secret = process.env.ADMIN_SESSION_SECRET;\n if (!secret) throw new Error(\"ADMIN_SESSION_SECRET env var is not set\");\n return secret;\n}\nasync function sign(payload) {\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\"raw\", encoder.encode(getSecret()), {\n name: \"HMAC\",\n hash: \"SHA-256\"\n }, false, [\n \"sign\"\n ]);\n const sig = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(payload));\n return btoa(String.fromCharCode(...new Uint8Array(sig)));\n}\nasync function createAdminSession(data) {\n const payload = btoa(JSON.stringify(data));\n return payload + SEP + await sign(payload);\n}\nasync function verifyAdminSession(token) {\n const sepIdx = token.lastIndexOf(SEP);\n if (sepIdx === -1) return null;\n const payload = token.slice(0, sepIdx);\n const sig = token.slice(sepIdx + 1);\n const expectedSig = await sign(payload);\n if (sig.length !== expectedSig.length) return null;\n try {\n if (!constantTimeEqual(sig, expectedSig)) return null;\n } catch {\n return null;\n }\n try {\n return JSON.parse(atob(payload));\n } catch {\n return null;\n }\n}\nfunction constantTimeEqual(a, b) {\n if (a.length !== b.length) return false;\n let result = 0;\n for(let i = 0; i < a.length; i++){\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n}\nconst COOKIE_NAME_ADMIN = COOKIE_NAME;\nfunction cookieOptions(value) {\n return {\n name: COOKIE_NAME,\n value,\n httpOnly: true,\n secure: \"development\" === \"production\",\n sameSite: \"lax\",\n path: \"/admin\"\n };\n}\nasync function getAdminSession() {\n const store = await (0,next_headers__WEBPACK_IMPORTED_MODULE_0__.cookies)();\n const token = store.get(COOKIE_NAME)?.value;\n if (!token) return null;\n return verifyAdminSession(token);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKG1pZGRsZXdhcmUpLy4vc3JjL2xpYi9hZG1pbi1zZXNzaW9uLnRzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUF1QztBQUV2QyxNQUFNQyxjQUFjO0FBQ3BCLE1BQU1DLE1BQU07QUFFWixTQUFTQztJQUNQLE1BQU1DLFNBQVNDLFFBQVFDLEdBQUcsQ0FBQ0Msb0JBQW9CO0lBQy9DLElBQUksQ0FBQ0gsUUFBUSxNQUFNLElBQUlJLE1BQU07SUFDN0IsT0FBT0o7QUFDVDtBQUVBLGVBQWVLLEtBQUtDLE9BQWU7SUFDakMsTUFBTUMsVUFBVSxJQUFJQztJQUNwQixNQUFNQyxNQUFNLE1BQU1DLE9BQU9DLE1BQU0sQ0FBQ0MsU0FBUyxDQUN2QyxPQUNBTCxRQUFRTSxNQUFNLENBQUNkLGNBQ2Y7UUFBRWUsTUFBTTtRQUFRQyxNQUFNO0lBQVUsR0FDaEMsT0FDQTtRQUFDO0tBQU87SUFFVixNQUFNQyxNQUFNLE1BQU1OLE9BQU9DLE1BQU0sQ0FBQ04sSUFBSSxDQUFDLFFBQVFJLEtBQUtGLFFBQVFNLE1BQU0sQ0FBQ1A7SUFDakUsT0FBT1csS0FBS0MsT0FBT0MsWUFBWSxJQUFJLElBQUlDLFdBQVdKO0FBQ3BEO0FBT08sZUFBZUssbUJBQW1CQyxJQUFrQjtJQUN6RCxNQUFNaEIsVUFBVVcsS0FBS00sS0FBS0MsU0FBUyxDQUFDRjtJQUNwQyxPQUFPaEIsVUFBVVIsTUFBTyxNQUFNTyxLQUFLQztBQUNyQztBQUVPLGVBQWVtQixtQkFBbUJDLEtBQWE7SUFDcEQsTUFBTUMsU0FBU0QsTUFBTUUsV0FBVyxDQUFDOUI7SUFDakMsSUFBSTZCLFdBQVcsQ0FBQyxHQUFHLE9BQU87SUFDMUIsTUFBTXJCLFVBQVVvQixNQUFNRyxLQUFLLENBQUMsR0FBR0Y7SUFDL0IsTUFBTVgsTUFBTVUsTUFBTUcsS0FBSyxDQUFDRixTQUFTO0lBQ2pDLE1BQU1HLGNBQWMsTUFBTXpCLEtBQUtDO0lBQy9CLElBQUlVLElBQUllLE1BQU0sS0FBS0QsWUFBWUMsTUFBTSxFQUFFLE9BQU87SUFDOUMsSUFBSTtRQUNGLElBQUksQ0FBQ0Msa0JBQWtCaEIsS0FBS2MsY0FBYyxPQUFPO0lBQ25ELEVBQUUsT0FBTTtRQUNOLE9BQU87SUFDVDtJQUNBLElBQUk7UUFDRixPQUFPUCxLQUFLVSxLQUFLLENBQUNDLEtBQUs1QjtJQUN6QixFQUFFLE9BQU07UUFDTixPQUFPO0lBQ1Q7QUFDRjtBQUVBLFNBQVMwQixrQkFBa0JHLENBQVMsRUFBRUMsQ0FBUztJQUM3QyxJQUFJRCxFQUFFSixNQUFNLEtBQUtLLEVBQUVMLE1BQU0sRUFBRSxPQUFPO0lBQ2xDLElBQUlNLFNBQVM7SUFDYixJQUFLLElBQUlDLElBQUksR0FBR0EsSUFBSUgsRUFBRUosTUFBTSxFQUFFTyxJQUFLO1FBQ2pDRCxVQUFVRixFQUFFSSxVQUFVLENBQUNELEtBQUtGLEVBQUVHLFVBQVUsQ0FBQ0Q7SUFDM0M7SUFDQSxPQUFPRCxXQUFXO0FBQ3BCO0FBRU8sTUFBTUcsb0JBQW9CM0MsWUFBWTtBQUV0QyxTQUFTNEMsY0FBY0MsS0FBYTtJQUN6QyxPQUFPO1FBQ0w1QixNQUFNakI7UUFDTjZDO1FBQ0FDLFVBQVU7UUFDVkMsUUFBUTNDLGtCQUF5QjtRQUNqQzRDLFVBQVU7UUFDVkMsTUFBTTtJQUNSO0FBQ0Y7QUFFTyxlQUFlQztJQUNwQixNQUFNQyxRQUFRLE1BQU1wRCxxREFBT0E7SUFDM0IsTUFBTThCLFFBQVFzQixNQUFNQyxHQUFHLENBQUNwRCxjQUFjNkM7SUFDdEMsSUFBSSxDQUFDaEIsT0FBTyxPQUFPO0lBQ25CLE9BQU9ELG1CQUFtQkM7QUFDNUIiLCJzb3VyY2VzIjpbIi9hcHAvc3JjL2xpYi9hZG1pbi1zZXNzaW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNvb2tpZXMgfSBmcm9tIFwibmV4dC9oZWFkZXJzXCI7XG5cbmNvbnN0IENPT0tJRV9OQU1FID0gXCJhZG1pbl9zZXNzaW9uXCI7XG5jb25zdCBTRVAgPSBcIi5cIjtcblxuZnVuY3Rpb24gZ2V0U2VjcmV0KCk6IHN0cmluZyB7XG4gIGNvbnN0IHNlY3JldCA9IHByb2Nlc3MuZW52LkFETUlOX1NFU1NJT05fU0VDUkVUO1xuICBpZiAoIXNlY3JldCkgdGhyb3cgbmV3IEVycm9yKFwiQURNSU5fU0VTU0lPTl9TRUNSRVQgZW52IHZhciBpcyBub3Qgc2V0XCIpO1xuICByZXR1cm4gc2VjcmV0O1xufVxuXG5hc3luYyBmdW5jdGlvbiBzaWduKHBheWxvYWQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IGVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgY29uc3Qga2V5ID0gYXdhaXQgY3J5cHRvLnN1YnRsZS5pbXBvcnRLZXkoXG4gICAgXCJyYXdcIixcbiAgICBlbmNvZGVyLmVuY29kZShnZXRTZWNyZXQoKSksXG4gICAgeyBuYW1lOiBcIkhNQUNcIiwgaGFzaDogXCJTSEEtMjU2XCIgfSxcbiAgICBmYWxzZSxcbiAgICBbXCJzaWduXCJdLFxuICApO1xuICBjb25zdCBzaWcgPSBhd2FpdCBjcnlwdG8uc3VidGxlLnNpZ24oXCJITUFDXCIsIGtleSwgZW5jb2Rlci5lbmNvZGUocGF5bG9hZCkpO1xuICByZXR1cm4gYnRvYShTdHJpbmcuZnJvbUNoYXJDb2RlKC4uLm5ldyBVaW50OEFycmF5KHNpZykpKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBZG1pblNlc3Npb24ge1xuICB1c2VybmFtZTogc3RyaW5nO1xuICByb2xlOiBcIlNVUEVSX0FETUlOXCIgfCBcIkFETUlOXCI7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVBZG1pblNlc3Npb24oZGF0YTogQWRtaW5TZXNzaW9uKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgcGF5bG9hZCA9IGJ0b2EoSlNPTi5zdHJpbmdpZnkoZGF0YSkpO1xuICByZXR1cm4gcGF5bG9hZCArIFNFUCArIChhd2FpdCBzaWduKHBheWxvYWQpKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHZlcmlmeUFkbWluU2Vzc2lvbih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxBZG1pblNlc3Npb24gfCBudWxsPiB7XG4gIGNvbnN0IHNlcElkeCA9IHRva2VuLmxhc3RJbmRleE9mKFNFUCk7XG4gIGlmIChzZXBJZHggPT09IC0xKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgcGF5bG9hZCA9IHRva2VuLnNsaWNlKDAsIHNlcElkeCk7XG4gIGNvbnN0IHNpZyA9IHRva2VuLnNsaWNlKHNlcElkeCArIDEpO1xuICBjb25zdCBleHBlY3RlZFNpZyA9IGF3YWl0IHNpZ24ocGF5bG9hZCk7XG4gIGlmIChzaWcubGVuZ3RoICE9PSBleHBlY3RlZFNpZy5sZW5ndGgpIHJldHVybiBudWxsO1xuICB0cnkge1xuICAgIGlmICghY29uc3RhbnRUaW1lRXF1YWwoc2lnLCBleHBlY3RlZFNpZykpIHJldHVybiBudWxsO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICB0cnkge1xuICAgIHJldHVybiBKU09OLnBhcnNlKGF0b2IocGF5bG9hZCkpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG5mdW5jdGlvbiBjb25zdGFudFRpbWVFcXVhbChhOiBzdHJpbmcsIGI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBpZiAoYS5sZW5ndGggIT09IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gIGxldCByZXN1bHQgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGEubGVuZ3RoOyBpKyspIHtcbiAgICByZXN1bHQgfD0gYS5jaGFyQ29kZUF0KGkpIF4gYi5jaGFyQ29kZUF0KGkpO1xuICB9XG4gIHJldHVybiByZXN1bHQgPT09IDA7XG59XG5cbmV4cG9ydCBjb25zdCBDT09LSUVfTkFNRV9BRE1JTiA9IENPT0tJRV9OQU1FO1xuXG5leHBvcnQgZnVuY3Rpb24gY29va2llT3B0aW9ucyh2YWx1ZTogc3RyaW5nKSB7XG4gIHJldHVybiB7XG4gICAgbmFtZTogQ09PS0lFX05BTUUsXG4gICAgdmFsdWUsXG4gICAgaHR0cE9ubHk6IHRydWUsXG4gICAgc2VjdXJlOiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gXCJwcm9kdWN0aW9uXCIsXG4gICAgc2FtZVNpdGU6IFwibGF4XCIgYXMgY29uc3QsXG4gICAgcGF0aDogXCIvYWRtaW5cIixcbiAgfTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEFkbWluU2Vzc2lvbigpOiBQcm9taXNlPEFkbWluU2Vzc2lvbiB8IG51bGw+IHtcbiAgY29uc3Qgc3RvcmUgPSBhd2FpdCBjb29raWVzKCk7XG4gIGNvbnN0IHRva2VuID0gc3RvcmUuZ2V0KENPT0tJRV9OQU1FKT8udmFsdWU7XG4gIGlmICghdG9rZW4pIHJldHVybiBudWxsO1xuICByZXR1cm4gdmVyaWZ5QWRtaW5TZXNzaW9uKHRva2VuKTtcbn1cbiJdLCJuYW1lcyI6WyJjb29raWVzIiwiQ09PS0lFX05BTUUiLCJTRVAiLCJnZXRTZWNyZXQiLCJzZWNyZXQiLCJwcm9jZXNzIiwiZW52IiwiQURNSU5fU0VTU0lPTl9TRUNSRVQiLCJFcnJvciIsInNpZ24iLCJwYXlsb2FkIiwiZW5jb2RlciIsIlRleHRFbmNvZGVyIiwia2V5IiwiY3J5cHRvIiwic3VidGxlIiwiaW1wb3J0S2V5IiwiZW5jb2RlIiwibmFtZSIsImhhc2giLCJzaWciLCJidG9hIiwiU3RyaW5nIiwiZnJvbUNoYXJDb2RlIiwiVWludDhBcnJheSIsImNyZWF0ZUFkbWluU2Vzc2lvbiIsImRhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwidmVyaWZ5QWRtaW5TZXNzaW9uIiwidG9rZW4iLCJzZXBJZHgiLCJsYXN0SW5kZXhPZiIsInNsaWNlIiwiZXhwZWN0ZWRTaWciLCJsZW5ndGgiLCJjb25zdGFudFRpbWVFcXVhbCIsInBhcnNlIiwiYXRvYiIsImEiLCJiIiwicmVzdWx0IiwiaSIsImNoYXJDb2RlQXQiLCJDT09LSUVfTkFNRV9BRE1JTiIsImNvb2tpZU9wdGlvbnMiLCJ2YWx1ZSIsImh0dHBPbmx5Iiwic2VjdXJlIiwic2FtZVNpdGUiLCJwYXRoIiwiZ2V0QWRtaW5TZXNzaW9uIiwic3RvcmUiLCJnZXQiXSwiaWdub3JlTGlzdCI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///(middleware)/./src/lib/admin-session.ts\n"); - -/***/ }) - -}); \ No newline at end of file diff --git a/.next_old/static/development/_buildManifest.js b/.next_old/static/development/_buildManifest.js deleted file mode 100644 index fda46a4..0000000 --- a/.next_old/static/development/_buildManifest.js +++ /dev/null @@ -1 +0,0 @@ -self.__BUILD_MANIFEST = (function(a){return {__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},__routerFilterStatic:a,__routerFilterDynamic:a,sortedPages:["\u002F_app"]}}(void 0));self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB() \ No newline at end of file diff --git a/.next_old/static/development/_ssgManifest.js b/.next_old/static/development/_ssgManifest.js deleted file mode 100644 index 2260768..0000000 --- a/.next_old/static/development/_ssgManifest.js +++ /dev/null @@ -1 +0,0 @@ -self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB() \ No newline at end of file diff --git a/.next_old/static/webpack/7595051f8d05b6c5.webpack.hot-update.json b/.next_old/static/webpack/7595051f8d05b6c5.webpack.hot-update.json deleted file mode 100644 index 5c82546..0000000 --- a/.next_old/static/webpack/7595051f8d05b6c5.webpack.hot-update.json +++ /dev/null @@ -1 +0,0 @@ -{"c":["app/layout","webpack"],"r":[],"m":[]} \ No newline at end of file diff --git a/.next_old/static/webpack/app/layout.7595051f8d05b6c5.hot-update.js b/.next_old/static/webpack/app/layout.7595051f8d05b6c5.hot-update.js deleted file mode 100644 index 8757775..0000000 --- a/.next_old/static/webpack/app/layout.7595051f8d05b6c5.hot-update.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -/* - * ATTENTION: An "eval-source-map" devtool has been used. - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -self["webpackHotUpdate_N_E"]("app/layout",{ - -/***/ "(app-pages-browser)/./src/app/globals.css": -/*!*****************************!*\ - !*** ./src/app/globals.css ***! - \*****************************/ -/***/ ((module, __webpack_exports__, __webpack_require__) => { - -eval(__webpack_require__.ts("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (\"b5a80c100df0\");\nif (true) { module.hot.accept() }\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKGFwcC1wYWdlcy1icm93c2VyKS8uL3NyYy9hcHAvZ2xvYmFscy5jc3MiLCJtYXBwaW5ncyI6Ijs7OztBQUFBLGlFQUFlLGNBQWM7QUFDN0IsSUFBSSxJQUFVLElBQUksaUJBQWlCIiwic291cmNlcyI6WyIvYXBwL3NyYy9hcHAvZ2xvYmFscy5jc3MiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGRlZmF1bHQgXCJiNWE4MGMxMDBkZjBcIlxuaWYgKG1vZHVsZS5ob3QpIHsgbW9kdWxlLmhvdC5hY2NlcHQoKSB9XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///(app-pages-browser)/./src/app/globals.css\n")); - -/***/ }) - -}); \ No newline at end of file diff --git a/.next_old/static/webpack/app/layout.b78eb0568bf98f77.hot-update.js b/.next_old/static/webpack/app/layout.b78eb0568bf98f77.hot-update.js deleted file mode 100644 index 3eb10d2..0000000 --- a/.next_old/static/webpack/app/layout.b78eb0568bf98f77.hot-update.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -/* - * ATTENTION: An "eval-source-map" devtool has been used. - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -self["webpackHotUpdate_N_E"]("app/layout",{ - -/***/ "(app-pages-browser)/./src/app/globals.css": -/*!*****************************!*\ - !*** ./src/app/globals.css ***! - \*****************************/ -/***/ ((module, __webpack_exports__, __webpack_require__) => { - -eval(__webpack_require__.ts("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (\"da0b7f42d544\");\nif (true) { module.hot.accept() }\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKGFwcC1wYWdlcy1icm93c2VyKS8uL3NyYy9hcHAvZ2xvYmFscy5jc3MiLCJtYXBwaW5ncyI6Ijs7OztBQUFBLGlFQUFlLGNBQWM7QUFDN0IsSUFBSSxJQUFVLElBQUksaUJBQWlCIiwic291cmNlcyI6WyIvYXBwL3NyYy9hcHAvZ2xvYmFscy5jc3MiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGRlZmF1bHQgXCJkYTBiN2Y0MmQ1NDRcIlxuaWYgKG1vZHVsZS5ob3QpIHsgbW9kdWxlLmhvdC5hY2NlcHQoKSB9XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///(app-pages-browser)/./src/app/globals.css\n")); - -/***/ }) - -}); \ No newline at end of file diff --git a/.next_old/static/webpack/app/layout.e3986117c9381609.hot-update.js b/.next_old/static/webpack/app/layout.e3986117c9381609.hot-update.js deleted file mode 100644 index fe1ab41..0000000 --- a/.next_old/static/webpack/app/layout.e3986117c9381609.hot-update.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -/* - * ATTENTION: An "eval-source-map" devtool has been used. - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -self["webpackHotUpdate_N_E"]("app/layout",{ - -/***/ "(app-pages-browser)/./src/app/globals.css": -/*!*****************************!*\ - !*** ./src/app/globals.css ***! - \*****************************/ -/***/ ((module, __webpack_exports__, __webpack_require__) => { - -eval(__webpack_require__.ts("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (\"cc1073572c60\");\nif (true) { module.hot.accept() }\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKGFwcC1wYWdlcy1icm93c2VyKS8uL3NyYy9hcHAvZ2xvYmFscy5jc3MiLCJtYXBwaW5ncyI6Ijs7OztBQUFBLGlFQUFlLGNBQWM7QUFDN0IsSUFBSSxJQUFVLElBQUksaUJBQWlCIiwic291cmNlcyI6WyIvYXBwL3NyYy9hcHAvZ2xvYmFscy5jc3MiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGRlZmF1bHQgXCJjYzEwNzM1NzJjNjBcIlxuaWYgKG1vZHVsZS5ob3QpIHsgbW9kdWxlLmhvdC5hY2NlcHQoKSB9XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///(app-pages-browser)/./src/app/globals.css\n")); - -/***/ }) - -}); \ No newline at end of file diff --git a/.next_old/static/webpack/b78eb0568bf98f77.webpack.hot-update.json b/.next_old/static/webpack/b78eb0568bf98f77.webpack.hot-update.json deleted file mode 100644 index 5c82546..0000000 --- a/.next_old/static/webpack/b78eb0568bf98f77.webpack.hot-update.json +++ /dev/null @@ -1 +0,0 @@ -{"c":["app/layout","webpack"],"r":[],"m":[]} \ No newline at end of file diff --git a/.next_old/static/webpack/e3986117c9381609.webpack.hot-update.json b/.next_old/static/webpack/e3986117c9381609.webpack.hot-update.json deleted file mode 100644 index 5c82546..0000000 --- a/.next_old/static/webpack/e3986117c9381609.webpack.hot-update.json +++ /dev/null @@ -1 +0,0 @@ -{"c":["app/layout","webpack"],"r":[],"m":[]} \ No newline at end of file diff --git a/.next_old/static/webpack/webpack.7595051f8d05b6c5.hot-update.js b/.next_old/static/webpack/webpack.7595051f8d05b6c5.hot-update.js deleted file mode 100644 index fc17d1d..0000000 --- a/.next_old/static/webpack/webpack.7595051f8d05b6c5.hot-update.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; -self["webpackHotUpdate_N_E"]("webpack",{}, -/******/ function(__webpack_require__) { // webpackRuntimeModules -/******/ /* webpack/runtime/getFullHash */ -/******/ (() => { -/******/ __webpack_require__.h = () => ("132a22e239466e3b") -/******/ })(); -/******/ -/******/ } -) -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJpZ25vcmVMaXN0IjpbMF0sIm1hcHBpbmdzIjoiQUFBQSIsInNvdXJjZXMiOlsid2VicGFjay1pbnRlcm5hbDovL25leHRqcy93ZWJwYWNrLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFRoaXMgc291cmNlIHdhcyBnZW5lcmF0ZWQgYnkgTmV4dC5qcyBiYXNlZCBvZmYgb2YgdGhlIGdlbmVyYXRlZCBXZWJwYWNrIHJ1bnRpbWUuXG4vLyBUaGUgbWFwcGluZ3MgYXJlIGluY29ycmVjdC5cbi8vIFRvIGdldCB0aGUgY29ycmVjdCBsaW5lL2NvbHVtbiBtYXBwaW5ncywgdHVybiBvZmYgc291cmNlbWFwcyBpbiB5b3VyIGRlYnVnZ2VyLlxuXG5zZWxmW1wid2VicGFja0hvdFVwZGF0ZV9OX0VcIl0oXCJ3ZWJwYWNrXCIse30sXG4vKioqKioqLyBmdW5jdGlvbihfX3dlYnBhY2tfcmVxdWlyZV9fKSB7IC8vIHdlYnBhY2tSdW50aW1lTW9kdWxlc1xuLyoqKioqKi8gLyogd2VicGFjay9ydW50aW1lL2dldEZ1bGxIYXNoICovXG4vKioqKioqLyAoKCkgPT4ge1xuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmggPSAoKSA9PiAoXCIxMzJhMjJlMjM5NDY2ZTNiXCIpXG4vKioqKioqLyB9KSgpO1xuLyoqKioqKi8gXG4vKioqKioqLyB9XG4pIl19 -; \ No newline at end of file diff --git a/.next_old/static/webpack/webpack.b78eb0568bf98f77.hot-update.js b/.next_old/static/webpack/webpack.b78eb0568bf98f77.hot-update.js deleted file mode 100644 index 84b77c2..0000000 --- a/.next_old/static/webpack/webpack.b78eb0568bf98f77.hot-update.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; -self["webpackHotUpdate_N_E"]("webpack",{}, -/******/ function(__webpack_require__) { // webpackRuntimeModules -/******/ /* webpack/runtime/getFullHash */ -/******/ (() => { -/******/ __webpack_require__.h = () => ("7595051f8d05b6c5") -/******/ })(); -/******/ -/******/ } -) -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJpZ25vcmVMaXN0IjpbMF0sIm1hcHBpbmdzIjoiQUFBQSIsInNvdXJjZXMiOlsid2VicGFjay1pbnRlcm5hbDovL25leHRqcy93ZWJwYWNrLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFRoaXMgc291cmNlIHdhcyBnZW5lcmF0ZWQgYnkgTmV4dC5qcyBiYXNlZCBvZmYgb2YgdGhlIGdlbmVyYXRlZCBXZWJwYWNrIHJ1bnRpbWUuXG4vLyBUaGUgbWFwcGluZ3MgYXJlIGluY29ycmVjdC5cbi8vIFRvIGdldCB0aGUgY29ycmVjdCBsaW5lL2NvbHVtbiBtYXBwaW5ncywgdHVybiBvZmYgc291cmNlbWFwcyBpbiB5b3VyIGRlYnVnZ2VyLlxuXG5zZWxmW1wid2VicGFja0hvdFVwZGF0ZV9OX0VcIl0oXCJ3ZWJwYWNrXCIse30sXG4vKioqKioqLyBmdW5jdGlvbihfX3dlYnBhY2tfcmVxdWlyZV9fKSB7IC8vIHdlYnBhY2tSdW50aW1lTW9kdWxlc1xuLyoqKioqKi8gLyogd2VicGFjay9ydW50aW1lL2dldEZ1bGxIYXNoICovXG4vKioqKioqLyAoKCkgPT4ge1xuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmggPSAoKSA9PiAoXCI3NTk1MDUxZjhkMDViNmM1XCIpXG4vKioqKioqLyB9KSgpO1xuLyoqKioqKi8gXG4vKioqKioqLyB9XG4pIl19 -; \ No newline at end of file diff --git a/.next_old/static/webpack/webpack.e3986117c9381609.hot-update.js b/.next_old/static/webpack/webpack.e3986117c9381609.hot-update.js deleted file mode 100644 index 9603c78..0000000 --- a/.next_old/static/webpack/webpack.e3986117c9381609.hot-update.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; -self["webpackHotUpdate_N_E"]("webpack",{}, -/******/ function(__webpack_require__) { // webpackRuntimeModules -/******/ /* webpack/runtime/getFullHash */ -/******/ (() => { -/******/ __webpack_require__.h = () => ("b78eb0568bf98f77") -/******/ })(); -/******/ -/******/ } -) -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJpZ25vcmVMaXN0IjpbMF0sIm1hcHBpbmdzIjoiQUFBQSIsInNvdXJjZXMiOlsid2VicGFjay1pbnRlcm5hbDovL25leHRqcy93ZWJwYWNrLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFRoaXMgc291cmNlIHdhcyBnZW5lcmF0ZWQgYnkgTmV4dC5qcyBiYXNlZCBvZmYgb2YgdGhlIGdlbmVyYXRlZCBXZWJwYWNrIHJ1bnRpbWUuXG4vLyBUaGUgbWFwcGluZ3MgYXJlIGluY29ycmVjdC5cbi8vIFRvIGdldCB0aGUgY29ycmVjdCBsaW5lL2NvbHVtbiBtYXBwaW5ncywgdHVybiBvZmYgc291cmNlbWFwcyBpbiB5b3VyIGRlYnVnZ2VyLlxuXG5zZWxmW1wid2VicGFja0hvdFVwZGF0ZV9OX0VcIl0oXCJ3ZWJwYWNrXCIse30sXG4vKioqKioqLyBmdW5jdGlvbihfX3dlYnBhY2tfcmVxdWlyZV9fKSB7IC8vIHdlYnBhY2tSdW50aW1lTW9kdWxlc1xuLyoqKioqKi8gLyogd2VicGFjay9ydW50aW1lL2dldEZ1bGxIYXNoICovXG4vKioqKioqLyAoKCkgPT4ge1xuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmggPSAoKSA9PiAoXCJiNzhlYjA1NjhiZjk4Zjc3XCIpXG4vKioqKioqLyB9KSgpO1xuLyoqKioqKi8gXG4vKioqKioqLyB9XG4pIl19 -; \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 104315e..925b796 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,14 @@ FROM base AS builder WORKDIR /app RUN apk add --no-cache openssl COPY --from=deps /app/node_modules ./node_modules -COPY . . +COPY package.json package-lock.json ./ +COPY next.config.ts ./ +COPY tsconfig.json ./ +COPY postcss.config.mjs ./ +COPY eslint.config.mjs ./ +COPY prisma ./prisma +COPY src ./src +COPY public ./public RUN npx prisma generate RUN npm run build @@ -18,7 +25,7 @@ FROM base AS runner WORKDIR /app ENV NODE_ENV=production -RUN apk add --no-cache openssl +RUN apk add --no-cache openssl wget RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs @@ -27,7 +34,8 @@ COPY --from=builder /app/public ./public COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/prisma ./prisma -COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma +COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma COPY scripts/start.sh /app/start.sh RUN chmod +x /app/start.sh @@ -40,4 +48,7 @@ EXPOSE 3000 ENV PORT=3000 ENV HOSTNAME="0.0.0.0" -CMD ["/bin/sh", "/app/start.sh"] \ No newline at end of file +HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ + CMD wget --quiet --spider http://localhost:3000/api/check-subdomain?slug=__health || exit 1 + +CMD ["/bin/sh", "/app/start.sh"] diff --git a/nginx/conf.d/default.conf b/nginx/conf.d/default.conf deleted file mode 100644 index 67f5945..0000000 --- a/nginx/conf.d/default.conf +++ /dev/null @@ -1,32 +0,0 @@ -upstream nextjs { - server app:3000; -} - -server { - listen 80; - server_name testbed.mk *.testbed.mk; - - location / { - proxy_pass http://nextjs; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - set $subdomain ""; - if ($host ~* "^([a-z0-9-]+)\.testbed\.mk$") { - set $subdomain $1; - } - - proxy_set_header X-Subdomain $subdomain; - } - - location /_next/static/ { - proxy_pass http://nextjs; - proxy_cache_valid 200 365d; - add_header Cache-Control "public, immutable"; - } -} \ No newline at end of file diff --git a/nginx/conf.d/production.conf b/nginx/conf.d/production.conf deleted file mode 100644 index 2e41486..0000000 --- a/nginx/conf.d/production.conf +++ /dev/null @@ -1,53 +0,0 @@ -upstream nextjs { - server app:3000; -} - -server { - listen 80; - server_name testbed.mk *.testbed.mk; - - location /.well-known/acme-challenge/ { - root /var/www/certbot; - } - - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 443 ssl; - http2 on; - server_name testbed.mk *.testbed.mk; - - ssl_certificate /etc/letsencrypt/live/testbed.mk/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/testbed.mk/privkey.pem; - - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers HIGH:!aNULL:!MD5; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://nextjs; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - set $subdomain ""; - if ($host ~* "^([a-z0-9-]+)\.testbed\.mk$") { - set $subdomain $1; - } - - proxy_set_header X-Subdomain $subdomain; - } - - location /_next/static/ { - proxy_pass http://nextjs; - proxy_cache_valid 200 365d; - add_header Cache-Control "public, immutable"; - } -} \ No newline at end of file diff --git a/src/app/error.tsx b/src/app/error.tsx new file mode 100644 index 0000000..01b5e48 --- /dev/null +++ b/src/app/error.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { useEffect } from "react"; + +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + useEffect(() => { + console.error(error); + }, [error]); + + return ( +
+

Настана грешка

+

+ Нешто тргна наопаку. Обидете се повторно или контактирајте н ако проблемот persist. +

+ +
+ ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d283fa6..e712983 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import { ClerkProvider } from "@clerk/nextjs"; +import { APP_URL } from "@/lib/config"; import "./globals.css"; const geistSans = Geist({ @@ -14,7 +15,11 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "СпоменQR — Во спомен на", + metadataBase: new URL(APP_URL), + title: { + default: "СпоменQR — Во спомен на", + template: "%s · СпоменQR", + }, description: "Креирајте убави спомен страници со QR кодови. Оддадете почит и зачувајте ги спомените на најблиските.", }; diff --git a/src/app/loading.tsx b/src/app/loading.tsx new file mode 100644 index 0000000..386117c --- /dev/null +++ b/src/app/loading.tsx @@ -0,0 +1,7 @@ +export default function Loading() { + return ( +
+
+
+ ); +}